empi 0.16.6
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/army.rb +18 -0
- data/lib/cursor.rb +99 -0
- data/lib/docu/Empi v14.png +0 -0
- data/lib/docu/info.txt +149 -0
- data/lib/empi.rb +143 -0
- data/lib/infopane.rb +36 -0
- data/lib/map.rb +172 -0
- data/lib/media/army.png +0 -0
- data/lib/media/cursor.png +0 -0
- data/lib/media/ground.png +0 -0
- data/lib/media/sea.png +0 -0
- data/lib/media/ship.png +0 -0
- data/lib/media/town.png +0 -0
- data/lib/save/m01.esf +20 -0
- data/lib/save/m02.esf +22 -0
- data/lib/save/m03.esf +24 -0
- data/lib/ship.rb +19 -0
- data/lib/town.rb +24 -0
- data/lib/unit.rb +244 -0
- data/lib/unitFunction.rb +47 -0
- metadata +99 -0
data/lib/army.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require_relative './unit'
|
2
|
+
|
3
|
+
class Army < Unit
|
4
|
+
def initialize(x, y, faction, map, infopane)
|
5
|
+
super
|
6
|
+
dir_path = File.dirname(__FILE__)
|
7
|
+
@image = Gosu::Image.new(dir_path + '/media/army.png')
|
8
|
+
|
9
|
+
@name = 'army'
|
10
|
+
@value = 5
|
11
|
+
@armor_left = @armor_max = 3
|
12
|
+
@moves_max = 5
|
13
|
+
end
|
14
|
+
|
15
|
+
def can_ride?
|
16
|
+
true
|
17
|
+
end
|
18
|
+
end
|
data/lib/cursor.rb
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
class Cursor
|
2
|
+
attr_accessor :x, :y, :freeroam
|
3
|
+
|
4
|
+
def initialize(x, y, map, infopane)
|
5
|
+
dir_path = File.dirname(__FILE__)
|
6
|
+
|
7
|
+
@x = x
|
8
|
+
@y = y
|
9
|
+
@map = map
|
10
|
+
@infopane = infopane
|
11
|
+
|
12
|
+
@image = Gosu::Image.new(dir_path + '/media/cursor.png')
|
13
|
+
@freeroam = false
|
14
|
+
end
|
15
|
+
|
16
|
+
def update(key)
|
17
|
+
case key
|
18
|
+
# Cardinal directions
|
19
|
+
when Gosu::KbLeft, Gosu::KbA then
|
20
|
+
@x -= 1 unless @x <= 0
|
21
|
+
when Gosu::KbRight, Gosu::KbD then
|
22
|
+
@x += 1 unless @x >= MAPX
|
23
|
+
when Gosu::KbUp, Gosu::KbW then
|
24
|
+
@y -= 1 unless @y <= 0
|
25
|
+
when Gosu::KbDown, Gosu::KbX then
|
26
|
+
@y += 1 unless @y >= MAPY
|
27
|
+
|
28
|
+
# Intercardinal directions
|
29
|
+
when Gosu::KbQ then
|
30
|
+
unless @x <= 0 || @y <= 0
|
31
|
+
@x -= 1
|
32
|
+
@y -= 1
|
33
|
+
end
|
34
|
+
when Gosu::KbE then
|
35
|
+
unless @x >= MAPX || @y <= 0
|
36
|
+
@x += 1
|
37
|
+
@y -= 1
|
38
|
+
end
|
39
|
+
when Gosu::KbZ then
|
40
|
+
unless @x <= 0 || @y >= MAPY
|
41
|
+
@x -= 1
|
42
|
+
@y += 1
|
43
|
+
end
|
44
|
+
when Gosu::KbC then
|
45
|
+
unless @x >= MAPX || @y >= MAPY
|
46
|
+
@x += 1
|
47
|
+
@y += 1
|
48
|
+
end
|
49
|
+
|
50
|
+
# Functions
|
51
|
+
when Gosu::KbS then
|
52
|
+
uu = @map.get_unit(@x, @y)
|
53
|
+
if uu then uu.set_function(FUNCSENTRY) end
|
54
|
+
when Gosu::KbB then
|
55
|
+
uu = @map.get_unit(@x, @y)
|
56
|
+
if uu then uu.set_function(FUNCBUILD) end
|
57
|
+
when Gosu::KbN then
|
58
|
+
uu = @map.get_unit(@x, @y)
|
59
|
+
if uu then uu.set_function(FUNCNONE) end
|
60
|
+
|
61
|
+
when Gosu::KbReturn then
|
62
|
+
info
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def draw
|
67
|
+
@image.draw(@x * TILESIZE, (@y + 1) * TILESIZE, ZCURSOR)
|
68
|
+
end
|
69
|
+
|
70
|
+
# Move to given coordinates
|
71
|
+
def warp(x, y)
|
72
|
+
@x = x
|
73
|
+
@y = y
|
74
|
+
end
|
75
|
+
|
76
|
+
# Switch between being attached to unit and being able to freeroam
|
77
|
+
def switch_freeroam
|
78
|
+
if freeroam == true
|
79
|
+
@infopane.text = 'freeroam disabled'
|
80
|
+
puts 'freeroam disabled'
|
81
|
+
else
|
82
|
+
@infopane.text = 'freeroam enabled'
|
83
|
+
puts 'freeroam enabled'
|
84
|
+
end
|
85
|
+
@freeroam = !@freeroam
|
86
|
+
end
|
87
|
+
|
88
|
+
# Find some info about unit in current tile
|
89
|
+
def info
|
90
|
+
uu = @map.get_unit(@x, @y)
|
91
|
+
if uu
|
92
|
+
@infopane.text = uu.info
|
93
|
+
puts uu.info
|
94
|
+
else
|
95
|
+
@infopane.text = ''
|
96
|
+
puts 'nothing here'
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
Binary file
|
data/lib/docu/info.txt
ADDED
@@ -0,0 +1,149 @@
|
|
1
|
+
/-- /// /-/ -/-
|
2
|
+
/-- ||| /-/ |
|
3
|
+
/-- ||| | -/-
|
4
|
+
|
5
|
+
Empi: Ruby Edition
|
6
|
+
====================
|
7
|
+
|
8
|
+
|
9
|
+
v16 dev
|
10
|
+
=========
|
11
|
+
- units on sentry duty say so when functioning
|
12
|
+
- neutral units can't have functions
|
13
|
+
- links to media and save files use full path
|
14
|
+
- towns build armies
|
15
|
+
! hardcoded unit type to be built
|
16
|
+
- units can transport other units
|
17
|
+
- newly built units are stored in town instead of map
|
18
|
+
fixes: new units are saved in map instead of the towns that built them
|
19
|
+
! transported units are not drawn
|
20
|
+
! transported units show info of their transport instead when selected
|
21
|
+
! all units can capture and visit towns
|
22
|
+
|
23
|
+
file changes
|
24
|
+
--------------
|
25
|
+
map
|
26
|
+
initialize() uses full paths to files
|
27
|
+
all_units renamed to all_map_units() - Return only units directly on map
|
28
|
+
+all_transported_units() - Return only units transported by other units
|
29
|
+
+all_units() - Return both map units and transported units
|
30
|
+
draw_units() draws only map units
|
31
|
+
|
32
|
+
unit
|
33
|
+
+@cargo, @cargo_max
|
34
|
+
+can_transport?() - Unit is able to both transport other units and currently has some space left
|
35
|
+
set_function() checks for @faction == 0
|
36
|
+
checking of movement separated from update()
|
37
|
+
+check_movement() - Processes move of unit and takes care of its (un)loading or attack
|
38
|
+
capture() makes newly captured towns start building
|
39
|
+
|
40
|
+
town
|
41
|
+
initialize() uses full path to file
|
42
|
+
+parts_built
|
43
|
+
+@cargo_max set to 10
|
44
|
+
|
45
|
+
army
|
46
|
+
initialize() uses full path to file
|
47
|
+
|
48
|
+
ship
|
49
|
+
initialize() uses full path to file
|
50
|
+
+@cargo_max set to 3
|
51
|
+
|
52
|
+
unitFunction
|
53
|
+
+FUNCBUILD case in func!()
|
54
|
+
FUNCSENTRY case in func!() sets "ret" even when unit keeps sentrying
|
55
|
+
|
56
|
+
|
57
|
+
v15 dev
|
58
|
+
=========
|
59
|
+
- units referenced only from map
|
60
|
+
fixed: no destruction of units
|
61
|
+
- loading of units from file
|
62
|
+
fixed: no loading
|
63
|
+
- checks of loaded terrain tiles and units
|
64
|
+
- map stored as [row, column], not [xx, yy]
|
65
|
+
|
66
|
+
file changes
|
67
|
+
--------------
|
68
|
+
empi.rb
|
69
|
+
-scenario_units() - Return list of units for given scenario
|
70
|
+
|
71
|
+
map.rb
|
72
|
+
load_map() now loads units too
|
73
|
+
load_head() now returns number of units to load too
|
74
|
+
load_map(), tile(), get_unit(), set_unit() use rr and cc instead of xx and yy
|
75
|
+
+load_unit() - Load one unit from given line
|
76
|
+
+draw_units() - Draw all units
|
77
|
+
|
78
|
+
save/m01.esf
|
79
|
+
8 units from old empi.scenario_units()
|
80
|
+
|
81
|
+
save/m02.esf
|
82
|
+
10 units similar to old empi.scenario_units()
|
83
|
+
|
84
|
+
save/m03.esf
|
85
|
+
|
86
|
+
|
87
|
+
v14 dev
|
88
|
+
=========
|
89
|
+
- loading of terrain tiles from file
|
90
|
+
fixed: hardcoded starting scenario
|
91
|
+
! hardcoded save file name
|
92
|
+
! hardcoded map size
|
93
|
+
|
94
|
+
file changes
|
95
|
+
--------------
|
96
|
+
empi.rb
|
97
|
+
TILE constants moved to map.rb
|
98
|
+
|
99
|
+
map.rb
|
100
|
+
-scenario_tiles() - Return map tile for given scenario
|
101
|
+
+load_map() - Load map from file (for now only terrain tiles)
|
102
|
+
+load_head() - Load head row of file
|
103
|
+
|
104
|
+
unit.rb
|
105
|
+
removed generic unit image
|
106
|
+
|
107
|
+
save/m01.esf
|
108
|
+
save/m02.esf
|
109
|
+
|
110
|
+
|
111
|
+
older versions
|
112
|
+
================
|
113
|
+
- towns and armies
|
114
|
+
- functions none and sentry
|
115
|
+
- armor and movement points
|
116
|
+
- movement of units
|
117
|
+
- rudimentary terrain checking after move
|
118
|
+
- capturing of units
|
119
|
+
- turn and score counting
|
120
|
+
- commmand line and screen text output
|
121
|
+
- next avaiable unit / freeroam cursor
|
122
|
+
|
123
|
+
current state
|
124
|
+
===============
|
125
|
+
old wishlist
|
126
|
+
! no panning of map
|
127
|
+
!x no destruction of units
|
128
|
+
!x no building of units
|
129
|
+
! no victory conditions
|
130
|
+
! attacker always wins
|
131
|
+
! player playing both factions at once
|
132
|
+
!x hardcoded starting scenario
|
133
|
+
! no fog of war
|
134
|
+
! no saving
|
135
|
+
!x no loading
|
136
|
+
! no title screen
|
137
|
+
! no highscore screen
|
138
|
+
! no settings
|
139
|
+
! no sound, no music
|
140
|
+
|
141
|
+
new problems
|
142
|
+
! hardcoded save file name
|
143
|
+
! hardcoded map size
|
144
|
+
! hardcoded unit type to be built
|
145
|
+
! transported units are not drawn
|
146
|
+
! transported units show info of their transport instead when selected
|
147
|
+
! all units can capture and visit towns
|
148
|
+
|
149
|
+
(! thing to fix, !x fixed thing)
|
data/lib/empi.rb
ADDED
@@ -0,0 +1,143 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'gosu'
|
3
|
+
|
4
|
+
require_relative './army'
|
5
|
+
require_relative './cursor'
|
6
|
+
require_relative './infopane'
|
7
|
+
require_relative './map'
|
8
|
+
require_relative './ship'
|
9
|
+
require_relative './town'
|
10
|
+
|
11
|
+
TILESIZE = 50
|
12
|
+
MAPX = 10
|
13
|
+
MAPY = 10
|
14
|
+
|
15
|
+
XTEXT = 5
|
16
|
+
YTEXT = 5
|
17
|
+
|
18
|
+
ZTILE = 0
|
19
|
+
ZUNIT = 1
|
20
|
+
ZTEXT = 2
|
21
|
+
ZCURSOR = 3
|
22
|
+
|
23
|
+
FACTIONS = 2
|
24
|
+
COLOUR = [0xff_ffffff, 0xff_ff3300, 0xff_ffcc00]
|
25
|
+
|
26
|
+
FUNCNONE = 'none'
|
27
|
+
FUNCSENTRY = 'sentry'
|
28
|
+
FUNCBUILD = 'build'
|
29
|
+
|
30
|
+
# Main class
|
31
|
+
class GameWindow < Gosu::Window
|
32
|
+
def initialize(width = (MAPX + 1) * TILESIZE, \
|
33
|
+
height = (MAPY + 2) * TILESIZE, \
|
34
|
+
fullscreen = false)
|
35
|
+
super
|
36
|
+
self.caption = 'Empi: Ruby Edition 0.16 dev'
|
37
|
+
|
38
|
+
@infopane = Infopane.new
|
39
|
+
@map = Map.new(@infopane)
|
40
|
+
@cursor = Cursor.new(5, 5, @map, @infopane)
|
41
|
+
|
42
|
+
new_turn
|
43
|
+
end
|
44
|
+
|
45
|
+
def button_up(key)
|
46
|
+
@button = key
|
47
|
+
|
48
|
+
case(key)
|
49
|
+
when Gosu::KbEscape then
|
50
|
+
close
|
51
|
+
when Gosu::KbPeriod then
|
52
|
+
new_turn
|
53
|
+
when Gosu::KbH then
|
54
|
+
help
|
55
|
+
when Gosu::KbJ then
|
56
|
+
unit_to_move = 0
|
57
|
+
@cursor.switch_freeroam
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Process given button to cursor
|
62
|
+
def update
|
63
|
+
if @button == -1 then return end
|
64
|
+
|
65
|
+
movable_units = @map.all_units.select { |uu| uu.can_move && uu.function == FUNCNONE}
|
66
|
+
# If there are any movable units without functions select one of them with the cursor
|
67
|
+
if @cursor.freeroam == false && movable_units.size > 0
|
68
|
+
unit_to_move = movable_units[0]
|
69
|
+
unit_to_move.update(@button)
|
70
|
+
|
71
|
+
# Can it still move?
|
72
|
+
if unit_to_move.can_move && unit_to_move.function == FUNCNONE
|
73
|
+
# Move the cursor to it unless it is already there
|
74
|
+
if (@cursor.x != unit_to_move.x \
|
75
|
+
|| @cursor.y != unit_to_move.y)
|
76
|
+
@cursor.warp(unit_to_move.x, unit_to_move.y)
|
77
|
+
@cursor.info
|
78
|
+
end
|
79
|
+
else
|
80
|
+
# Was that the last currently avaiable non-function move?
|
81
|
+
movable_units = @map.all_units.select { |uu| uu.can_move && uu.function == FUNCNONE}
|
82
|
+
if movable_units.size == 0
|
83
|
+
puts 'all movable units without functions moved'
|
84
|
+
@cursor.switch_freeroam
|
85
|
+
else
|
86
|
+
# Move cursor to next avaiable unit
|
87
|
+
unit_to_move = movable_units[0]
|
88
|
+
@cursor.warp(unit_to_move.x, unit_to_move.y)
|
89
|
+
@cursor.info
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
else
|
94
|
+
# Cursor in freeroam mode
|
95
|
+
@cursor.update(@button)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# Draw only after some button was released and in the start
|
100
|
+
def needs_redraw?
|
101
|
+
@button != -1
|
102
|
+
end
|
103
|
+
|
104
|
+
def draw
|
105
|
+
@button = -1 # use each button just once
|
106
|
+
|
107
|
+
# Draw map tiles and units
|
108
|
+
@map.draw_tiles
|
109
|
+
@map.draw_units
|
110
|
+
# DEBUG @map.all_units.each { |uu| puts uu.info}
|
111
|
+
|
112
|
+
@cursor.draw
|
113
|
+
@infopane.draw
|
114
|
+
|
115
|
+
# @message = Gosu::Image.from_text(
|
116
|
+
# self, "Empire", Gosu.default_font_name, 20)
|
117
|
+
# @message.draw(10, 10, 2)
|
118
|
+
end
|
119
|
+
|
120
|
+
# End current turn and start next one
|
121
|
+
def new_turn
|
122
|
+
@cursor.freeroam = true
|
123
|
+
@cursor.switch_freeroam # so freeroam = false, with messages
|
124
|
+
|
125
|
+
functionable_units = @map.all_units.select { |uu| uu.function != FUNCNONE}
|
126
|
+
functionable_units.each { |uu| uu.function! }
|
127
|
+
|
128
|
+
@map.all_units.each { |uu| uu.reset_moves}
|
129
|
+
@infopane.next_turn
|
130
|
+
end
|
131
|
+
|
132
|
+
def help
|
133
|
+
puts "----------\n" \
|
134
|
+
"QWEADZXC movement, h help, Enter info, j switch freeroam\n" \
|
135
|
+
"functions: s sentry, n none\n" \
|
136
|
+
"----------\n"
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
# ---------------------------------------------------------------
|
141
|
+
|
142
|
+
window = GameWindow.new
|
143
|
+
window.show
|
data/lib/infopane.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# Score, turn and event texts
|
2
|
+
class Infopane
|
3
|
+
attr_writer :text, :act_fact
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@score = [0, 0]
|
7
|
+
@turn = 0
|
8
|
+
@act_fact = 0 # active faction
|
9
|
+
@text = 'ready'
|
10
|
+
end
|
11
|
+
|
12
|
+
def update
|
13
|
+
end
|
14
|
+
|
15
|
+
def draw
|
16
|
+
turnscore = Gosu::Image.from_text(
|
17
|
+
self, "Turn: #{@turn}, Score: #{@score[0]} - #{@score[1]}", Gosu.default_font_name, 20)
|
18
|
+
turnscore.draw(XTEXT, YTEXT, ZTEXT)
|
19
|
+
|
20
|
+
text = Gosu::Image.from_text(self, "#{@text}", Gosu.default_font_name, 20)
|
21
|
+
text.draw(XTEXT, (TILESIZE / 2) + YTEXT, ZTEXT)
|
22
|
+
end
|
23
|
+
|
24
|
+
def next_faction
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
def next_turn
|
29
|
+
@turn += 1
|
30
|
+
puts "Turn: #{@turn}, Score: #{@score[0]} - #{@score[1]}"
|
31
|
+
end
|
32
|
+
|
33
|
+
def add_score(to_whom, how_much)
|
34
|
+
@score[to_whom] += how_much
|
35
|
+
end
|
36
|
+
end
|
data/lib/map.rb
ADDED
@@ -0,0 +1,172 @@
|
|
1
|
+
TILE_SEA = 0
|
2
|
+
TILE_GROUND = 1
|
3
|
+
|
4
|
+
SYMBOL_SEA = '.'
|
5
|
+
SYMBOL_GROUND = '#'
|
6
|
+
SYMBOL_TOWN = 'T'
|
7
|
+
SYMBOL_ARMY = 'A'
|
8
|
+
SYMBOL_SHIP = 'S'
|
9
|
+
|
10
|
+
class Map
|
11
|
+
attr_accessor :name, :mapx, :mapy, :infopane
|
12
|
+
|
13
|
+
# Fill tile map and prepare
|
14
|
+
def initialize(infopane)
|
15
|
+
dir_path = File.dirname(__FILE__)
|
16
|
+
|
17
|
+
@infopane = infopane
|
18
|
+
@sea_image = Gosu::Image.new(dir_path + '/media/sea.png')
|
19
|
+
@ground_image = Gosu::Image.new(dir_path + '/media/ground.png')
|
20
|
+
load_map(dir_path + '/save/m03.esf')
|
21
|
+
end
|
22
|
+
|
23
|
+
# Load map from file
|
24
|
+
def load_map(filename)
|
25
|
+
input = File.open(filename, 'r')
|
26
|
+
unit_count = load_head(input.gets)
|
27
|
+
|
28
|
+
# Load tiles
|
29
|
+
@tiles = []
|
30
|
+
@units = []
|
31
|
+
0.upto(@mapy - 1) { |rr|
|
32
|
+
@tiles[rr] = []
|
33
|
+
@units[rr] = []
|
34
|
+
map_row = input.gets
|
35
|
+
0.upto(@mapx - 1) { |cc|
|
36
|
+
case(map_row[cc])
|
37
|
+
when SYMBOL_SEA then
|
38
|
+
@tiles[rr][cc] = TILE_SEA
|
39
|
+
when SYMBOL_GROUND then
|
40
|
+
@tiles[rr][cc] = TILE_GROUND
|
41
|
+
else
|
42
|
+
abort("map.load_map(): Unknown terrain symbol (#{map_row[cc]})")
|
43
|
+
end
|
44
|
+
}
|
45
|
+
}
|
46
|
+
|
47
|
+
# Load units
|
48
|
+
unit_count.times { load_unit(input.gets) }
|
49
|
+
|
50
|
+
puts("Save loaded: #{@name} with #{unit_count} units")
|
51
|
+
input.close
|
52
|
+
end
|
53
|
+
|
54
|
+
# Load core info from given head row of file
|
55
|
+
# Return number of units to be loaded
|
56
|
+
def load_head(row)
|
57
|
+
head = []
|
58
|
+
size = []
|
59
|
+
|
60
|
+
head = row.split(' ')
|
61
|
+
size = head[1].split('x')
|
62
|
+
|
63
|
+
@name = head[0]
|
64
|
+
@mapx = size[0].to_i
|
65
|
+
@mapy = size[1].to_i
|
66
|
+
|
67
|
+
head[2].to_i # unit_count
|
68
|
+
end
|
69
|
+
|
70
|
+
# Load one unit from given line
|
71
|
+
def load_unit(row)
|
72
|
+
unit = []
|
73
|
+
coords = []
|
74
|
+
|
75
|
+
unit = row.split(' ')
|
76
|
+
coords = unit[2].split('-')
|
77
|
+
|
78
|
+
# Check faction
|
79
|
+
fac = unit[1].to_i
|
80
|
+
if(fac < 0 || fac > FACTIONS)
|
81
|
+
abort("map.load_unit(): Bad faction id (#{fac})")
|
82
|
+
end
|
83
|
+
|
84
|
+
# Check coordinates
|
85
|
+
coords_x = coords[0].to_i
|
86
|
+
coords_y = coords[1].to_i
|
87
|
+
if (coords_x < 0 || coords_x >= @mapx ||
|
88
|
+
coords_y < 0 || coords_y >= @mapy)
|
89
|
+
abort("map.load_unit(): Unit out of map borders (#{coords_x}-#{coords_y})")
|
90
|
+
end
|
91
|
+
|
92
|
+
# Create unit
|
93
|
+
case(unit[0])
|
94
|
+
when SYMBOL_TOWN then
|
95
|
+
Town.new(coords_x, coords_y, fac, self, @infopane)
|
96
|
+
when SYMBOL_ARMY then
|
97
|
+
Army.new(coords_x, coords_y, fac, self, @infopane)
|
98
|
+
when SYMBOL_SHIP then
|
99
|
+
Ship.new(coords_x, coords_y, fac, self, @infopane)
|
100
|
+
else
|
101
|
+
abort("map.load_unit(): Unknown unit type symbol (#{unit[0]})")
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# Draw all tiles
|
106
|
+
def draw_tiles
|
107
|
+
# TODO combine with draw_units()
|
108
|
+
|
109
|
+
0.upto(MAPX) { |rr|
|
110
|
+
0.upto(MAPX) { |cc|
|
111
|
+
if @tiles[rr][cc] == TILE_SEA
|
112
|
+
# TODO tiles (z1) and units (z2) together
|
113
|
+
im = @sea_image
|
114
|
+
else
|
115
|
+
im = @ground_image
|
116
|
+
end
|
117
|
+
im.draw(cc * TILESIZE, (rr + 1) * TILESIZE, ZTILE)
|
118
|
+
}
|
119
|
+
}
|
120
|
+
end
|
121
|
+
|
122
|
+
# Draw all map units
|
123
|
+
def draw_units
|
124
|
+
all_map_units.each { |uu| uu.draw} # TODO do not draw transported units? only draw them on selection (with their tile)?
|
125
|
+
end
|
126
|
+
|
127
|
+
# Getter for tile type in given coordinates
|
128
|
+
def tile(cc, rr)
|
129
|
+
@tiles[rr][cc]
|
130
|
+
end
|
131
|
+
|
132
|
+
# Getter for unit in given coordinates
|
133
|
+
def get_unit(cc, rr)
|
134
|
+
@units[rr][cc]
|
135
|
+
end
|
136
|
+
|
137
|
+
# Setter for tile type in given coordinates
|
138
|
+
def set_unit(cc, rr, uu)
|
139
|
+
@units[rr][cc] = uu
|
140
|
+
end
|
141
|
+
|
142
|
+
# Return both map units and transported units
|
143
|
+
def all_units
|
144
|
+
all_map_units + all_transported_units
|
145
|
+
end
|
146
|
+
|
147
|
+
# Return only units directly on map
|
148
|
+
def all_map_units
|
149
|
+
ret = []
|
150
|
+
ii = 0
|
151
|
+
0.upto(MAPX) { |rr|
|
152
|
+
0.upto(MAPX) { |cc|
|
153
|
+
if @units[rr][cc]
|
154
|
+
ret[ii] = @units[rr][cc]
|
155
|
+
ii += 1
|
156
|
+
end
|
157
|
+
}
|
158
|
+
}
|
159
|
+
ret
|
160
|
+
end
|
161
|
+
|
162
|
+
# Return only units transported by other units
|
163
|
+
def all_transported_units
|
164
|
+
ret = []
|
165
|
+
all_map_units.each { |uu|
|
166
|
+
if uu.is_transporting?
|
167
|
+
ret += uu.cargo
|
168
|
+
end
|
169
|
+
}
|
170
|
+
ret
|
171
|
+
end
|
172
|
+
end
|
data/lib/media/army.png
ADDED
Binary file
|
Binary file
|
Binary file
|
data/lib/media/sea.png
ADDED
Binary file
|
data/lib/media/ship.png
ADDED
Binary file
|
data/lib/media/town.png
ADDED
Binary file
|
data/lib/save/m01.esf
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
mission01 11x11 8
|
2
|
+
#####..####
|
3
|
+
####....###
|
4
|
+
###......##
|
5
|
+
##........#
|
6
|
+
#...###...#
|
7
|
+
....##....#
|
8
|
+
....#....##
|
9
|
+
#.......###
|
10
|
+
##.....####
|
11
|
+
###...#####
|
12
|
+
###########
|
13
|
+
T 0 1-3
|
14
|
+
T 0 3-1
|
15
|
+
T 0 6-9
|
16
|
+
T 0 9-6
|
17
|
+
T 1 8-1
|
18
|
+
A 1 9-1
|
19
|
+
T 2 1-8
|
20
|
+
A 2 1-9
|
data/lib/save/m02.esf
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
mission02 11x11 10
|
2
|
+
###########
|
3
|
+
#..###..###
|
4
|
+
#....#...##
|
5
|
+
##...#....#
|
6
|
+
##....#...#
|
7
|
+
####...####
|
8
|
+
#...#....##
|
9
|
+
#....#....#
|
10
|
+
##...#....#
|
11
|
+
###..##..##
|
12
|
+
###########
|
13
|
+
T 0 1-3
|
14
|
+
T 0 3-1
|
15
|
+
T 0 6-9
|
16
|
+
T 0 9-6
|
17
|
+
T 1 8-1
|
18
|
+
T 1 9-2
|
19
|
+
A 1 10-0
|
20
|
+
T 2 1-8
|
21
|
+
T 2 2-9
|
22
|
+
A 2 0-10
|
data/lib/save/m03.esf
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
mission03 11x11 11
|
2
|
+
.....###...
|
3
|
+
..#######..
|
4
|
+
.#.##.##.#.
|
5
|
+
#.#....#.##
|
6
|
+
##...##.###
|
7
|
+
#..#####..#
|
8
|
+
###.##...##
|
9
|
+
##.#....#.#
|
10
|
+
.#.##.##.#.
|
11
|
+
..#######..
|
12
|
+
...###.....
|
13
|
+
T 0 3-8
|
14
|
+
T 0 10-4
|
15
|
+
T 0 5-1
|
16
|
+
T 0 5-5
|
17
|
+
T 0 5-9
|
18
|
+
T 0 7-2
|
19
|
+
T 0 0-6
|
20
|
+
T 1 2-3
|
21
|
+
A 1 1-2
|
22
|
+
T 2 8-7
|
23
|
+
A 2 9-8
|
24
|
+
|
data/lib/ship.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require_relative './unit'
|
2
|
+
|
3
|
+
class Ship < Unit
|
4
|
+
def initialize(x, y, faction, map, infopane)
|
5
|
+
super
|
6
|
+
dir_path = File.dirname(__FILE__)
|
7
|
+
@image = Gosu::Image.new(dir_path + '/media/ship.png')
|
8
|
+
|
9
|
+
@name = 'ship'
|
10
|
+
@value = 10
|
11
|
+
@armor_left = @armor_max = 1
|
12
|
+
@moves_max = 2
|
13
|
+
@cargo_max = 3
|
14
|
+
end
|
15
|
+
|
16
|
+
def can_sail?
|
17
|
+
true
|
18
|
+
end
|
19
|
+
end
|
data/lib/town.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require_relative './unit'
|
2
|
+
|
3
|
+
class Town < Unit
|
4
|
+
attr_accessor :parts_built
|
5
|
+
|
6
|
+
def initialize(x, y, faction, map, infopane)
|
7
|
+
super
|
8
|
+
dir_path = File.dirname(__FILE__)
|
9
|
+
@image = Gosu::Image.new(dir_path + '/media/town.png')
|
10
|
+
|
11
|
+
@name = 'town'
|
12
|
+
@value = 20
|
13
|
+
@armor_left = @armor_max = 1
|
14
|
+
@moves_max = 0
|
15
|
+
|
16
|
+
@parts_built = 0
|
17
|
+
@cargo_max = 10
|
18
|
+
set_function(FUNCBUILD)
|
19
|
+
end
|
20
|
+
|
21
|
+
def can_build?
|
22
|
+
true
|
23
|
+
end
|
24
|
+
end
|
data/lib/unit.rb
ADDED
@@ -0,0 +1,244 @@
|
|
1
|
+
require_relative './unitFunction'
|
2
|
+
|
3
|
+
# All capturable game pieces
|
4
|
+
class Unit
|
5
|
+
attr_accessor :x, :y, :faction, :function, :cargo
|
6
|
+
|
7
|
+
|
8
|
+
def initialize(x, y, faction, map, infopane)
|
9
|
+
@x = x
|
10
|
+
@y = y
|
11
|
+
@faction = faction
|
12
|
+
@map = map
|
13
|
+
@infopane = infopane
|
14
|
+
|
15
|
+
@name = 'unit'
|
16
|
+
@value = 1
|
17
|
+
@armor_max = 1
|
18
|
+
@armor_left = @armor_max
|
19
|
+
@moves_max = 1
|
20
|
+
@moves_left = @moves_max
|
21
|
+
@cargo = [] # transported units
|
22
|
+
@cargo_max = 0
|
23
|
+
@function = UnitFunction.new(FUNCNONE)
|
24
|
+
|
25
|
+
|
26
|
+
|
27
|
+
# Store yourself
|
28
|
+
coords_unit = @map.get_unit(@x, @y)
|
29
|
+
if !coords_unit
|
30
|
+
@map.set_unit(@x, @y, self)
|
31
|
+
else # some town has just built you
|
32
|
+
coords_unit.cargo.insert(-1, self) # -1 = to the end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Add <value> to the other faction
|
37
|
+
def destroy
|
38
|
+
@infopane.add_score(3 - @faction - 1, @value) # TODO more factions?
|
39
|
+
# TODO is this deleted enough?
|
40
|
+
@map.set_unit(@x, @y, nil)
|
41
|
+
end
|
42
|
+
|
43
|
+
def capture(by_whom)
|
44
|
+
# add <value> to the capturing faction
|
45
|
+
@infopane.add_score(by_whom - 1, @value)
|
46
|
+
@faction = by_whom
|
47
|
+
|
48
|
+
# if you are a town, start building units
|
49
|
+
if can_build?
|
50
|
+
set_function(FUNCBUILD)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def update(key)
|
55
|
+
old_x = @x
|
56
|
+
old_y = @y
|
57
|
+
|
58
|
+
case key
|
59
|
+
# Cardinal directions
|
60
|
+
when Gosu::KbLeft, Gosu::KbA then
|
61
|
+
@x -= 1 unless @x <= 0
|
62
|
+
when Gosu::KbRight, Gosu::KbD then
|
63
|
+
@x += 1 unless @x >= MAPX
|
64
|
+
when Gosu::KbUp, Gosu::KbW then
|
65
|
+
@y -= 1 unless @y <= 0
|
66
|
+
when Gosu::KbDown, Gosu::KbX then
|
67
|
+
@y += 1 unless @y >= MAPY
|
68
|
+
|
69
|
+
# Intercardinal directions
|
70
|
+
when Gosu::KbQ then
|
71
|
+
unless @x <= 0 || @y <= 0
|
72
|
+
@x -= 1
|
73
|
+
@y -= 1
|
74
|
+
end
|
75
|
+
when Gosu::KbE then
|
76
|
+
unless @x >= MAPX || @y <= 0
|
77
|
+
@x += 1
|
78
|
+
@y -= 1
|
79
|
+
end
|
80
|
+
when Gosu::KbZ then
|
81
|
+
unless @x <= 0 || @y >= MAPY
|
82
|
+
@x -= 1
|
83
|
+
@y += 1
|
84
|
+
end
|
85
|
+
when Gosu::KbC then
|
86
|
+
unless @x >= MAPX || @y >= MAPY
|
87
|
+
@x += 1
|
88
|
+
@y += 1
|
89
|
+
end
|
90
|
+
|
91
|
+
# Functions
|
92
|
+
when Gosu::KbS then
|
93
|
+
set_function(FUNCSENTRY)
|
94
|
+
when Gosu::KbB then
|
95
|
+
set_function(FUNCBUILD)
|
96
|
+
end
|
97
|
+
|
98
|
+
check_movement(old_x, old_y)
|
99
|
+
end
|
100
|
+
|
101
|
+
|
102
|
+
# Processes move of unit and takes care of its (un)loading or attack
|
103
|
+
def check_movement(old_x, old_y)
|
104
|
+
if @x != old_x || @y != old_y
|
105
|
+
oldcoords_unit = @map.get_unit(old_x, old_y)
|
106
|
+
newcoords_unit = @map.get_unit(@x, @y)
|
107
|
+
|
108
|
+
# If there is nobody or is there friendly unit with some cargo space
|
109
|
+
if !newcoords_unit || \
|
110
|
+
(newcoords_unit.faction == @faction && newcoords_unit.can_transport?)
|
111
|
+
|
112
|
+
# Leave old coordinates
|
113
|
+
if oldcoords_unit == self
|
114
|
+
@map.set_unit(old_x, old_y, nil)
|
115
|
+
else # if you have been transported
|
116
|
+
puts "oldcoords_unit.cargo = \"#{oldcoords_unit.cargo}\""
|
117
|
+
oldcoords_unit.cargo.delete(self)
|
118
|
+
puts "oldcoords_unit.cargo = \"#{oldcoords_unit.cargo}\""
|
119
|
+
end
|
120
|
+
|
121
|
+
# Get to new coordinates
|
122
|
+
if newcoords_unit == nil
|
123
|
+
@map.set_unit(@x, @y, self)
|
124
|
+
else # if you are going to be transported
|
125
|
+
newcoords_unit.cargo.insert(-1, self) # -1 = to the end
|
126
|
+
end
|
127
|
+
|
128
|
+
else # if there already is somebody
|
129
|
+
# Stay on your original tile
|
130
|
+
@x = old_x
|
131
|
+
@y = old_y
|
132
|
+
|
133
|
+
# Don't capture allies
|
134
|
+
if newcoords_unit.faction != @faction
|
135
|
+
puts to_s + ' is capturing ' + newcoords_unit.to_s # TODO capture only towns, do combat otherwise
|
136
|
+
newcoords_unit.capture(@faction)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
@moves_left -= 1
|
140
|
+
|
141
|
+
# Check if unit is on invalid type of tile
|
142
|
+
if tile_check == false
|
143
|
+
puts to_s + " found itself in a bad place"
|
144
|
+
destroy
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
|
150
|
+
def draw
|
151
|
+
@image.draw(@x * TILESIZE, (@y + 1) * TILESIZE, ZUNIT,
|
152
|
+
scale_x = 1, scale_y = 1, color = COLOUR[@faction])
|
153
|
+
end
|
154
|
+
|
155
|
+
def can_move
|
156
|
+
(can_fly? || can_sail? || can_ride?) && @moves_left > 0
|
157
|
+
end
|
158
|
+
|
159
|
+
def can_fly?
|
160
|
+
false
|
161
|
+
end
|
162
|
+
|
163
|
+
def can_sail?
|
164
|
+
false
|
165
|
+
end
|
166
|
+
|
167
|
+
def can_ride?
|
168
|
+
false
|
169
|
+
end
|
170
|
+
|
171
|
+
def can_build?
|
172
|
+
false
|
173
|
+
end
|
174
|
+
|
175
|
+
# Unit is able to both transport other units and currently has some space left
|
176
|
+
def can_transport?
|
177
|
+
@cargo_max > 0 && @cargo.size < @cargo_max
|
178
|
+
end
|
179
|
+
|
180
|
+
def is_transporting?
|
181
|
+
@cargo.size > 0
|
182
|
+
end
|
183
|
+
|
184
|
+
def tile_check
|
185
|
+
case @map.tile(@x, @y)
|
186
|
+
when TILE_SEA
|
187
|
+
return can_fly? || can_sail?
|
188
|
+
when TILE_GROUND
|
189
|
+
return can_fly? || can_ride?
|
190
|
+
end
|
191
|
+
true
|
192
|
+
end
|
193
|
+
|
194
|
+
def function
|
195
|
+
@function.func
|
196
|
+
end
|
197
|
+
|
198
|
+
def set_function(func)
|
199
|
+
unless @faction == 0 # neutral faction doesn't need functions
|
200
|
+
if (func == FUNCBUILD && !can_build?)
|
201
|
+
puts to_s + ": this unit can't build other units"
|
202
|
+
end
|
203
|
+
|
204
|
+
if @function == func
|
205
|
+
puts to_s + ": function already set to #{@function.func}"
|
206
|
+
else
|
207
|
+
@function.func = func
|
208
|
+
puts to_s + ": function set to #{@function.func}"
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
|
214
|
+
def function!
|
215
|
+
ret = @function.func!(@x, @y, @map, @infopane)
|
216
|
+
puts to_s + ret
|
217
|
+
end
|
218
|
+
|
219
|
+
# Set short info string: type, faction, coordinates
|
220
|
+
def to_s
|
221
|
+
"#{@name} (FAC#{@faction} #{@x}-#{@y})"
|
222
|
+
end
|
223
|
+
|
224
|
+
# Set long info string: short info string, armor, moves, function, cargo
|
225
|
+
def info
|
226
|
+
ret = to_s + ": armor #{@armor_left}/#{@armor_max}"
|
227
|
+
|
228
|
+
if can_move
|
229
|
+
ret = ret + ", moves #{@moves_left}/#{@moves_max}"
|
230
|
+
end
|
231
|
+
|
232
|
+
ret = ret + ", func #{@function.func}"
|
233
|
+
|
234
|
+
if @cargo.size > 0
|
235
|
+
ret = ret + ", transports #{@cargo.size} units"
|
236
|
+
end
|
237
|
+
|
238
|
+
ret
|
239
|
+
end
|
240
|
+
|
241
|
+
def reset_moves
|
242
|
+
@moves_left = @moves_max
|
243
|
+
end
|
244
|
+
end
|
data/lib/unitFunction.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
PARTS = 3
|
2
|
+
|
3
|
+
class UnitFunction
|
4
|
+
attr_accessor :func
|
5
|
+
|
6
|
+
def initialize(function = FUNCNONE)
|
7
|
+
@func = function
|
8
|
+
end
|
9
|
+
|
10
|
+
def func!(xx, yy, map, infopane)
|
11
|
+
ret = " didn't actually do anything (ERROR)"
|
12
|
+
|
13
|
+
unit = map.get_unit(xx, yy)
|
14
|
+
if unit == nil
|
15
|
+
abort("unitFunction.func!(): Functioning unit not found at given coordinates (#{xx}-#{yy})")
|
16
|
+
end
|
17
|
+
|
18
|
+
case @func
|
19
|
+
# Build given unit
|
20
|
+
when FUNCBUILD
|
21
|
+
if(unit.parts_built >= PARTS) # just == should be enough
|
22
|
+
ret = " completed building of army"
|
23
|
+
unit.parts_built = 0
|
24
|
+
Army.new(unit.x, unit.y, unit.faction, map, infopane) # TODO allow setting what to build
|
25
|
+
else
|
26
|
+
ret = " built next part of army"
|
27
|
+
unit.parts_built = unit.parts_built + 1
|
28
|
+
end
|
29
|
+
|
30
|
+
# Wake up when enemies are nearby
|
31
|
+
when FUNCSENTRY
|
32
|
+
units_around = map.all_units.select { |uu|
|
33
|
+
(uu.x - xx).abs <= 1 &&
|
34
|
+
(uu.y - yy).abs <= 1 &&
|
35
|
+
uu.faction != unit.faction
|
36
|
+
}
|
37
|
+
if units_around.size > 0
|
38
|
+
ret = " woke up"
|
39
|
+
@func = FUNCNONE
|
40
|
+
else
|
41
|
+
ret = " was on sentry duty"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
ret
|
46
|
+
end
|
47
|
+
end
|
metadata
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: empi
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.16.6
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Detros
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2016-04-14 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: gosu
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rake
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '10.0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '10.0'
|
46
|
+
description: ! 'Empi: Ruby Edition is a turn based wargame, currently deep in development.
|
47
|
+
While learning Ruby I have found there are hardly any strategic games avaiable.
|
48
|
+
So this should be Ruby version of Classic Empire, wargame from old times.'
|
49
|
+
email: rasunadon@seznam.cz
|
50
|
+
executables: []
|
51
|
+
extensions: []
|
52
|
+
extra_rdoc_files: []
|
53
|
+
files:
|
54
|
+
- lib/docu/Empi v14.png
|
55
|
+
- lib/docu/info.txt
|
56
|
+
- lib/media/town.png
|
57
|
+
- lib/media/ship.png
|
58
|
+
- lib/media/army.png
|
59
|
+
- lib/media/cursor.png
|
60
|
+
- lib/media/sea.png
|
61
|
+
- lib/media/ground.png
|
62
|
+
- lib/save/m02.esf
|
63
|
+
- lib/save/m01.esf
|
64
|
+
- lib/save/m03.esf
|
65
|
+
- lib/ship.rb
|
66
|
+
- lib/unit.rb
|
67
|
+
- lib/unitFunction.rb
|
68
|
+
- lib/town.rb
|
69
|
+
- lib/map.rb
|
70
|
+
- lib/army.rb
|
71
|
+
- lib/cursor.rb
|
72
|
+
- lib/infopane.rb
|
73
|
+
- lib/empi.rb
|
74
|
+
homepage: http://www.bay12forums.com/smf/index.php?topic=157538.0
|
75
|
+
licenses:
|
76
|
+
- CC-BY-SA 3.0
|
77
|
+
post_install_message:
|
78
|
+
rdoc_options: []
|
79
|
+
require_paths:
|
80
|
+
- lib
|
81
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
82
|
+
none: false
|
83
|
+
requirements:
|
84
|
+
- - ! '>='
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
version: '0'
|
87
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
88
|
+
none: false
|
89
|
+
requirements:
|
90
|
+
- - ! '>='
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: '0'
|
93
|
+
requirements: []
|
94
|
+
rubyforge_project:
|
95
|
+
rubygems_version: 1.8.23
|
96
|
+
signing_key:
|
97
|
+
specification_version: 3
|
98
|
+
summary: Turn-based wargame
|
99
|
+
test_files: []
|