UG_RRobots 1.2

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 (165) hide show
  1. data/bin/rrobots +202 -0
  2. data/bin/tournament +413 -0
  3. data/config/rrobots.yml +15 -0
  4. data/contribs/allbots.rb +0 -0
  5. data/doc/manual.rdoc +126 -0
  6. data/doc/manual_fr.rdoc +129 -0
  7. data/images/explosion00.gif +0 -0
  8. data/images/explosion01.gif +0 -0
  9. data/images/explosion02.gif +0 -0
  10. data/images/explosion03.gif +0 -0
  11. data/images/explosion04.gif +0 -0
  12. data/images/explosion05.gif +0 -0
  13. data/images/explosion06.gif +0 -0
  14. data/images/explosion07.gif +0 -0
  15. data/images/explosion08.gif +0 -0
  16. data/images/explosion09.gif +0 -0
  17. data/images/explosion10.gif +0 -0
  18. data/images/explosion11.gif +0 -0
  19. data/images/explosion12.gif +0 -0
  20. data/images/explosion13.gif +0 -0
  21. data/images/explosion14.gif +0 -0
  22. data/images/red_body000.gif +0 -0
  23. data/images/red_body010.gif +0 -0
  24. data/images/red_body020.gif +0 -0
  25. data/images/red_body030.gif +0 -0
  26. data/images/red_body040.gif +0 -0
  27. data/images/red_body050.gif +0 -0
  28. data/images/red_body060.gif +0 -0
  29. data/images/red_body070.gif +0 -0
  30. data/images/red_body080.gif +0 -0
  31. data/images/red_body090.gif +0 -0
  32. data/images/red_body100.gif +0 -0
  33. data/images/red_body110.gif +0 -0
  34. data/images/red_body120.gif +0 -0
  35. data/images/red_body130.gif +0 -0
  36. data/images/red_body140.gif +0 -0
  37. data/images/red_body150.gif +0 -0
  38. data/images/red_body160.gif +0 -0
  39. data/images/red_body170.gif +0 -0
  40. data/images/red_body180.gif +0 -0
  41. data/images/red_body190.gif +0 -0
  42. data/images/red_body200.gif +0 -0
  43. data/images/red_body210.gif +0 -0
  44. data/images/red_body220.gif +0 -0
  45. data/images/red_body230.gif +0 -0
  46. data/images/red_body240.gif +0 -0
  47. data/images/red_body250.gif +0 -0
  48. data/images/red_body260.gif +0 -0
  49. data/images/red_body270.gif +0 -0
  50. data/images/red_body280.gif +0 -0
  51. data/images/red_body290.gif +0 -0
  52. data/images/red_body300.gif +0 -0
  53. data/images/red_body310.gif +0 -0
  54. data/images/red_body320.gif +0 -0
  55. data/images/red_body330.gif +0 -0
  56. data/images/red_body340.gif +0 -0
  57. data/images/red_body350.gif +0 -0
  58. data/images/red_radar000.gif +0 -0
  59. data/images/red_radar010.gif +0 -0
  60. data/images/red_radar020.gif +0 -0
  61. data/images/red_radar030.gif +0 -0
  62. data/images/red_radar040.gif +0 -0
  63. data/images/red_radar050.gif +0 -0
  64. data/images/red_radar060.gif +0 -0
  65. data/images/red_radar070.gif +0 -0
  66. data/images/red_radar080.gif +0 -0
  67. data/images/red_radar090.gif +0 -0
  68. data/images/red_radar100.gif +0 -0
  69. data/images/red_radar110.gif +0 -0
  70. data/images/red_radar120.gif +0 -0
  71. data/images/red_radar130.gif +0 -0
  72. data/images/red_radar140.gif +0 -0
  73. data/images/red_radar150.gif +0 -0
  74. data/images/red_radar160.gif +0 -0
  75. data/images/red_radar170.gif +0 -0
  76. data/images/red_radar180.gif +0 -0
  77. data/images/red_radar190.gif +0 -0
  78. data/images/red_radar200.gif +0 -0
  79. data/images/red_radar210.gif +0 -0
  80. data/images/red_radar220.gif +0 -0
  81. data/images/red_radar230.gif +0 -0
  82. data/images/red_radar240.gif +0 -0
  83. data/images/red_radar250.gif +0 -0
  84. data/images/red_radar260.gif +0 -0
  85. data/images/red_radar270.gif +0 -0
  86. data/images/red_radar280.gif +0 -0
  87. data/images/red_radar290.gif +0 -0
  88. data/images/red_radar300.gif +0 -0
  89. data/images/red_radar310.gif +0 -0
  90. data/images/red_radar320.gif +0 -0
  91. data/images/red_radar330.gif +0 -0
  92. data/images/red_radar340.gif +0 -0
  93. data/images/red_radar350.gif +0 -0
  94. data/images/red_turret000.gif +0 -0
  95. data/images/red_turret010.gif +0 -0
  96. data/images/red_turret020.gif +0 -0
  97. data/images/red_turret030.gif +0 -0
  98. data/images/red_turret040.gif +0 -0
  99. data/images/red_turret050.gif +0 -0
  100. data/images/red_turret060.gif +0 -0
  101. data/images/red_turret070.gif +0 -0
  102. data/images/red_turret080.gif +0 -0
  103. data/images/red_turret090.gif +0 -0
  104. data/images/red_turret100.gif +0 -0
  105. data/images/red_turret110.gif +0 -0
  106. data/images/red_turret120.gif +0 -0
  107. data/images/red_turret130.gif +0 -0
  108. data/images/red_turret140.gif +0 -0
  109. data/images/red_turret150.gif +0 -0
  110. data/images/red_turret160.gif +0 -0
  111. data/images/red_turret170.gif +0 -0
  112. data/images/red_turret180.gif +0 -0
  113. data/images/red_turret190.gif +0 -0
  114. data/images/red_turret200.gif +0 -0
  115. data/images/red_turret210.gif +0 -0
  116. data/images/red_turret220.gif +0 -0
  117. data/images/red_turret230.gif +0 -0
  118. data/images/red_turret240.gif +0 -0
  119. data/images/red_turret250.gif +0 -0
  120. data/images/red_turret260.gif +0 -0
  121. data/images/red_turret270.gif +0 -0
  122. data/images/red_turret280.gif +0 -0
  123. data/images/red_turret290.gif +0 -0
  124. data/images/red_turret300.gif +0 -0
  125. data/images/red_turret310.gif +0 -0
  126. data/images/red_turret320.gif +0 -0
  127. data/images/red_turret330.gif +0 -0
  128. data/images/red_turret340.gif +0 -0
  129. data/images/red_turret350.gif +0 -0
  130. data/images/toolbox.gif +0 -0
  131. data/lib/battlefield.rb +102 -0
  132. data/lib/bullets.rb +39 -0
  133. data/lib/configuration.rb +26 -0
  134. data/lib/explosions.rb +20 -0
  135. data/lib/overloads.rb +10 -0
  136. data/lib/robot.rb +122 -0
  137. data/lib/robotrunner.rb +260 -0
  138. data/lib/tkarena.rb +197 -0
  139. data/lib/toolboxes.rb +28 -0
  140. data/robots/BillDuck.rb +92 -0
  141. data/robots/BotOne.rb +39 -0
  142. data/robots/DuckBill.rb +384 -0
  143. data/robots/DuckBill04.rb +330 -0
  144. data/robots/DuckToEndAllDucks.rb +140 -0
  145. data/robots/EdgeBot.rb +203 -0
  146. data/robots/HuntingDuck.rb +74 -0
  147. data/robots/HyperactiveDuck.rb +15 -0
  148. data/robots/Killer.rb +58 -0
  149. data/robots/Kite.rb +193 -0
  150. data/robots/KoDuck.rb +57 -0
  151. data/robots/LinearShooter.rb +279 -0
  152. data/robots/LuckyDuck.rb +83 -0
  153. data/robots/MoxonoM.rb +85 -0
  154. data/robots/MsgBot.rb +13 -0
  155. data/robots/NervousDuck.rb +13 -0
  156. data/robots/Polisher.rb +15 -0
  157. data/robots/RomBot.rb +514 -0
  158. data/robots/RoomPainter.rb +205 -0
  159. data/robots/Rrrkele.rb +48 -0
  160. data/robots/Seeker.rb +57 -0
  161. data/robots/ShootingStation.rb +15 -0
  162. data/robots/SittingDuck.rb +18 -0
  163. data/robots/SniperDuck.rb +277 -0
  164. data/robots/WallPainter.rb +224 -0
  165. metadata +220 -0
@@ -0,0 +1,57 @@
1
+ require 'robot'
2
+
3
+ class KoDuck
4
+ include Robot
5
+
6
+ def initialize *bd
7
+ super
8
+ end
9
+
10
+ def near_wall?
11
+ if x+10 <= size || y+10 < size || (x+size+10 >= battlefield_width) ||
12
+ (y+size+10 >= battlefield_height)
13
+ return true
14
+ else
15
+ return false
16
+ end
17
+ end
18
+
19
+ def tick events
20
+ @out_of_wall = 0
21
+ if time == 0 && near_wall?
22
+ turn -10
23
+ accelerate 1
24
+ return
25
+ end
26
+ n = (rand + 0.5) * -1
27
+ if near_wall? && @out_of_wall.zero?
28
+ n *= 10
29
+ @out_of_wall += 1
30
+ turn n
31
+ else
32
+ @out_of_wall += 1 unless @out_of_wall.zero?
33
+ turn n
34
+ accelerate 1
35
+ if @out_of_wall > 100
36
+ @out_of_wall = 0
37
+ if n.abs > 5
38
+ n /=5.0
39
+ end
40
+ end
41
+ end
42
+ if !events['robot_scanned'].empty?
43
+ fire 3
44
+ if (n * 5).abs > 30
45
+ n = (n > 0) ? 3: -3
46
+ end
47
+ turn_gun(-n * 10)
48
+ else
49
+ turn_gun -6
50
+ fire 0.1
51
+ end
52
+
53
+ end
54
+
55
+ end
56
+
57
+
@@ -0,0 +1,279 @@
1
+ require 'robot'
2
+ require 'matrix'
3
+
4
+
5
+ class Numeric
6
+
7
+ def deg2rad
8
+ self * 0.0174532925199433
9
+ end
10
+
11
+ def rad2deg
12
+ self * 57.2957795130823
13
+ end
14
+
15
+ end
16
+
17
+ class Array
18
+ def average
19
+ inject{|s,i|s+i} / size.to_f
20
+ end
21
+ def sd
22
+ avg = average
23
+ Math.sqrt( inject(0){|s,i| s+(i-avg)**2} / (size-1.0) )
24
+ end
25
+ end
26
+
27
+ class Vector
28
+ include Enumerable
29
+
30
+ def each &block
31
+ @elements.each(&block)
32
+ end
33
+
34
+ end
35
+
36
+
37
+ class LinearShooter
38
+ include Robot
39
+
40
+ def initialize *args, &block
41
+ super
42
+ @rt = @radar_scan = 15
43
+ @min_radar_scan = 1.5
44
+ @max_radar_scan = 60.0
45
+ @radar_turned = false
46
+ @lock = false
47
+ @lock_threshold = 15.0
48
+ @firing_threshold = 20.0
49
+ @wanted_turn = @wanted_gun_turn = @wanted_radar_turn = 0
50
+ @rturn_dir = 1
51
+ @racc_dir = 1
52
+ @serial_hit_limit = 10
53
+ @serial_hit_counter = 0
54
+ @target_positions = []
55
+ @min_distance = 1500
56
+ @sd_limit = 30
57
+ end
58
+
59
+ def tick events
60
+ @prev_health = energy if time == 0
61
+ scan events
62
+ firing_solution events
63
+ navigate events
64
+ turn_hull
65
+ turn_turret
66
+ turn_radar_dish
67
+ @prev_health = energy
68
+ end
69
+
70
+ def scan events
71
+ if events['robot_scanned'].empty?
72
+ increase_radar_scan
73
+ @lock = false
74
+ else
75
+ decrease_radar_scan
76
+ @lock = @radar_scan.abs < @lock_threshold
77
+ end
78
+ @rt = (time/2 % 2 < 1 ? -@radar_scan/2.0 : @radar_scan/2.0) if @radar_scan.abs < @max_radar_scan - 0.1
79
+ @wanted_radar_turn += @rt
80
+ end
81
+
82
+ def firing_solution events
83
+ add_target_position(events['robot_scanned'])
84
+ th = target_heading
85
+ gtd = heading_distance(gun_heading, th) if th
86
+ @firepower = [1.5e5 / (@min_distance)**2, 3*25 / (@vsd||1500)].max / 2.0
87
+ msg = "Hope this hits.."
88
+ msg = "On target." if @firepower > 1.5
89
+ msg = "Takedown!" if @firepower > 2.25
90
+ msg = "SURE HIT!" if @firepower > 3.0
91
+ say msg if @on_target and gun_heat == 0
92
+ fire @firepower if @on_target
93
+ if @lock and gtd and gtd.abs < @firing_threshold
94
+ @wanted_gun_turn = gtd
95
+ @on_target = true
96
+ else
97
+ #fire @firepower*0.3
98
+ @wanted_gun_turn = gtd || (gun_radar_distance/3.0) + Math.sin(time*0.2)*(1000.0/@min_distance)
99
+ @on_target = false
100
+ end
101
+ end
102
+
103
+ def add_target_position(distances)
104
+ unless distances.empty?
105
+ positions = distances.map{|d|
106
+ tx = x + Math.cos((radar_heading - @radar_scan.abs / 2.0).deg2rad) * d[0]
107
+ ty = y - Math.sin((radar_heading - @radar_scan.abs / 2.0).deg2rad) * d[0]
108
+ [d, Vector[tx,ty]]
109
+ }
110
+ last = @target_positions.last
111
+ position = if last
112
+ positions.min{|a,b| (a[1] - last).r <=> (b[1] - last).r }[1]
113
+ else
114
+ positions.min{|a,b| a[0] <=> b[0]}[1]
115
+ end
116
+ @min_distance = distances.min{|a,b| a[0]<=>b[0]}[0]
117
+ @target_positions.push position if position
118
+ end
119
+ @target_positions.shift if @target_positions.size > 200
120
+ end
121
+
122
+ def average_last_positions(c=4)
123
+ tps = @target_positions[-10,10]
124
+ d = tps.size/c
125
+ ptas = (0...c).map{|i| tps[i*d,d] }
126
+ ptas.map{|pta| average(pta) }
127
+ end
128
+
129
+ def average arr
130
+ arr.inject{|s,i| s+i} * (1.0/arr.size)
131
+ end
132
+
133
+ def sd arr
134
+ Math.sqrt(arr.map{|v| v[0]}.sd**2 + arr.map{|v| v[1]}.sd**2)
135
+ end
136
+
137
+ def deltas arr
138
+ arr[0..-2].zip(arr[1..-1]).map{|a,b| b - a}
139
+ end
140
+
141
+ def target_heading
142
+ return nil if @target_positions.size < 10
143
+ return radar_heading if @min_distance < 200
144
+ lps = average_last_positions(5)
145
+ p4 = lps.last
146
+ vs = deltas(lps).map{|v| v * 0.5 }
147
+ @vsd = sd vs
148
+ return nil if @vsd > @sd_limit
149
+ v = average(vs)
150
+ if v.r < 4.0
151
+ #say 'Stationary targeting'
152
+ return heading_for(average(lps))
153
+ end
154
+ p4 = p4 + (v*0.5)
155
+ distance = p4 - Vector[x,y]
156
+ shot_speed = (30/8.0)*v.r
157
+ a = distance[0]**2 + distance[1]**2
158
+ b = 2*distance[0]*v[0] + 2*distance[1]*v[1]
159
+ c = v[0]**2 + v[1]**2 - shot_speed**2
160
+ t = 2*a / (-b + Math.sqrt(b**2-4*a*c))
161
+ ep = p4 + v*t
162
+ estimated_position = Vector[[size, [battlefield_width-size, ep[0]].min].max, [size, [battlefield_height-size, ep[1]].min].max]
163
+ est_head = heading_for(estimated_position)
164
+ #say 'Linear targeting'
165
+ est_head + (rand-0.5)*@vsd*0.2
166
+ end
167
+
168
+ def format(arr, precision = 1)
169
+ case arr
170
+ when Float
171
+ (arr * 10**precision).round * 10**-precision
172
+ when Array
173
+ arr.map{|i| format i, precision}
174
+ else
175
+ arr
176
+ end
177
+ end
178
+
179
+ def gun_vector
180
+ Vector[Math.cos(gun_heading.deg2rad), -Math.sin(gun_heading.deg2rad)]
181
+ end
182
+
183
+ def heading_for(position)
184
+ distance = position - Vector[x,y]
185
+ heading = (Math.atan2(-distance[1], distance[0])).rad2deg
186
+ heading += 360 if heading < 0
187
+ heading
188
+ end
189
+
190
+ def navigate events
191
+ if events['got_hit'].empty?
192
+ @serial_hit_counter -= 0.05 if @serial_hit_counter > 0
193
+ accelerate(@racc_dir) if velocity.abs < 7.9
194
+ else
195
+ @serial_hit_counter += @prev_health - events['got_hit'].last.last
196
+ @serial_hit_counter = [@serial_hit_counter, @serial_hit_limit + 0.04].max
197
+ if @serial_hit_counter > @serial_hit_limit
198
+ acc = velocity > 0 ? 1 : -1
199
+ accelerate(acc) if velocity.abs < 7.9
200
+ end
201
+ end
202
+ if @serial_hit_counter > @serial_hit_limit and not events['got_hit'].empty? and @wanted_turn <= 1
203
+ @wanted_turn = @rturn_dir * 30
204
+ @rturn_dir *= -1 if rand < 0.05
205
+ elsif approaching_wall? and @wanted_turn <= 1
206
+ @wanted_turn = 60 * @rturn_dir
207
+ @rturn_dir *= -1 if rand < 0.5
208
+ elsif rand < 0.15
209
+ @wanted_turn += rand * 10 * @rturn_dir
210
+ elsif rand < 0.01
211
+ @rturn_dir *= -1
212
+ elsif rand < 0.01
213
+ @racc_dir *= -1
214
+ end
215
+ end
216
+
217
+ def increase_radar_scan
218
+ @radar_scan *= 1.5
219
+ @radar_scan = [@radar_scan, @max_radar_scan].min
220
+ end
221
+
222
+ def decrease_radar_scan
223
+ @radar_scan *= 0.6
224
+ @radar_scan = [@radar_scan, @min_radar_scan].max
225
+ end
226
+
227
+ def heading_distance h1, h2
228
+ limit h2 - h1, 180
229
+ end
230
+
231
+ def limit value, m
232
+ value -= 360 if value > 180
233
+ value += 360 if value < -180
234
+ value = -m if value < -m
235
+ value = m if value > m
236
+ return value
237
+ end
238
+
239
+ def gun_radar_distance
240
+ heading_distance gun_heading, radar_heading
241
+ end
242
+
243
+ def turn_hull
244
+ turn_amt = [-10.0, [@wanted_turn, 10.0].min].max
245
+ #puts "Turning hull by: #{turn_amt}" if turn_amt.abs > 1
246
+ turn turn_amt
247
+ @wanted_turn -= turn_amt
248
+ @wanted_gun_turn -= turn_amt
249
+ @wanted_radar_turn -= turn_amt
250
+ end
251
+
252
+ def turn_turret
253
+ turn_amt = [-30.0, [@wanted_gun_turn, 30.0].min].max
254
+ #puts "Turning gun by: #{turn_amt}" if turn_amt.abs > 1
255
+ turn_gun turn_amt
256
+ @wanted_gun_turn -= turn_amt
257
+ @wanted_radar_turn -= turn_amt
258
+ end
259
+
260
+ def turn_radar_dish
261
+ turn_amt = [-60.0, [@wanted_radar_turn, 60.0].min].max
262
+ #puts "Turning radar by: #{turn_amt}" if turn_amt.abs > 1
263
+ turn_radar turn_amt
264
+ @wanted_radar_turn -= turn_amt
265
+ end
266
+
267
+ def approaching_wall?
268
+ if not ( (velocity > 0) ^ heading.between?(0.0, 180.0) )
269
+ y < 100
270
+ else
271
+ y > battlefield_height - 100
272
+ end or if not ( (velocity > 0) ^ heading.between?(90.0, 270.0) )
273
+ x < 100
274
+ else
275
+ x > battlefield_width - 100
276
+ end
277
+ end
278
+
279
+ end
@@ -0,0 +1,83 @@
1
+ require 'robot'
2
+ class LuckyDuck
3
+ include Robot
4
+ def initialize *bf
5
+ if bf.size != 0
6
+ super(bf[0])
7
+ @tourney = false
8
+ else
9
+ super
10
+ @tourney = true
11
+ end
12
+ @lastchange = time
13
+ @dc = []
14
+ @dc[300] = 3
15
+ @dc[300] = 3
16
+ @dc[300] = 3
17
+ @dc[300] = 3
18
+ @dc[300] = 3
19
+ end
20
+
21
+ def rel_direction(from, to)
22
+ rel = to -from
23
+ if rel > 180
24
+ rel = -360 + rel
25
+ end
26
+ if rel < -180
27
+ rel = 360 + rel
28
+ end
29
+ return rel
30
+ end
31
+
32
+ def a_rand(*args)
33
+ args.flatten!
34
+ return args[rand(args.size)]
35
+ end
36
+
37
+ def tick events
38
+ @enemy = 0 unless @enemy
39
+ @dist = 400 unless @dist
40
+ @gun_head = nil unless @gun_head
41
+ @head = (@head||=90)
42
+ @gun_head_to = (@gun_head_to||=90)
43
+ istop = (y-size <= size*2)
44
+ isleft = (x-size <= size*2)
45
+ isbottom = (battlefield_height-size <= (y+size))
46
+ isright = (battlefield_width-size <= (x+size))
47
+ if (time-@lastchange >= 5 || !events['got_hit'].empty?)
48
+ (isleft) ? (@head = a_rand([270,90])) : nil
49
+ (isbottom) ? (@head = a_rand([180,0])) : nil
50
+ (isright) ? (@head = a_rand([270,90])) : nil
51
+ (istop) ? (@head = a_rand([180,0])) : nil
52
+ (isleft && istop) ? (@head = a_rand([270,0])) : nil
53
+ (isleft && isbottom) ? (@head = a_rand([90,0])) : nil
54
+ (isright && istop) ? (@head = a_rand([270,180])) : nil
55
+ (isright && isbottom) ? (@head = a_rand([90,180])) : nil
56
+ @lastchange = time
57
+ end
58
+ if !events['robot_scanned'].empty?
59
+ @enemy = 10
60
+ @dist = events['robot_scanned'].first.first
61
+ @gun_head = gun_heading
62
+ end
63
+ rel = rel_direction(heading, @head)
64
+ (rel >= 5) ? (turn(rel*10);turn_gun(-(rel*10))) : turn(0)
65
+ if gun_heat <= 0
66
+ if @enemy >= 1
67
+ offset = (gun_heading+(@dist/200).to_i).abs
68
+ gun_rel = rel_direction(gun_heading, @gun_head)
69
+ puts "[#{gun_rel} | #{@gun_head} ~~ #{gun_heading} (#{offset})"
70
+ #(gun_rel != 0) ? turn_gun(gun_rel) : turn_gun(+2)
71
+ turn_gun(gun_rel/2)
72
+
73
+ (@dist <= 600) ? fire(3) : fire(0.1)*30
74
+ end
75
+ end
76
+ turn_gun(-10) if @gun_head.nil?
77
+ accelerate(1)
78
+ @enemy = ((@enemy <= 0) ? (@ememy; @gun_head = nil) : (@enemy-1))
79
+ if @enemy == 1
80
+ turn_gun(15)
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,85 @@
1
+ require 'robot'
2
+ class MoxonoM
3
+ include Robot
4
+ def initialize *bf
5
+ if bf.size != 0
6
+ super(bf[0])
7
+ @tourney = false
8
+ else
9
+ super
10
+ @tourney = true
11
+ end
12
+ @adjust_radar = true
13
+ @turn_gun_range = (-5..5).to_a
14
+ @turn_range = (-10..10).to_a
15
+ @lastchange = time
16
+ end
17
+
18
+ def rel_direction(from, to)
19
+ rel = to -from
20
+ if rel > 180
21
+ rel = -360 + rel
22
+ end
23
+ if rel < -180
24
+ rel = 360 + rel
25
+ end
26
+ return rel
27
+ end
28
+
29
+ def a_rand(*args)
30
+ args.flatten!
31
+ return args[rand(args.size)]
32
+ end
33
+
34
+ def tick events
35
+ @enemy = 0 unless @enemy
36
+ @dist = 400 unless @dist
37
+ @gun_head = nil unless @gun_head
38
+ @adjust = nil unless @adjust
39
+ if !@adjust
40
+ turn_radar(-5)
41
+ @adjust = true
42
+ end
43
+ @head = (@head||=90)
44
+ @gun_head_to = (@gun_head_to||=90)
45
+ top = y-size
46
+ left = x-size
47
+ bottom = battlefield_height-size
48
+ right = battlefield_width-size
49
+ istop = (top <= size)
50
+ isleft = (left <= size)
51
+ isbottom = (bottom <= (y+size))
52
+ isright = (right <= (x+size))
53
+ if (time-@lastchange >= 15 || !events['got_hit'].empty?)
54
+ (isleft) ? (@head = a_rand([270,90,0])) : nil
55
+ (isbottom) ? (@head = a_rand([180,90,0])) : nil
56
+ (isright) ? (@head = a_rand([270,90,180])) : nil
57
+ (istop) ? (@head = a_rand([270,180,0])) : nil
58
+ (isleft && istop) ? (@head = a_rand([315,270,0])) : nil
59
+ (isleft && isbottom) ? (@head = a_rand([45,90,0])) : nil
60
+ (isright && istop) ? (@head = a_rand([270,180,225])) : nil
61
+ (isright && isbottom) ? (@head = a_rand([135,90,180])) : nil
62
+ @lastchange = time
63
+ end
64
+ if !events['robot_scanned'].empty?
65
+ @enemy = 5
66
+ @dist = events['robot_scanned'].first.first
67
+ @gun_head = gun_heading
68
+ fire(3)
69
+ end
70
+ rel = rel_direction(heading, @head)
71
+ (rel >= 5) ? (turn(rel*10);turn_gun(-(rel*10))) : turn(0)
72
+ if gun_heat <= 0
73
+ if @enemy >= 1
74
+ (@dist <= 300) ? fire(3) : fire(3)
75
+ gun_rel = rel_direction(gun_heading, @gun_head-5)
76
+ (gun_rel >= 10) ? turn(gun_rel*rand(15)) : turn(0)
77
+ else
78
+ fire(0.5)
79
+ end
80
+ end
81
+ turn_gun(-15) if @gun_head.nil?
82
+ accelerate(1)
83
+ @enemy = ((@enemy <= 0) ? (@ememy; @gun_head = nil) : (@enemy-1))
84
+ end
85
+ end