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.
Files changed (2) hide show
  1. data/bin/tactical_fighter +780 -0
  2. 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
+