empi 0.16.6
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.
- 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: []
|