empi 0.21 → 0.25

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -9,9 +9,9 @@ class Army < Unit
9
9
  def initialize(x, y, faction, map, infopane)
10
10
  super
11
11
  dir_path = File.dirname(__FILE__)
12
- @image = Gosu::Image.new(dir_path + '/media/army.png')
12
+ @image = Gosu::Image.new(dir_path + '/../../media/army.png')
13
13
 
14
- @armor_left = @armor_max = 3
14
+ @armour_left = @armour_max = 3
15
15
  @moves_max = 5
16
16
  end
17
17
 
@@ -9,9 +9,9 @@ class Ship < Unit
9
9
  def initialize(x, y, faction, map, infopane)
10
10
  super
11
11
  dir_path = File.dirname(__FILE__)
12
- @image = Gosu::Image.new(dir_path + '/media/ship.png')
12
+ @image = Gosu::Image.new(dir_path + '/../../media/ship.png')
13
13
 
14
- @armor_left = @armor_max = 1
14
+ @armour_left = @armour_max = 1
15
15
  @moves_max = 2
16
16
  @cargo_max = 3
17
17
  end
@@ -1,10 +1,10 @@
1
- require_relative './game_state'
2
- require_relative './build_state'
3
-
4
1
  require_relative './army'
5
2
  require_relative './ship'
6
3
  require_relative './unit'
7
4
 
5
+ require_relative './../game_states/game_state'
6
+ require_relative './../game_states/build_state'
7
+
8
8
  class Town < Unit
9
9
  @name = 'town'
10
10
  @map_symbol = 'T'
@@ -15,18 +15,19 @@ class Town < Unit
15
15
  def initialize(x, y, faction, map, infopane)
16
16
  super
17
17
  dir_path = File.dirname(__FILE__)
18
- @image = Gosu::Image.new(dir_path + '/media/town.png')
18
+ @image = Gosu::Image.new(dir_path + '/../../media/town.png')
19
19
 
20
- @armor_left = @armor_max = 1
20
+ @armour_left = @armour_max = 1
21
21
  @moves_max = 0
22
22
  @cargo_max = 10
23
23
 
24
- @starting_project = Army unless @faction == 0
24
+ @starting_project = Army unless @faction == 0 # used once at the game start
25
+ @default_project = Army # used after capture
25
26
  @project = nil
26
27
  @parts_built = 0
27
28
  @parts_needed = 0
28
29
 
29
- set_function!(FUNCBUILD)
30
+ set_function!(FUNCBUILD, @faction) unless @faction == 0
30
31
  end
31
32
 
32
33
  def can_build?
@@ -47,17 +48,21 @@ class Town < Unit
47
48
  super
48
49
 
49
50
  # Reset build process
51
+ # 1) remove old project so that it is not disclosed
52
+ # 2) set default project so that there is always some set (remove old parts)
53
+ # 3) offer change of the project to the new owner
54
+ @function.func = FUNCNONE
50
55
  @project = nil
51
- @parts_built = 0
52
- set_function!(FUNCBUILD)
56
+ set_project!(@default_project)
57
+ set_function!(FUNCBUILD, @faction)
53
58
  end
54
59
 
55
60
  # Set desired function and possibly also project
56
- def set_function!(func)
61
+ def set_function!(func, commanding_faction)
57
62
  super
58
63
 
59
- if @faction != 0 and func == FUNCBUILD # neutral towns don't need projects
60
- # Set once starting project or ask player about next project
64
+ if @faction != 0 and commanding_faction == @faction and func == FUNCBUILD
65
+ # Set starting project once or ask player about next project
61
66
  if @starting_project
62
67
  set_project!(@starting_project)
63
68
  @starting_project = nil
@@ -70,15 +75,10 @@ class Town < Unit
70
75
 
71
76
  # Set desired project
72
77
  def set_project!(desired_project)
73
- # Figure out the price
74
- prices = Hash[
75
- [Army, Ship].collect { |ii| [ii, ii.price] } # TODO all subclasses of Unit which can_be_built?
76
- ]
77
-
78
- unless prices.key?(desired_project)
79
- abort("town.set_project!(): Unknown project (#{desired_project})")
78
+ unless price_list.key?(desired_project)
79
+ abort("Town.set_project!(): Unknown project (#{desired_project})")
80
80
  end
81
- @parts_needed = prices[desired_project]
81
+ @parts_needed = price_list[desired_project]
82
82
 
83
83
  # Compare new setting with the old one
84
84
  if desired_project == @project
@@ -90,11 +90,19 @@ class Town < Unit
90
90
  @parts_built = 0
91
91
 
92
92
  new_project_set_text = PROMPT + to_s + ": project set to #{@project.name} (#{build_info} done)"
93
- unless lost_parts > 0
94
- puts new_project_set_text
93
+ if previous_project and lost_parts > 0 # parts were lost but not due to capture
94
+ puts new_project_set_text + ", losing #{lost_parts} " +
95
+ "part#{ 's' unless lost_parts == 1 } of #{previous_project.name}"
95
96
  else
96
- puts new_project_set_text + ", losing #{lost_parts} parts of #{previous_project.name} "
97
+ puts new_project_set_text
97
98
  end
98
99
  end
99
100
  end
101
+
102
+ # Load all prices
103
+ def price_list
104
+ prices = Hash[
105
+ [Army, Ship].collect { |ii| [ii, ii.price] } # TODO all subclasses of Unit which can_be_built?
106
+ ]
107
+ end
100
108
  end
@@ -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
@@ -6,7 +6,8 @@ class Unit
6
6
  attr_reader :name, :map_symbol, :price, :value
7
7
  end
8
8
 
9
- attr_accessor :x, :y, :faction, :function, :cargo
9
+ attr_reader :armour_left
10
+ attr_accessor :x, :y, :faction, :function, :cargo, :cargo_max
10
11
 
11
12
  def initialize(x, y, faction, map, infopane)
12
13
  @x = x
@@ -15,8 +16,8 @@ class Unit
15
16
  @map = map
16
17
  @infopane = infopane
17
18
 
18
- @armor_max = 1
19
- @armor_left = @armor_max
19
+ @armour_max = 1
20
+ @armour_left = @armour_max
20
21
  @moves_max = 1
21
22
  @moves_left = @moves_max
22
23
  @cargo = [] # transported units
@@ -34,8 +35,8 @@ class Unit
34
35
 
35
36
  # Process engagement targeted at this unit
36
37
  def engage!(by_whom)
37
- if by_whom == @faction
38
- 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})")
39
40
  end
40
41
 
41
42
  # Can it be captured and is it without defenders?
@@ -45,7 +46,7 @@ class Unit
45
46
  else # then capture it if you can
46
47
  if by_whom.can_capture?
47
48
  puts PROMPT + by_whom.to_s + ' is capturing ' + to_s
48
- capture!(by_whom.faction)
49
+ capture!(by_whom)
49
50
  else
50
51
  puts PROMPT + by_whom.to_s + ' can\'t capture other units'
51
52
  end
@@ -64,20 +65,22 @@ class Unit
64
65
  # Process capture targeted at this unit
65
66
  def capture!(by_whom)
66
67
  unless can_be_captured?
67
- abort("unit.capture!(): This unit can\'t be captured")
68
+ abort("Unit.capture!(): This unit can\'t be captured")
68
69
  end
69
70
 
70
- if by_whom == @faction
71
- 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}")
72
73
  end
73
74
 
74
75
  # Add <value> to the capturing faction
75
- @infopane.add_score(by_whom - 1, self.class.value)
76
- @faction = by_whom
76
+ @infopane.add_score(by_whom.faction - 1, self.class.value)
77
+ @faction = by_whom.faction
77
78
  end
78
79
 
79
80
  # Add <value> to the other faction and remove links to given unit
80
81
  def destroy!
82
+ @armour_left = 0 # for non-attack damage
83
+
81
84
  # If you are transporting somebody, destroy them first
82
85
  @cargo.each { |uu| uu.destroy! }
83
86
 
@@ -95,16 +98,17 @@ class Unit
95
98
  def check_movement(old_x, old_y)
96
99
  if @x != old_x || @y != old_y # only if it moved
97
100
  if @moves_left <= 0
98
- 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)")
99
102
  end
100
103
 
101
104
  oldcoords_unit = @map.get_unit(old_x, old_y)
102
105
  newcoords_unit = @map.get_unit(@x, @y)
103
106
 
104
- # If there is nobody or is there friendly unit with some cargo space
107
+ # If there is nobody or is there friendly unit with some cargo space (and bigger cargo space)
105
108
  if !newcoords_unit || \
106
109
  (newcoords_unit.faction == @faction && \
107
110
  newcoords_unit.can_transport? && \
111
+ @cargo_max < newcoords_unit.cargo_max && \
108
112
  !newcoords_unit.is_full?)
109
113
 
110
114
  # Leave old coordinates
@@ -115,35 +119,40 @@ class Unit
115
119
  end
116
120
 
117
121
  # Get to new coordinates
118
- if newcoords_unit == nil
122
+ if !newcoords_unit
119
123
  @map.set_unit(@x, @y, self)
120
- @cargo.each { |uu|
121
- uu.x = @x
122
- uu.y = @y
123
- }
124
-
125
124
  else # if you are going to be transported
126
125
  newcoords_unit.cargo.insert(-1, self) # -1 = to the end
127
126
  puts PROMPT + to_s + ' got loaded into '+ newcoords_unit.to_s
128
127
  @moves_left = 1 unless newcoords_unit.can_build? # use all your left moves unless you are getting loaded into a town
129
128
  end
130
129
 
130
+ # Update position of your cargo
131
+ @cargo.each { |uu|
132
+ uu.x = @x
133
+ uu.y = @y
134
+ }
135
+
131
136
  else # if there already is somebody that can't transport you (enemy or full friend)
132
- # Stay on your original tile
133
- @x = old_x
134
- @y = old_y
135
-
136
- # If it was a friend unit
137
- if newcoords_unit.faction == @faction
138
- if !newcoords_unit.can_transport?
139
- puts PROMPT + newcoords_unit.to_s + ' can\'t transport other units'
140
- else # newcoords_unit.can_transport?; has to be full then
137
+ # Stay on your original tile
138
+ @x = old_x
139
+ @y = old_y
140
+
141
+ # If it was a friend unit
142
+ if newcoords_unit.faction == @faction
143
+ if !newcoords_unit.can_transport?
144
+ puts PROMPT + newcoords_unit.to_s + ' can\'t transport other units'
145
+ else
146
+ if @cargo_max >= newcoords_unit.cargo_max
147
+ puts PROMPT + "#{self.class.name} can\'t fit in #{newcoords_unit.class.name}"
148
+ else # thus newcoords_unit.is_full? is true
141
149
  puts PROMPT + newcoords_unit.to_s + ' is already full'
142
150
  end
143
- else
144
- # Enemy!
145
- newcoords_unit.engage!(self)
146
151
  end
152
+ else
153
+ # Enemy!
154
+ newcoords_unit.engage!(self)
155
+ end
147
156
  end
148
157
  @moves_left -= 1
149
158
 
@@ -155,12 +164,17 @@ class Unit
155
164
  end
156
165
  end
157
166
 
158
-
159
167
  def draw
160
168
  @image.draw(@x * TILESIZE, (@y + 1) * TILESIZE, ZUNIT,
161
169
  scale_x = 1, scale_y = 1, color = COLOUR[@faction])
162
170
  end
163
171
 
172
+ def is_waiting_for_commands?
173
+ @faction == @infopane.faction and
174
+ function == FUNCNONE and
175
+ can_move?
176
+ end
177
+
164
178
  def can_move?
165
179
  (can_fly? || can_sail? || can_ride?) && @moves_left > 0
166
180
  end
@@ -227,19 +241,31 @@ class Unit
227
241
  end
228
242
 
229
243
  # Set desired function
230
- def set_function!(func)
231
- unless @faction == 0 # neutral towns dom't need functions
232
- if func == FUNCBUILD and !can_build?
233
- puts PROMPT + to_s + ": this unit can't build other units"
234
- return
235
- end
244
+ def set_function!(func, commanding_faction)
245
+ # Check your neutrality
246
+ if @faction == 0
247
+ puts PROMPT + to_s + ": neutral units can't have functions set"
248
+ return
249
+ end
236
250
 
237
- if @function.func == func
238
- puts PROMPT + to_s + ": function is already set to #{@function.func}"
239
- else
240
- @function.func = func
241
- puts PROMPT + to_s + ": function set to #{@function.func}"
242
- end
251
+ # Check origin of command
252
+ if commanding_faction != @faction
253
+ puts PROMPT + to_s + ": this unit does not take commands from other factions"
254
+ return
255
+ end
256
+
257
+ # Check your abilities
258
+ if func == FUNCBUILD and !can_build?
259
+ puts PROMPT + to_s + ": this unit can't build other units"
260
+ return
261
+ end
262
+
263
+ # Check current function and set the new one
264
+ if @function.func == func
265
+ puts PROMPT + to_s + ": function is already set to #{@function.func}"
266
+ else
267
+ @function.func = func
268
+ puts PROMPT + to_s + ": function set to #{@function.func}"
243
269
  end
244
270
  end
245
271
 
@@ -253,9 +279,9 @@ class Unit
253
279
  "#{self.class.name} (FAC#{@faction} #{@x}-#{@y})"
254
280
  end
255
281
 
256
- # Set long info string: short info string, armor, moves, function, cargo
282
+ # Set long info string: short info string, armour, moves, function, cargo
257
283
  def info
258
- ret = to_s + ": armor #{@armor_left}/#{@armor_max}"
284
+ ret = to_s + ": armour #{@armour_left}/#{@armour_max}"
259
285
 
260
286
  if @moves_max > 0
261
287
  ret = ret + ", moves #{@moves_left}/#{@moves_max}"
@@ -12,6 +12,9 @@ class UnitFunction
12
12
  when FUNCNONE
13
13
  "no function"
14
14
  when FUNCBUILD
15
+ unless @unit.project
16
+ abort("UnitFunction.info(): No project set (" + @unit.to_s + ")")
17
+ end
15
18
  "building #{@unit.project.name} (#{@unit.build_info})"
16
19
  when FUNCSENTRY
17
20
  "sentrying"
@@ -19,11 +22,13 @@ class UnitFunction
19
22
  end
20
23
 
21
24
  def func!(map, infopane)
22
- ret = " didn't actually do anything (ERROR)"
23
-
24
25
  case @func
25
26
  # Build given unit
26
27
  when FUNCBUILD
28
+ unless @unit.project
29
+ abort("UnitFunction.func!(): No project set (" + @unit.to_s + ")")
30
+ end
31
+
27
32
  @unit.parts_built += 1
28
33
 
29
34
  unless @unit.parts_built >= @unit.parts_needed # just == should be enough
@@ -34,9 +39,9 @@ class UnitFunction
34
39
  @unit.project.new(@unit.x, @unit.y, @unit.faction, map, infopane)
35
40
  end
36
41
 
37
- # Wake when enemies are nearby
42
+ # Wake when enemies are nearby (checking just map units is enough)
38
43
  when FUNCSENTRY
39
- units_around = map.all_units.select { |uu|
44
+ units_around = map.all_units(0,0).select { |uu|
40
45
  (uu.x - @unit.x).abs <= 1 &&
41
46
  (uu.y - @unit.y).abs <= 1 &&
42
47
  uu.faction != @unit.faction
@@ -49,6 +54,10 @@ class UnitFunction
49
54
  end
50
55
  end
51
56
 
57
+ unless ret
58
+ abort("UnitFunction.func!(): Functionable unit didn't function (" + @unit.to_s + ")")
59
+ end
60
+
52
61
  ret
53
62
  end
54
63
  end