tactical_fighter 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|