tactical_fighter 1.0.0
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/bin/tactical_fighter +780 -0
- metadata +82 -0
@@ -0,0 +1,780 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
#Tactical Fighter V1.0
|
4
|
+
#this file is part of Tactical Fighter
|
5
|
+
#Tactical Fighter is distributed under the CDDL licence
|
6
|
+
#the author of Tactical Fighter is Dobai-Pataky Balint(dpblnt@gmail.com)
|
7
|
+
|
8
|
+
|
9
|
+
begin
|
10
|
+
require 'gtk2'
|
11
|
+
rescue LoadError => err
|
12
|
+
print "install ruby-gtk2\n"
|
13
|
+
exit
|
14
|
+
end
|
15
|
+
|
16
|
+
require 'drb'
|
17
|
+
|
18
|
+
#default language
|
19
|
+
@@lang="en"
|
20
|
+
|
21
|
+
Strings={
|
22
|
+
"en"=>{"title"=>"Tactical Fighter"},
|
23
|
+
"hu"=>{"Map size"=>"Térkép méret", "title"=>"Taktikai Vadász","Language"=>"Nyelv", "Own address"=>"Saját cím", "Enemy address"=>"Ellenség címe", "Prepare the planes"=>"Készítsd elő a repülőket", "You Lost"=>"Vesztettél", "Shoot"=>"Lőjj", "Wait"=>"Várj", "You Won"=>"Nyertél"}
|
24
|
+
}
|
25
|
+
|
26
|
+
class String
|
27
|
+
def lng
|
28
|
+
@@lang && Strings.has_key?(@@lang) && Strings[@@lang].has_key?(self) ? Strings[@@lang][self] : self
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class Main < Gtk::Window
|
33
|
+
class MultiMap < Gtk::HBox
|
34
|
+
class Map < Gtk::EventBox
|
35
|
+
class Plane
|
36
|
+
Down=1
|
37
|
+
Right=2
|
38
|
+
Up=3
|
39
|
+
Left=4
|
40
|
+
InitialState=0
|
41
|
+
ReadyState=1
|
42
|
+
def initialize(nx,ny)
|
43
|
+
@state=InitialState
|
44
|
+
@nx=nx
|
45
|
+
@ny=ny
|
46
|
+
@head_x=rand(@nx-7).to_i+4
|
47
|
+
@head_y=rand(@ny-7).to_i+4
|
48
|
+
@direction=rand(4).to_i+1 #torso direction from head
|
49
|
+
end
|
50
|
+
def on_coordinates?(x,y)
|
51
|
+
head?(x,y) || body?(x,y)
|
52
|
+
end
|
53
|
+
def body?(x,y)
|
54
|
+
case @direction
|
55
|
+
when Down then @head_x-2 <= x && x <= @head_x+2 && y == @head_y+1 || @head_x-1 <= x && x <= @head_x+1 && y == @head_y+3 || x == @head_x && y == @head_y+2
|
56
|
+
when Up then @head_x-2 <= x && x <= @head_x+2 && y == @head_y-1 || @head_x-1 <= x && x <= @head_x+1 && y == @head_y-3 || x == @head_x && y == @head_y-2
|
57
|
+
when Left then @head_y-2 <= y && y <= @head_y+2 && x == @head_x-1 || @head_y-1 <= y && y <= @head_y+1 && x == @head_x-3 || y == @head_y && x == @head_x-2
|
58
|
+
when Right then @head_y-2 <= y && y <= @head_y+2 && x == @head_x+1 || @head_y-1 <= y && y <= @head_y+1 && x == @head_x+3 || y == @head_y && x == @head_x+2
|
59
|
+
end
|
60
|
+
end
|
61
|
+
def ready?
|
62
|
+
@status == ReadyState
|
63
|
+
end
|
64
|
+
def invalidate
|
65
|
+
@status = InitialState
|
66
|
+
end
|
67
|
+
def validate
|
68
|
+
@status = ReadyState
|
69
|
+
end
|
70
|
+
def head?(x,y)
|
71
|
+
x == @head_x and y == @head_y
|
72
|
+
end
|
73
|
+
def rotate_cw(only_by_rotate=false)
|
74
|
+
@direction-=1
|
75
|
+
@direction+=4 if @direction<1
|
76
|
+
if only_by_rotate
|
77
|
+
keep_on_map_by_rotate_only
|
78
|
+
else
|
79
|
+
keep_on_map
|
80
|
+
end
|
81
|
+
end
|
82
|
+
def move_to(newx,newy)
|
83
|
+
@head_x=newx
|
84
|
+
@head_y=newy
|
85
|
+
keep_on_map
|
86
|
+
return @head_x,@head_y
|
87
|
+
end
|
88
|
+
def keep_on_map
|
89
|
+
newx=@head_x
|
90
|
+
newy=@head_y
|
91
|
+
#keep head on map
|
92
|
+
newx=0 if @head_x < 0
|
93
|
+
newy=0 if @head_y < 0
|
94
|
+
newx=@nx if @head_x > @nx
|
95
|
+
newy=@ny if @head_y > @ny
|
96
|
+
#keep body on map
|
97
|
+
case @direction
|
98
|
+
when Down then newy=@ny-3 if @head_y+3>@ny
|
99
|
+
when Up then newy=4 if @head_y<4
|
100
|
+
when Left then newx=4 if @head_x<4
|
101
|
+
when Right then newx=@nx-3 if @head_x+3>@nx
|
102
|
+
end
|
103
|
+
case @direction
|
104
|
+
when Up,Down then
|
105
|
+
newx=3 if @head_x<3
|
106
|
+
newx=@nx-2 if @head_x>@nx-2
|
107
|
+
when Right,Left then
|
108
|
+
newy=3 if @head_y<3
|
109
|
+
newy=@ny-2 if @head_y>@ny-2
|
110
|
+
end
|
111
|
+
|
112
|
+
move_to(newx,newy) if newx!=@head_x || newy!=@head_y
|
113
|
+
end
|
114
|
+
def keep_on_map_by_rotate_only(nhead_x=@head_x,nhead_y=@head_y)
|
115
|
+
newx=@head_x
|
116
|
+
newy=@head_y
|
117
|
+
if nhead_x!=@head_x || nhead_y!=@head_y
|
118
|
+
@head_x=nhead_x
|
119
|
+
@head_y=nhead_y
|
120
|
+
end
|
121
|
+
#keep body on map
|
122
|
+
case @direction
|
123
|
+
when Down then newy=@ny-3 if @head_y+3>@ny
|
124
|
+
when Up then newy=4 if @head_y<4
|
125
|
+
when Left then newx=4 if @head_x<4
|
126
|
+
when Right then newx=@nx-3 if @head_x+3>@nx
|
127
|
+
end
|
128
|
+
case @direction
|
129
|
+
when Up,Down then
|
130
|
+
newx=3 if @head_x<3
|
131
|
+
newx=@nx-2 if @head_x>@nx-2
|
132
|
+
when Right,Left then
|
133
|
+
newy=3 if @head_y<3
|
134
|
+
newy=@ny-2 if @head_y>@ny-2
|
135
|
+
end
|
136
|
+
rotate_cw(true) if newx!=@head_x || newy!=@head_y
|
137
|
+
validate
|
138
|
+
end
|
139
|
+
|
140
|
+
def draw(cr,xroot,yroot,bs)
|
141
|
+
r=bs/3
|
142
|
+
if ready?
|
143
|
+
cr.set_source_rgba(0,0,1,0.5)
|
144
|
+
else
|
145
|
+
cr.set_source_rgba(0,1,0,0.5)
|
146
|
+
end
|
147
|
+
cr.move_to(xroot+bs*(@head_x-0.5)+rx(0,-r),yroot+bs*(@head_y-0.5)+ry(0,-r))
|
148
|
+
rct(cr,-r,0,-r,0,-r,r*2)
|
149
|
+
rct(cr,0,r,0,r,-r,r)
|
150
|
+
rct(cr,-(bs*2-r),0,-(bs*2-r),0,-(bs*2-r),r)
|
151
|
+
rct(cr,0,r,0,r,(bs*2-r),r)
|
152
|
+
rct(cr,r,0,r,0,r,r)
|
153
|
+
rct(cr,0,bs,0,bs,-r,bs)
|
154
|
+
rct(cr,-r*2,0,-r*2,0,-r*2,r)
|
155
|
+
|
156
|
+
rct(cr,0,r,0,r,bs+r,r)
|
157
|
+
rct(cr,bs+r,0,bs+r,0,bs+r,-r)
|
158
|
+
|
159
|
+
rct(cr,0,-r,0,-r,-r*2,-r)
|
160
|
+
rct(cr,-r,0,-r,0,-r,-r)
|
161
|
+
rct(cr,0,-bs,0,-bs,r,-bs)
|
162
|
+
rct(cr,bs*2-r,0,bs*2-r,0,bs*2-r,-r)
|
163
|
+
rct(cr,0,-r,0,-r,-(bs*2-r),-r)
|
164
|
+
rct(cr,-r,0,-r,0,-r,-r)
|
165
|
+
rct(cr,0,-2*r,0,-2*r,-r,-2*r)
|
166
|
+
cr.close_path
|
167
|
+
cr.fill
|
168
|
+
|
169
|
+
cr.stroke
|
170
|
+
end
|
171
|
+
def rct(cr,x1,y1,x2,y2,xd,yd)
|
172
|
+
cr.rel_curve_to(rx(x1,y1),ry(x1,y1),rx(x2,y2),ry(x2,y2),rx(xd,yd),ry(xd,yd))
|
173
|
+
end
|
174
|
+
def rx(x,y)
|
175
|
+
case @direction
|
176
|
+
when Down then x
|
177
|
+
when Up then -x
|
178
|
+
when Left then -y
|
179
|
+
when Right then y
|
180
|
+
end
|
181
|
+
end
|
182
|
+
def ry(x,y)
|
183
|
+
case @direction
|
184
|
+
when Down then y
|
185
|
+
when Up then -y
|
186
|
+
when Left then -x
|
187
|
+
when Right then x
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
#-------------- map -----------
|
193
|
+
Local=1
|
194
|
+
Remote=2
|
195
|
+
Empty=0
|
196
|
+
Missed=1
|
197
|
+
Hit=2
|
198
|
+
Wasted=3
|
199
|
+
def initialize(main,map_type,nx,ny)
|
200
|
+
@nx=nx
|
201
|
+
@ny=ny
|
202
|
+
@main=main
|
203
|
+
@map_type=map_type
|
204
|
+
@shoot_fifo=Array.new
|
205
|
+
@block_size=20
|
206
|
+
@line_width=(@block_size/7).to_i
|
207
|
+
@planes=Array.new
|
208
|
+
@plane_count=(0.03*@nx*@ny).to_i
|
209
|
+
@plane_count.times{|i| @planes.push(Plane.new(@nx,@ny))} if local?
|
210
|
+
super()
|
211
|
+
set_visible_window(false)
|
212
|
+
add(@widget=Gtk::Fixed.new)
|
213
|
+
set_size_request(@nx*@block_size,@ny*@block_size)
|
214
|
+
@map=Hash.new
|
215
|
+
for i in 1 .. @nx
|
216
|
+
@map[i]=Hash.new
|
217
|
+
for j in 1 .. @ny
|
218
|
+
@map[i][j]=Empty
|
219
|
+
end
|
220
|
+
end
|
221
|
+
@widget.signal_connect('size-allocate'){|me,allocation|
|
222
|
+
@block_size=(me.allocation.width-1)/@nx
|
223
|
+
yblock_size=(me.allocation.height-1)/@ny
|
224
|
+
@block_size=yblock_size if yblock_size<@block_size
|
225
|
+
@line_width=(@block_size/7).to_i
|
226
|
+
@xroot=me.allocation.x+(me.allocation.width-@nx*@block_size-1)/2
|
227
|
+
@yroot=me.allocation.y+(me.allocation.height-@ny*@block_size-1)/2
|
228
|
+
}
|
229
|
+
@widget.signal_connect('expose-event'){|me,ev|
|
230
|
+
cr=me.window.create_cairo_context
|
231
|
+
#grid
|
232
|
+
cr.set_source_rgb(0.8,0.8,0.8)
|
233
|
+
cr.set_line_width(1)
|
234
|
+
cr.set_line_cap(Cairo::LineCap::ROUND)
|
235
|
+
for i in 0 .. @nx
|
236
|
+
for j in 0 .. @ny
|
237
|
+
cr.move_to(@xroot+i*@block_size,@yroot)
|
238
|
+
cr.line_to(@xroot+i*@block_size,@yroot+@ny*@block_size)
|
239
|
+
cr.move_to(@xroot,@yroot+j*@block_size)
|
240
|
+
cr.line_to(@xroot+@nx*@block_size,@yroot+j*@block_size)
|
241
|
+
end
|
242
|
+
end
|
243
|
+
cr.stroke
|
244
|
+
cr.set_source_rgb(0.3,0.3,0.3)
|
245
|
+
cr.rectangle(@xroot,@yroot,@nx*@block_size,@ny*@block_size)
|
246
|
+
cr.stroke
|
247
|
+
all_set?#invalidate planes
|
248
|
+
#planes
|
249
|
+
@planes.each{|plane| plane.draw(cr,@xroot,@yroot,@block_size)}
|
250
|
+
for i in 1 .. @nx do
|
251
|
+
for j in 1 .. @ny do
|
252
|
+
if (cnt=count_plane_on_coordinates?(i,j))>1
|
253
|
+
plane=first_plane_on_coordinates?(i,j)
|
254
|
+
cr.set_source_rgba(1.0*(cnt-1)/(@plane_count-1), if plane.ready? then 1 else 0 end, 1-1.0*(cnt-1)/(@plane_count-1),0.2)
|
255
|
+
cr.rectangle(@xroot+(i-1)*@block_size+1,@yroot+(j-1)*@block_size+1,@block_size-2,@block_size-2)
|
256
|
+
cr.fill
|
257
|
+
end
|
258
|
+
#battle-map
|
259
|
+
case @map[i][j]
|
260
|
+
when Hit then
|
261
|
+
cr.set_source_rgb(1,0,0)
|
262
|
+
cr.set_line_width(@line_width)
|
263
|
+
cr.set_line_cap(Cairo::LineCap::ROUND)
|
264
|
+
cr.move_to(@xroot+(i-1)*@block_size+@line_width*2,@yroot+(j-1)*@block_size+@line_width*2)
|
265
|
+
cr.line_to(@xroot+i*@block_size-@line_width*2,@yroot+j*@block_size-@line_width*2)
|
266
|
+
cr.move_to(@xroot+i*@block_size-@line_width*2,@yroot+(j-1)*@block_size+@line_width*2)
|
267
|
+
cr.line_to(@xroot+(i-1)*@block_size+@line_width*2,@yroot+j*@block_size-@line_width*2)
|
268
|
+
cr.stroke
|
269
|
+
when Missed then
|
270
|
+
cr.set_source_rgb(0,1,0)
|
271
|
+
cr.set_line_width(@line_width)
|
272
|
+
cr.set_line_cap(Cairo::LineCap::ROUND)
|
273
|
+
cr.arc(@xroot+(i-0.5)*@block_size, @yroot+(j-0.5)*@block_size, @block_size/3, 0, Math::PI*2)
|
274
|
+
cr.stroke
|
275
|
+
when Wasted then
|
276
|
+
cr.set_source_rgb(1,0,0)
|
277
|
+
cr.set_line_width(@line_width)
|
278
|
+
cr.set_line_cap(Cairo::LineCap::ROUND)
|
279
|
+
cr.arc(@xroot+(i-0.5)*@block_size, @yroot+(j-0.5)*@block_size, @block_size/3, 0 , Math::PI*2)
|
280
|
+
cr.move_to(@xroot+(i-1)*@block_size+@line_width*2,@yroot+(j-1)*@block_size+@line_width*2)
|
281
|
+
cr.line_to(@xroot+i*@block_size-@line_width*2,@yroot+j*@block_size-@line_width*2)
|
282
|
+
cr.move_to(@xroot+i*@block_size-@line_width*2,@yroot+(j-1)*@block_size+@line_width*2)
|
283
|
+
cr.line_to(@xroot+(i-1)*@block_size+@line_width*2,@yroot+j*@block_size-@line_width*2)
|
284
|
+
cr.stroke
|
285
|
+
end
|
286
|
+
end
|
287
|
+
end
|
288
|
+
cr.stroke
|
289
|
+
#draw the shoot_fifo
|
290
|
+
@shoot_fifo.each_index{|ind|
|
291
|
+
@shoot_fifo[ind]
|
292
|
+
layout=cr.create_pango_layout
|
293
|
+
layout.text=(ind+1).to_s
|
294
|
+
layout.set_width(@block_size * Pango::SCALE).set_alignment(Pango::Layout::ALIGN_CENTER)
|
295
|
+
layout.set_font_description(Pango::FontDescription.new("Sans #{(@block_size*0.6).to_i}"))
|
296
|
+
cr.update_pango_layout(layout)
|
297
|
+
cr.move_to(@xroot+@block_size*(@shoot_fifo[ind][0]-1),@yroot+@block_size*(@shoot_fifo[ind][1]-1))
|
298
|
+
cr.set_source_rgba(0.9,0.1,0.1,0.5)
|
299
|
+
cr.show_pango_layout(layout)
|
300
|
+
cr.stroke
|
301
|
+
}
|
302
|
+
#draw round transparent charts on the map, the waste a smaller inside
|
303
|
+
waste_ratio,hit_ratio = hit_counter
|
304
|
+
|
305
|
+
r=@block_size-1
|
306
|
+
xc=@xroot+@block_size
|
307
|
+
yc=@yroot+@ny*@block_size-@block_size
|
308
|
+
cr.set_line_width(1)
|
309
|
+
cr.set_source_rgba(0,2,0,0.1)
|
310
|
+
cr.move_to(xc,yc)
|
311
|
+
cr.arc(xc,yc,r,0,Math::PI*2)
|
312
|
+
cr.move_to(xc,yc)
|
313
|
+
cr.fill
|
314
|
+
cr.stroke
|
315
|
+
if hit_ratio>0
|
316
|
+
cr.set_source_rgba(1,0,0,0.1)
|
317
|
+
cr.move_to(xc,yc)
|
318
|
+
cr.line_to(xc+r,yc)
|
319
|
+
cr.arc(xc,yc,r,0,Math::PI*2*hit_ratio)
|
320
|
+
cr.line_to(xc,yc)
|
321
|
+
cr.close_path
|
322
|
+
cr.fill
|
323
|
+
cr.stroke
|
324
|
+
end
|
325
|
+
|
326
|
+
r=@block_size/2-1
|
327
|
+
xc=@xroot+@block_size
|
328
|
+
yc=@yroot+@ny*@block_size-@block_size
|
329
|
+
cr.set_line_width(1)
|
330
|
+
cr.set_source_rgba(0,2,0,0.3)
|
331
|
+
cr.move_to(xc,yc)
|
332
|
+
cr.arc(xc,yc,r,0,Math::PI*2)
|
333
|
+
cr.move_to(xc,yc)
|
334
|
+
cr.fill
|
335
|
+
cr.stroke
|
336
|
+
if waste_ratio>0
|
337
|
+
cr.set_source_rgba(1,0,0,0.3)
|
338
|
+
cr.move_to(xc,yc)
|
339
|
+
cr.line_to(xc+r,yc)
|
340
|
+
cr.arc(xc,yc,r,0,Math::PI*2*waste_ratio)
|
341
|
+
cr.line_to(xc,yc)
|
342
|
+
cr.close_path
|
343
|
+
cr.fill
|
344
|
+
cr.stroke
|
345
|
+
end
|
346
|
+
|
347
|
+
|
348
|
+
#message
|
349
|
+
message=nil
|
350
|
+
if local?
|
351
|
+
message="Prepare the planes".lng if @main.place?
|
352
|
+
message="You Lost".lng if @main.lost?
|
353
|
+
message="" if @main.won?
|
354
|
+
end
|
355
|
+
if remote?
|
356
|
+
message="Shoot".lng if @main.shoot?
|
357
|
+
message="Wait".lng if @main.wait?
|
358
|
+
message="You Won".lng if @main.won?
|
359
|
+
message="" if @main.lost?
|
360
|
+
end
|
361
|
+
|
362
|
+
unless message.nil?
|
363
|
+
layout=cr.create_pango_layout
|
364
|
+
layout.text=message
|
365
|
+
layout.set_width(@block_size*@nx/2 * Pango::SCALE)
|
366
|
+
font_size=@block_size
|
367
|
+
layout.set_font_description(Pango::FontDescription.new("Sans #{font_size}"))
|
368
|
+
cr.update_pango_layout(layout)
|
369
|
+
while layout.size[0]/Pango::SCALE>@block_size*@nx do
|
370
|
+
font_size-=1
|
371
|
+
layout.set_font_description(Pango::FontDescription.new("Sans #{font_size}"))
|
372
|
+
cr.update_pango_layout(layout)
|
373
|
+
end
|
374
|
+
cr.move_to(@xroot+(@block_size*@nx-layout.size[0]/Pango::SCALE)/2,@yroot+(@block_size*@ny-layout.size[1]/Pango::SCALE)/2)
|
375
|
+
cr.set_source_rgba(1,1,0,0.6)
|
376
|
+
cr.show_pango_layout(layout)
|
377
|
+
cr.stroke
|
378
|
+
end
|
379
|
+
true
|
380
|
+
}
|
381
|
+
signal_connect('button-press-event'){|me,ev|
|
382
|
+
if ev.button == 1
|
383
|
+
if local? && @main.place?
|
384
|
+
#start moving plane
|
385
|
+
@xshift=((ev.x-@xroot)/@block_size).to_i+1
|
386
|
+
@yshift=((ev.y-@yroot)/@block_size).to_i+1
|
387
|
+
@dragged=false
|
388
|
+
end
|
389
|
+
if remote?
|
390
|
+
x=((me.allocation.x+ev.x-@xroot)/@block_size).to_i+1
|
391
|
+
y=((me.allocation.y+ev.y-@yroot)/@block_size).to_i+1
|
392
|
+
if 1<=x && x<=@nx && 1<=y && y<=@ny && @map[x][y] == Empty
|
393
|
+
if @main.shoot?
|
394
|
+
#shoot the enemy
|
395
|
+
set_cell_state(x,y,@main.shoot_enemy(x,y))
|
396
|
+
@main.wait unless @main.ended?
|
397
|
+
elsif @main.wait?
|
398
|
+
if @shoot_fifo.include?([x,y])
|
399
|
+
#remove from the fifo if already there
|
400
|
+
@shoot_fifo.delete([x,y])
|
401
|
+
redraw_map
|
402
|
+
else
|
403
|
+
#add to shoot fifo
|
404
|
+
@shoot_fifo.push([x,y])
|
405
|
+
redraw_cell(x,y)
|
406
|
+
end
|
407
|
+
end
|
408
|
+
end
|
409
|
+
end
|
410
|
+
end
|
411
|
+
if ev.button == 3
|
412
|
+
if local? && @main.place?
|
413
|
+
#make plane ready
|
414
|
+
if ev.event_type == Gdk::Event::BUTTON2_PRESS
|
415
|
+
#double-right-click validate all planes
|
416
|
+
@planes.each{|pl| pl.validate}
|
417
|
+
redraw_map
|
418
|
+
@main.ready if all_set?
|
419
|
+
else
|
420
|
+
if plane=first_head_on_coordinates?(((ev.x-@xroot)/@block_size).to_i+1,((ev.y-@yroot)/@block_size).to_i+1)
|
421
|
+
if plane.ready? then plane.invalidate else plane.validate end
|
422
|
+
redraw_map
|
423
|
+
@main.ready if all_set?
|
424
|
+
end
|
425
|
+
end
|
426
|
+
end
|
427
|
+
if remote?
|
428
|
+
#rotate guessed enemy plane
|
429
|
+
x=((me.allocation.x+ev.x-@xroot)/@block_size).to_i+1
|
430
|
+
y=((me.allocation.y+ev.y-@yroot)/@block_size).to_i+1
|
431
|
+
if @map[x][y] == Wasted
|
432
|
+
if plane=first_head_on_coordinates?(x,y)
|
433
|
+
plane.rotate_cw(true)
|
434
|
+
@planes.each{|plane| plane.validate}
|
435
|
+
redraw_map
|
436
|
+
end
|
437
|
+
end
|
438
|
+
end
|
439
|
+
end
|
440
|
+
}
|
441
|
+
signal_connect('button-release-event'){|me,ev|
|
442
|
+
if ev.button == 1
|
443
|
+
if local? && @main.place? && !@xshift.nil? && !@yshift.nil?
|
444
|
+
#rotate plane
|
445
|
+
x=((ev.x-@xroot)/@block_size).to_i+1
|
446
|
+
y=((ev.y-@yroot)/@block_size).to_i+1
|
447
|
+
plane=first_head_on_coordinates?(@xshift,@yshift)
|
448
|
+
if !plane.nil? && !@dragged && !plane.ready?
|
449
|
+
plane.rotate_cw
|
450
|
+
redraw_map #also invalidate planes if needed
|
451
|
+
end
|
452
|
+
@xshift=nil
|
453
|
+
@yshift=nil
|
454
|
+
end
|
455
|
+
end
|
456
|
+
}
|
457
|
+
signal_connect('motion-notify-event'){|me,ev|
|
458
|
+
if local? && @main.place? && !@xshift.nil? && !@yshift.nil?
|
459
|
+
#move plane
|
460
|
+
if plane=first_head_on_coordinates?(@xshift,@yshift)
|
461
|
+
x=((ev.x-@xroot)/@block_size).to_i+1
|
462
|
+
y=((ev.y-@yroot)/@block_size).to_i+1
|
463
|
+
if (x!=@xshift || y!=@yshift) && !plane.ready?
|
464
|
+
@xshift,@yshift=plane.move_to(x,y)
|
465
|
+
if plane.head?(x,y)
|
466
|
+
@dragged=true
|
467
|
+
redraw_map
|
468
|
+
end
|
469
|
+
end
|
470
|
+
end
|
471
|
+
end
|
472
|
+
}
|
473
|
+
end
|
474
|
+
def redraw_map
|
475
|
+
@widget.window.invalidate(Gdk::Rectangle.new(@widget.allocation.x,@widget.allocation.y,@widget.allocation.width,@widget.allocation.height),false)
|
476
|
+
end
|
477
|
+
def redraw_cell(x,y)
|
478
|
+
@widget.window.invalidate(Gdk::Rectangle.new(@xroot+@block_size*(x-1),@yroot+@block_size*(y-1),@block_size,@block_size),false)
|
479
|
+
end
|
480
|
+
def local?
|
481
|
+
@map_type == Local
|
482
|
+
end
|
483
|
+
def remote?
|
484
|
+
@map_type == Remote
|
485
|
+
end
|
486
|
+
def fifo_shoot
|
487
|
+
if @main.shoot? && coo=@shoot_fifo[0]
|
488
|
+
#shoot the enemy from fifo
|
489
|
+
set_cell_state(coo[0],coo[1],@main.shoot_enemy(coo[0],coo[1]))
|
490
|
+
@shoot_fifo.delete_at(0)
|
491
|
+
@main.wait unless @main.ended?
|
492
|
+
end
|
493
|
+
end
|
494
|
+
def count_plane_on_coordinates?(x,y)
|
495
|
+
cnt=0
|
496
|
+
@planes.each{|plane| cnt+=1 if plane.on_coordinates?(x,y)}
|
497
|
+
cnt
|
498
|
+
end
|
499
|
+
def first_plane_on_coordinates?(x,y)
|
500
|
+
pl=nil
|
501
|
+
@planes.each{|plane| pl=plane if plane.on_coordinates?(x,y) && pl.nil?}
|
502
|
+
pl
|
503
|
+
end
|
504
|
+
def first_head_on_coordinates?(x,y)
|
505
|
+
pl=nil
|
506
|
+
@planes.each{|plane| pl=plane if plane.head?(x,y) && pl.nil?}
|
507
|
+
pl
|
508
|
+
end
|
509
|
+
def all_set?
|
510
|
+
cnt=0
|
511
|
+
for i in 1 .. @nx
|
512
|
+
for j in 1 .. @ny
|
513
|
+
if count_plane_on_coordinates?(i,j)>1
|
514
|
+
first_plane_on_coordinates?(i,j).invalidate
|
515
|
+
cnt+=1
|
516
|
+
end
|
517
|
+
end
|
518
|
+
end
|
519
|
+
good=cnt == 0
|
520
|
+
@planes.each{|plane| good=false unless plane.ready?}
|
521
|
+
good
|
522
|
+
end
|
523
|
+
def hit?(x,y)
|
524
|
+
cell_state=set_cell_state(x,y,if first_head_on_coordinates?(x,y)
|
525
|
+
Wasted
|
526
|
+
elsif first_plane_on_coordinates?(x,y)
|
527
|
+
Hit
|
528
|
+
else
|
529
|
+
Missed
|
530
|
+
end
|
531
|
+
)
|
532
|
+
@main.lost if all_wasted?
|
533
|
+
cell_state
|
534
|
+
end
|
535
|
+
def set_cell_state(x,y,state)
|
536
|
+
@map[x][y]=state
|
537
|
+
xwg=@xroot+x*@block_size
|
538
|
+
ywg=@xroot+y*@block_size
|
539
|
+
# redraw_map
|
540
|
+
# #@widget.window.invalidate(Gdk::Rectangle.new(xwg+1,ywg+1,@block_size-2,@block_size-2),false)
|
541
|
+
if remote? && state==Wasted
|
542
|
+
@planes.push(pp=Plane.new(@nx,@ny))
|
543
|
+
pp.keep_on_map_by_rotate_only(x,y)
|
544
|
+
end
|
545
|
+
state
|
546
|
+
end
|
547
|
+
def all_wasted?
|
548
|
+
waste_cnt=0
|
549
|
+
for i in 1 .. @nx
|
550
|
+
for j in 1 .. @ny
|
551
|
+
waste_cnt+=1 if @map[i][j] == Wasted
|
552
|
+
end
|
553
|
+
end
|
554
|
+
waste_cnt == @plane_count
|
555
|
+
end
|
556
|
+
def hit_counter
|
557
|
+
waste_cnt=0
|
558
|
+
hit_cnt=0
|
559
|
+
miss_cnt=0
|
560
|
+
for i in 1 .. @nx
|
561
|
+
for j in 1 .. @ny
|
562
|
+
waste_cnt+=1 if @map[i][j] == Wasted
|
563
|
+
hit_cnt+=1 if @map[i][j] == Hit
|
564
|
+
miss_cnt+=1 if @map[i][j] == Missed
|
565
|
+
end
|
566
|
+
end
|
567
|
+
return (waste_cnt.to_f/ @plane_count.to_f),hit_cnt.to_f/(hit_cnt.to_f+miss_cnt.to_f)
|
568
|
+
|
569
|
+
end
|
570
|
+
|
571
|
+
end
|
572
|
+
def initialize(main,nx,ny)
|
573
|
+
@main=main
|
574
|
+
super()
|
575
|
+
pack_start(@local=Map.new(main,Map::Local,nx,ny),true,true)
|
576
|
+
#pack_start(Gtk::Fixed.new.set_size_request(10,10))
|
577
|
+
pack_start(@remote=Map.new(main,Map::Remote,nx,ny),true,true)
|
578
|
+
show_all
|
579
|
+
end
|
580
|
+
attr_reader :local, :remote
|
581
|
+
end
|
582
|
+
|
583
|
+
class Setup < Gtk::Alignment
|
584
|
+
def initialize(main)
|
585
|
+
@main=main
|
586
|
+
super(0.5,0.5,0,0)
|
587
|
+
add(Gtk::VBox.new)
|
588
|
+
child.pack_start(Gtk::Table.new(2,2).
|
589
|
+
attach_defaults(@oa=Gtk::Label.new,0,1,0,1).attach_defaults(Gtk::Entry.new.set_text(@main.uri).set_editable(false).set_width_request(300),1,2,0,1).
|
590
|
+
attach_defaults(@ea=Gtk::Label.new,0,1,1,2).attach_defaults(@remote_address=Gtk::Entry.new,1,2,1,2)).
|
591
|
+
pack_start(
|
592
|
+
Gtk::HBox.new.
|
593
|
+
pack_start(@ms=Gtk::Label.new).
|
594
|
+
pack_start(@nxw=Gtk::SpinButton.new(10,40,1)).
|
595
|
+
pack_start(Gtk::Label.new('X')).
|
596
|
+
pack_start(@nyw=Gtk::SpinButton.new(10,40,1))
|
597
|
+
).
|
598
|
+
pack_start(
|
599
|
+
Gtk::HBox.new.
|
600
|
+
pack_start(@l=Gtk::Label.new).
|
601
|
+
pack_start(lang_combo=Gtk::ComboBox.new)
|
602
|
+
).
|
603
|
+
pack_start(Gtk::HBox.new.
|
604
|
+
pack_start(@connect=Gtk::Button.new(Gtk::Stock::MEDIA_PLAY)).
|
605
|
+
pack_start(@exit=Gtk::Button.new(Gtk::Stock::QUIT)))
|
606
|
+
Strings.each_key{|l| lang_combo.append_text(l)}
|
607
|
+
lang_combo.signal_connect("changed"){|me|
|
608
|
+
set_lang(me.active_text)
|
609
|
+
}
|
610
|
+
@nxw.signal_connect('value-changed'){|me| @remote_server.setup.set_map_size(@nxw.value,@nyw.value) if @remote_server}
|
611
|
+
@nyw.signal_connect('value-changed'){|me| @remote_server.setup.set_map_size(@nxw.value,@nyw.value) if @remote_server}
|
612
|
+
|
613
|
+
@exit.signal_connect('clicked'){|me|
|
614
|
+
DRb.stop_service
|
615
|
+
Gtk.main_quit
|
616
|
+
}
|
617
|
+
@connect.signal_connect('clicked'){|me| @main.start_game}
|
618
|
+
|
619
|
+
lang_combo.set_active(1)
|
620
|
+
end
|
621
|
+
attr_reader :nxw, :nyw, :remote_address
|
622
|
+
|
623
|
+
def set_lang(lang)
|
624
|
+
@@lang=lang
|
625
|
+
@main.set_title('title'.lng)
|
626
|
+
@oa.set_text('Own address'.lng)
|
627
|
+
@ea.set_text('Enemy address'.lng)
|
628
|
+
@ms.set_text('Map size'.lng)
|
629
|
+
@l.set_text("Language".lng)
|
630
|
+
end
|
631
|
+
def set_map_size(x,y)
|
632
|
+
@nxw.set_value(x)
|
633
|
+
@nyw.set_value(y)
|
634
|
+
end
|
635
|
+
end
|
636
|
+
|
637
|
+
Idle=1
|
638
|
+
Place=2
|
639
|
+
Shoot=3
|
640
|
+
Wait=4
|
641
|
+
Won=5
|
642
|
+
Lost=6
|
643
|
+
|
644
|
+
|
645
|
+
def initialize
|
646
|
+
super()
|
647
|
+
@server=DRb.start_service(nil,self)
|
648
|
+
@remote_server=nil
|
649
|
+
@state=Idle
|
650
|
+
add(@setup=Setup.new(self))
|
651
|
+
|
652
|
+
signal_connect('delete-event') {|me,ev|
|
653
|
+
end_game
|
654
|
+
true
|
655
|
+
}
|
656
|
+
|
657
|
+
show_all
|
658
|
+
end
|
659
|
+
attr_reader :state, :setup
|
660
|
+
|
661
|
+
def idle?
|
662
|
+
@state == Idle
|
663
|
+
end
|
664
|
+
def place?
|
665
|
+
@state == Place
|
666
|
+
end
|
667
|
+
def shoot?
|
668
|
+
@state == Shoot
|
669
|
+
end
|
670
|
+
def wait?
|
671
|
+
@state == Wait
|
672
|
+
end
|
673
|
+
def ended?
|
674
|
+
@state == Won || @state == Lost
|
675
|
+
end
|
676
|
+
def won?
|
677
|
+
@state == Won
|
678
|
+
end
|
679
|
+
def lost?
|
680
|
+
@state == Lost
|
681
|
+
end
|
682
|
+
|
683
|
+
def end_game
|
684
|
+
unless idle?
|
685
|
+
@maps.destroy
|
686
|
+
add(@setup)
|
687
|
+
show_all
|
688
|
+
@state=Idle
|
689
|
+
@remote_server.end_game
|
690
|
+
@remote_server=nil
|
691
|
+
end
|
692
|
+
end
|
693
|
+
|
694
|
+
def start_game
|
695
|
+
begin
|
696
|
+
helloed=false
|
697
|
+
@remote_server=DRbObject.new(nil, "druby://#{@setup.remote_address.text}")
|
698
|
+
@remote_server.setup.set_map_size(@setup.nxw.value,@setup.nyw.value)
|
699
|
+
helloed=@remote_server.hello(self)
|
700
|
+
@setup.remote_address.set_text(@remote_server.uri)
|
701
|
+
rescue =>e
|
702
|
+
print e.message,"\n",e.backtrace.join("\n\t")
|
703
|
+
end
|
704
|
+
if helloed
|
705
|
+
remove(child)
|
706
|
+
add(@maps=MultiMap.new(self,setup.nxw.value,setup.nyw.value))
|
707
|
+
@state=Place
|
708
|
+
end
|
709
|
+
end
|
710
|
+
|
711
|
+
def hello(remote_server)
|
712
|
+
@remote_server=remote_server
|
713
|
+
@setup.remote_address.set_text(@remote_server.uri)
|
714
|
+
remove(child)
|
715
|
+
add(@maps=MultiMap.new(self,setup.nxw.value,setup.nyw.value))
|
716
|
+
@state=Place
|
717
|
+
true
|
718
|
+
end
|
719
|
+
def ready
|
720
|
+
if @remote_server.ready?
|
721
|
+
wait
|
722
|
+
end
|
723
|
+
end
|
724
|
+
def shoot
|
725
|
+
@state=Shoot
|
726
|
+
@remote_server.dont_shoot
|
727
|
+
@maps.local.redraw_map
|
728
|
+
@maps.remote.redraw_map
|
729
|
+
@maps.remote.fifo_shoot
|
730
|
+
end
|
731
|
+
def dont_shoot
|
732
|
+
@state=Wait
|
733
|
+
@maps.local.redraw_map
|
734
|
+
@maps.remote.redraw_map
|
735
|
+
end
|
736
|
+
def wait
|
737
|
+
@state=Wait
|
738
|
+
@remote_server.dont_wait
|
739
|
+
@maps.local.redraw_map
|
740
|
+
@maps.remote.redraw_map
|
741
|
+
end
|
742
|
+
def dont_wait
|
743
|
+
@state=Shoot
|
744
|
+
@maps.local.redraw_map
|
745
|
+
@maps.remote.redraw_map
|
746
|
+
@maps.remote.fifo_shoot
|
747
|
+
end
|
748
|
+
def ready?
|
749
|
+
@maps.local.all_set?
|
750
|
+
end
|
751
|
+
def shoot_enemy(x,y)
|
752
|
+
@remote_server.enemy_shoot(x,y)
|
753
|
+
end
|
754
|
+
def enemy_shoot(x,y)
|
755
|
+
@maps.local.hit?(x,y)
|
756
|
+
end
|
757
|
+
def lost
|
758
|
+
@state=Lost
|
759
|
+
@remote_server.won
|
760
|
+
@maps.local.redraw_map
|
761
|
+
@maps.remote.redraw_map
|
762
|
+
end
|
763
|
+
def won
|
764
|
+
@state=Won
|
765
|
+
@maps.local.redraw_map
|
766
|
+
@maps.remote.redraw_map
|
767
|
+
end
|
768
|
+
def uri
|
769
|
+
@server.uri[@server.uri.rindex('/')+1 .. @server.uri.length]
|
770
|
+
end
|
771
|
+
end
|
772
|
+
|
773
|
+
begin
|
774
|
+
Main.new
|
775
|
+
rescue =>e
|
776
|
+
print e.message,"\n",e.backtrace.join("\n\t")
|
777
|
+
end
|
778
|
+
|
779
|
+
Gtk.main
|
780
|
+
|
metadata
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: tactical_fighter
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 23
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
- 0
|
10
|
+
version: 1.0.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Dobai-Pataky Balint
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-03-05 00:00:00 +02:00
|
19
|
+
default_executable: tactical_fighter
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: gtk2
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 377
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
- 90
|
33
|
+
- 7
|
34
|
+
version: 0.90.7
|
35
|
+
type: :runtime
|
36
|
+
version_requirements: *id001
|
37
|
+
description: A multiplayer LAN game on gtk2 for anyone to protect the friendly air force by taking down the enemy fighters
|
38
|
+
email: dpblnt@gmail.com
|
39
|
+
executables:
|
40
|
+
- tactical_fighter
|
41
|
+
extensions: []
|
42
|
+
|
43
|
+
extra_rdoc_files: []
|
44
|
+
|
45
|
+
files:
|
46
|
+
- bin/tactical_fighter
|
47
|
+
has_rdoc: true
|
48
|
+
homepage: http://sourceforge.net/projects/tacticalfighter/
|
49
|
+
licenses:
|
50
|
+
- CDDL
|
51
|
+
post_install_message:
|
52
|
+
rdoc_options: []
|
53
|
+
|
54
|
+
require_paths:
|
55
|
+
- lib
|
56
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
hash: 3
|
62
|
+
segments:
|
63
|
+
- 0
|
64
|
+
version: "0"
|
65
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
hash: 3
|
71
|
+
segments:
|
72
|
+
- 0
|
73
|
+
version: "0"
|
74
|
+
requirements: []
|
75
|
+
|
76
|
+
rubyforge_project:
|
77
|
+
rubygems_version: 1.3.7
|
78
|
+
signing_key:
|
79
|
+
specification_version: 3
|
80
|
+
summary: tactical_fighter
|
81
|
+
test_files: []
|
82
|
+
|