tactical_fighter 1.0.0

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