SHOW:
|
|
- or go back to the newest paste.
1 | local component = require 'component' | |
2 | local modem = component.modem | |
3 | ||
4 | - | local QUEEN = {} |
4 | + | local PAWN = {} |
5 | ||
6 | ||
7 | local FIRMWARE = { | |
8 | [[ | |
9 | - | r= component.proxy(component.list('radar')()) |
9 | + | |
10 | - | n= component.proxy(component.list('navigation')()) |
10 | + | |
11 | Channel = 2413 | |
12 | ResponseChannel = 2403 | |
13 | - | Channel = 2412 |
13 | + | |
14 | - | ResponseChannel = 2402 |
14 | + | |
15 | m.open(Channel) | |
16 | - | m.setStrength(math.huge) |
16 | + | |
17 | - | drone_inv = "inv_q" |
17 | + | |
18 | - | isDroneQueen = true |
18 | + | drone_inv = "inv_s" |
19 | isDroneQueen = false | |
20 | - | broadcastGPS = false |
20 | + | |
21 | ||
22 | - | gpsRequestChannel = 20 |
22 | + | gpsSats={} |
23 | - | m.open(gpsRequestChannel) |
23 | + | cmdTRGPos={} |
24 | ]] | |
25 | , | |
26 | [[ | |
27 | function sleep(timeout) | |
28 | checkArg(1, timeout, 'number', 'nil') | |
29 | local deadline = computer.uptime() + (timeout or 0) | |
30 | repeat | |
31 | computer.pullSignal(deadline - computer.uptime()) | |
32 | until computer.uptime() >= deadline | |
33 | end | |
34 | ]] | |
35 | , | |
36 | [[ | |
37 | - | function sub_vec(A,B) return {A[1]-B[1],A[2]-B[2],A[3]-B[3]} end |
37 | + | floor, sqrt, abs = math.floor, math.sqrt, math.abs |
38 | - | function math.trunc(v) |
38 | + | |
39 | - | local t = math.modf(v) |
39 | + | function round(v, m) return {x = floor((v.x+(m*0.5))/m)*m, y = floor((v.y+(m*0.5))/m)*m, z = floor((v.z+(m*0.5))/m)*m} end |
40 | - | return t |
40 | + | function cross(v, b) return {x = v.y*b.z-v.z*b.y, y = v.z*b.x-v.x*b.z, z = v.x*b.y-v.y*b.x} end |
41 | function len(v) return sqrt(v.x^2+v.y^2+v.z^2) end | |
42 | function dot(v, b) return v.x*b.x+v.y*b.y+v.z*b.z end | |
43 | function add(v, b) return {x=v.x+b.x, y=v.y+b.y, z=v.z+b.z} end | |
44 | - | return {math.trunc(A[1]),math.trunc(A[2]),math.trunc(A[3])} |
44 | + | function sub(v, b) return {x=v.x-b.x, y=v.y-b.y, z=v.z-b.z} end |
45 | function mul(v, m) return {x=v.x*m, y=v.y*m, z=v.z*m} end | |
46 | function norm(v) return mul(v, 1/len(v)) end | |
47 | ||
48 | function arr_length(a) | |
49 | local c = 0 | |
50 | for k,_ in pairs(a) do c=c+1 end | |
51 | - | function getPlayerCoord(e_name) |
51 | + | return c |
52 | - | checkArg(1,e_name,'string','nil') |
52 | + | |
53 | - | for k,v in ipairs(r.getPlayers()) do |
53 | + | function trunc(v) local t = math.modf(v) return t end |
54 | - | if v.name == e_name then |
54 | + | |
55 | - | return {v.x,v.y,v.z},v.distance |
55 | + | |
56 | - | end |
56 | + | return {x=trunc(A.x),y=trunc(A.y),z=trunc(A.z)} |
57 | end | |
58 | return nil | |
59 | end | |
60 | ]] | |
61 | , | |
62 | ||
63 | - | function move(x,y,z) |
63 | + | |
64 | - | checkArg(1,x,'number','nil') |
64 | + | function add2GPSTable(r_addr,x,y,z,dist) |
65 | - | checkArg(1,y,'number','nil') |
65 | + | if arr_length(gpsSats) < 7 then gpsSats[r_addr] = {x=x,y=y,z=z,d=dist} end |
66 | - | checkArg(1,z,'number','nil') |
66 | + | |
67 | - | if x and y and z then |
67 | + | |
68 | - | d.setLightColor(0x00FFAF) |
68 | + | |
69 | - | d.move(x,y,z) |
69 | + | |
70 | function replyInv(add) | |
71 | m.send(add,ResponseChannel,"stats",isFree,isDroneQueen)--Queens send "true" | |
72 | end | |
73 | ]] | |
74 | , | |
75 | [[ | |
76 | acts = { | |
77 | [drone_inv] = function(r_add) d.setLightColor(0x00FFBB) replyInv(r_add) end, | |
78 | ["commit"] = function() d.setLightColor(0x5E00FF) isFree = false end, | |
79 | ["uncommit"] = function() isFree = true end, | |
80 | ||
81 | ["gps"] = function(r_addr,x,y,z,dist) add2GPSTable(r_addr,x,y,z,dist) end, | |
82 | - | function QgpsBroadcast(c) |
82 | + | ["trg"] = function(_,x,y,z,dist) cmdTRGPos={c={x,y,z},d=dist} end, |
83 | - | if broadcastGPS and c[1] then |
83 | + | ["formup"] = function(_,x,y,z,_,trgC) d.setStatusText(gpsMoveToTarget({x=x,y=y,z=z},trgC)) end, |
84 | - | --m.broadcast(gpsChannel,"gps",-c[1],-(c[2]+1),-c[3]) |
84 | + | ["orbit"] = function(_,x,y,z,_,trgC) d.setStatusText("orbiting") d.setStatusText(gpsOrbitTRG({x=x,y=y,z=z},trgC)) end, |
85 | - | m.broadcast(gpsChannel,"gps",c[1],c[2],c[3]) |
85 | + | |
86 | - | d.setLightColor(0x00FFCC) |
86 | + | |
87 | ]] | |
88 | , | |
89 | [[ | |
90 | actsWhileMoving = { | |
91 | [drone_inv] = function(r_add) replyInv(r_add) end, | |
92 | - | function gpsReply(addr) |
92 | + | |
93 | - | if gpsSatPos[1] then |
93 | + | |
94 | - | m.send(addr,gpsChannel,"gps",gpsSatPos[1],gpsSatPos[2],gpsSatPos[3]) |
94 | + | ["gps"] = function(r_addr,x,y,z,dist) add2GPSTable(r_addr,x,y,z,dist) end, |
95 | --["trg"] = function(_,x,y,z,dist) cmdTRGPos={c={x=x,y=y,z=z},d=dist} d.setStatusText("trg2:"..tostring(cmdTRGPos.c.x)) end, | |
96 | ["HUSH"] = function() d.setLightColor(0xFF0000) sleep(1) computer.shutdown() end | |
97 | } | |
98 | ]] | |
99 | , | |
100 | [[ | |
101 | - | ["go"] = function(_,tag) d.setLightColor(0x00FF00) d.setStatusText(navMoveToPlayer(tag)) end, |
101 | + | function trilaterate(A, B, C) |
102 | - | ["bzz"] = function(_,tag) d.setLightColor(0x0000FF) d.setStatusText(navSwarmPlayer(tag)) end, |
102 | + | local a2b = {x=B.x-A.x, y=B.y-A.y, z=B.z-A.z} |
103 | - | ["move"] = function(_,_,x,y,z) move(x,y,z) end, |
103 | + | local a2c = {x=C.x-A.x, y=C.y-A.y, z=C.z-A.z} |
104 | - | [drone_inv] = function(r_add) d.setLightColor(0xFF00BB) replyInv(r_add) end, |
104 | + | if abs(dot(norm(a2b), norm(a2c))) > 0.999 then return nil end |
105 | local d, ex = len(a2b), norm(a2b) | |
106 | local i = dot(ex, a2c) | |
107 | - | ["formup"] = function(_,tag,x,y,z) d.setStatusText(navMoveToPlayerWOffset(tag,x,y,z)) end, |
107 | + | local exMi = mul(ex, i) |
108 | - | ["setgpspos"] = function(_,_,x,y,z) gpsSatPos = {x,y,z} end, |
108 | + | local ey = norm(sub(a2c, mul(ex, i))) |
109 | - | ["startgps"] = function() broadcastGPS = true end, |
109 | + | local j, ez = dot(ey, a2c), cross(ex, ey) |
110 | - | ["stopgps"] = function() broadcastGPS = false end, |
110 | + | local r1, r2, r3 = A.d, B.d, C.d |
111 | - | ["reqgps"] = function(r_add) gpsReply(r_add) end, |
111 | + | local x = (r1^2 - r2^2 + d^2) / (2*d) |
112 | local y = (r1^2 - r3^2 - x^2 + (x-i)^2 + j^2) / (2*j) | |
113 | local result = add(A, add(mul(ex, x), mul(ey, y))) | |
114 | local zSquared = r1^2 - x^2 - y^2 | |
115 | if zSquared > 0 then | |
116 | local z = sqrt( zSquared ) | |
117 | local result1 = add(result, mul(ez, z)) | |
118 | local result2 = sub(result, mul(ez, z)) | |
119 | local rnd1, rnd2 = result1,result2 | |
120 | if rnd1.x ~= rnd2.x or rnd1.y ~= rnd2.y or rnd1.z ~= rnd2.z then | |
121 | - | ["setgpspos"] = function(_,_,x,y,z) gpsSatPos = {x,y,z} end, |
121 | + | return rnd1, rnd2 |
122 | - | ["startgps"] = function() broadcastGPS = true end, |
122 | + | |
123 | - | ["stopgps"] = function() broadcastGPS = false end, |
123 | + | return rnd1 |
124 | end | |
125 | end | |
126 | return result | |
127 | end | |
128 | ]] | |
129 | - | function navMoveToPlayer(e_name) |
129 | + | |
130 | - | checkArg(1,e_name,"string","nil") |
130 | + | |
131 | - | local trgPos = {n.getPosition()},msg,r_add |
131 | + | function narrow(p1, p2, fix) |
132 | - | |
132 | + | local d1 = abs(len(sub(p1, fix))-fix.d) |
133 | - | if not trgPos[1] then d.setLightColor(0xFF0000) return "Out Of\nRange" end |
133 | + | local d2 = abs(len(sub(p2, fix))-fix.d) |
134 | - | |
134 | + | if abs(d1-d2) < 0.01 then |
135 | - | trgPos = vec_trunc(trgPos) |
135 | + | return p1, p2 |
136 | - | local mv = {0,0,0} |
136 | + | elseif d1 < d2 then |
137 | - | local mapRange = n.getRange() |
137 | + | return p1,nil |
138 | - | |
138 | + | else |
139 | return p2,nil | |
140 | - | local v = getPlayerCoord(e_name) |
140 | + | |
141 | - | if not v then |
141 | + | |
142 | - | d.setLightColor(0xFF0000) |
142 | + | |
143 | - | d.setStatusText("Out Of\nRange") |
143 | + | |
144 | [[ | |
145 | - | v = vec_trunc(v) |
145 | + | function getGPSlocation() |
146 | - | local npos = {n.getPosition()} |
146 | + | local fixes = {} |
147 | - | if npos[1] then |
147 | + | local pos1, pos2 = nil, nil |
148 | - | npos = vec_trunc(npos) |
148 | + | for addr,fix in pairs(gpsSats) do |
149 | - | local Qpn = {npos[1] + v[1], npos[2] + v[2] + 2, npos[3] + v[3]} |
149 | + | if fix.d == 0 then |
150 | - | mv = sub_vec(Qpn,trgPos) |
150 | + | pos1, pos2 = {x=fix.x, y=fix.y, z=fix.z}, nil |
151 | - | if math.abs(Qpn[1]) < mapRange-5 and math.abs(Qpn[3]) < mapRange-5 then |
151 | + | else |
152 | - | d.move(mv[1],mv[2],mv[3]) |
152 | + | table.insert(fixes, fix) |
153 | - | trgPos = Qpn |
153 | + | |
154 | end | |
155 | - | else |
155 | + | if #fixes >= 3 then |
156 | - | d.setLightColor(0xFF0000) |
156 | + | if not pos1 then |
157 | - | d.setStatusText("Out Of\nRange") |
157 | + | pos1, pos2 = trilaterate(fixes[1], fixes[2], fixes[3]) |
158 | - | d.move(-mv[1],-mv[2],-mv[3]) |
158 | + | |
159 | if pos1 and pos2 then | |
160 | for f=4,#fixes do | |
161 | - | _,_,r_add,_,_,msg = computer.pullSignal(0.5) |
161 | + | pos1, pos2 = narrow(pos1, pos2, fixes[f]) |
162 | if pos1 and not pos2 then break end | |
163 | - | actsWhileMoving[msg](r_add) |
163 | + | |
164 | end | |
165 | - | until msg == "stop" |
165 | + | end |
166 | ||
167 | if pos1 and pos2 then | |
168 | d.setStatusText("ps12") | |
169 | return nil | |
170 | elseif pos1 then | |
171 | - | function navSwarmPlayer(e_name) |
171 | + | local c = round(pos1,1) |
172 | - | checkArg(1,e_name,"string","nil") |
172 | + | return {x=c.x,y=c.y,z=c.z} |
173 | - | local trgPos = {n.getPosition()},msg,r_add |
173 | + | else |
174 | - | |
174 | + | d.setStatusText("else") |
175 | - | if not trgPos[1] then d.setLightColor(0xFF0000) return "Out Of\nRange" end |
175 | + | return nil |
176 | - | |
176 | + | |
177 | - | trgPos = vec_trunc(trgPos) |
177 | + | |
178 | - | local mv = {0,0,0} |
178 | + | |
179 | - | local mapRange = n.getRange() |
179 | + | |
180 | - | |
180 | + | |
181 | refreshGPSInterval = 0 | |
182 | - | local v = getPlayerCoord(e_name) |
182 | + | function refreshGPSTable() |
183 | - | if not v then |
183 | + | if refreshGPSInterval >= 17 then gpsSats={} refreshGPSInterval = 0 end |
184 | - | d.setLightColor(0xFF0000) |
184 | + | refreshGPSInterval = refreshGPSInterval + 1 |
185 | - | d.setStatusText("Out Of\nRange") |
185 | + | |
186 | ||
187 | - | v = vec_trunc(v) |
187 | + | function getTRGPos() |
188 | - | local npos = {n.getPosition()} |
188 | + | return cmdTRGPos |
189 | - | if npos[1] then |
189 | + | |
190 | - | npos = vec_trunc(npos) |
190 | + | |
191 | - | local Qpn = {npos[1] + v[1] +math.random(-3,3), npos[2] + v[2] +math.random(-3,3), npos[3] + v[3]+math.random(-3,3)} |
191 | + | |
192 | - | mv = sub_vec(Qpn,trgPos) |
192 | + | |
193 | - | if math.abs(Qpn[1]) < mapRange-5 and math.abs(Qpn[3]) < mapRange-5 then |
193 | + | function gpsMoveToTarget(offset,trgChannel) |
194 | - | d.move(mv[1],mv[2],mv[3]) |
194 | + | d.setLightColor(0xFFFFFF) |
195 | - | trgPos = Qpn |
195 | + | gpsSats={} |
196 | m.open(gpsChannel) | |
197 | - | else |
197 | + | local ctrlTRGPos = nil |
198 | - | d.setLightColor(0xFF0000) |
198 | + | |
199 | - | d.setStatusText("Out Of\nRange") |
199 | + | if arr_length(gpsSats)>=3 then |
200 | - | d.move(-mv[1],-mv[2],-mv[3]) |
200 | + | ctrlTRGPos = getGPSlocation() |
201 | end | |
202 | ||
203 | - | _,_,r_add,_,_,msg = computer.pullSignal(0.5) |
203 | + | if ctrlTRGPos then ctrlTRGPos = vec_trunc(ctrlTRGPos) |
204 | else d.setLightColor(0xFF0000) d.setStatusText("No GPS:") end | |
205 | - | actsWhileMoving[msg](r_add) |
205 | + | |
206 | _,_,r_addr,_,dist,msg,x,y,z,trgCh = computer.pullSignal(0.5) | |
207 | - | until msg == "stop" |
207 | + | |
208 | if actsWhileMoving[msg] then | |
209 | actsWhileMoving[msg](r_addr,x,y,z,dist) | |
210 | end | |
211 | refreshGPSTable() | |
212 | until msg == "stop" or ctrlTRGPos | |
213 | - | gpsSatPos={} |
213 | + | |
214 | - | function navMoveToPlayerWOffset(e_name,xo,yo,zo) |
214 | + | if ctrlTRGPos then |
215 | - | checkArg(1,e_name,"string","nil") |
215 | + | m.close(gpsChannel) |
216 | - | local trgPos = {n.getPosition()} |
216 | + | d.setLightColor(0xFFFFFF) |
217 | - | if not trgPos[1] then d.setLightColor(0xFF0000) return "Out Of\nRange" end |
217 | + | m.open(trgChannel) |
218 | - | trgPos = vec_trunc(trgPos) |
218 | + | local mv = {x=0,y=0,z=0},msg,r_add,dist,x,y,z |
219 | - | local mv = {0,0,0},msg,r_add |
219 | + | local trgUpdate = {} |
220 | - | local mapRange = n.getRange() |
220 | + | repeat |
221 | _,_,r_addr,_,dist,msg,x,y,z,trgCh = computer.pullSignal(0.5) | |
222 | - | local v = getPlayerCoord(e_name) |
222 | + | |
223 | - | if not v then |
223 | + | if msg == "trg" then |
224 | - | d.setLightColor(0xFF0000) |
224 | + | trgUpdate = {c={x=x,y=y,z=z},d=dist} |
225 | - | d.setStatusText("Out Of\nRange") |
225 | + | |
226 | local trgPos = trgUpdate | |
227 | - | v = vec_trunc(v) |
227 | + | |
228 | - | --QgpsBroadcast(v) |
228 | + | if trgPos.d and trgPos.d < 50 then |
229 | trgPos.c = vec_trunc(trgPos.c) | |
230 | - | --gpsSatPos = {-v[1],-(v[2]+1),-v[3]} --offset origin to tablet position (above player's head) |
230 | + | local trgPosOffset = add(trgPos.c, offset) |
231 | - | --gpsSatPos = {-v[1],-v[2],-v[3]} |
231 | + | mv = sub(trgPosOffset,ctrlTRGPos) |
232 | d.move(mv.x,mv.y,mv.z) | |
233 | - | local npos = {n.getPosition()} |
233 | + | ctrlTRGPos = trgPosOffset |
234 | - | if npos[1] then |
234 | + | d.setLightColor(0x00FF00) |
235 | - | npos = vec_trunc(npos) |
235 | + | d.setStatusText(d.name()) |
236 | - | local Qpn = {npos[1] + v[1] + xo, npos[2] + v[2] + yo, npos[3] + v[3] + zo} |
236 | + | else |
237 | - | mv = sub_vec(Qpn,trgPos) |
237 | + | d.setLightColor(0xFF0000) |
238 | - | if math.abs(Qpn[1]) < mapRange-5 and math.abs(Qpn[3]) < mapRange-5 then |
238 | + | d.setStatusText("Out Of\nRange") |
239 | - | d.move(mv[1],mv[2],mv[3]) |
239 | + | d.move(-mv.x,-mv.y,-mv.z) |
240 | - | trgPos = Qpn |
240 | + | |
241 | if actsWhileMoving[msg] then | |
242 | - | else |
242 | + | actsWhileMoving[msg](r_addr,x,y,z,dist) |
243 | - | d.setLightColor(0xFF0000) |
243 | + | |
244 | - | d.setStatusText("Out Of\nRange") |
244 | + | until msg == "stop" |
245 | - | d.move(-mv[1],-mv[2],-mv[3]) |
245 | + | |
246 | m.close(trgChannel) | |
247 | return d.name() | |
248 | - | _,_,r_add,_,_,msg = computer.pullSignal(0.5) |
248 | + | |
249 | ]] | |
250 | - | actsWhileMoving[msg](r_add) |
250 | + | |
251 | [[ | |
252 | - | until msg == "stop" |
252 | + | function rotatePoint(rad,point) |
253 | local s = math.sin(rad); | |
254 | local c = math.cos(rad); | |
255 | ||
256 | // rotate point | |
257 | float xnew = point.x * c - point.y * s; | |
258 | float ynew = point.x * s + point.y * c; | |
259 | - | local cmd,tag,x,y,z |
259 | + | |
260 | - | d.setLightColor(0xFFAF00) |
260 | + | return point |
261 | end | |
262 | - | _,_,r_add,_,_,cmd,tag,x,y,z = computer.pullSignal(0.5) |
262 | + | |
263 | - | if d.name():match("^Q%d+$") then |
263 | + | |
264 | - | if acts[cmd] then |
264 | + | |
265 | - | acts[cmd](r_add,tag,x,y,z) |
265 | + | function gpsOrbitTRG(offset,trgChannel) |
266 | d.setLightColor(0xFFFFFF) | |
267 | - | QgpsBroadcast(gpsSatPos) |
267 | + | gpsSats={} |
268 | m.open(gpsChannel) | |
269 | local ctrlTRGPos = nil | |
270 | repeat | |
271 | if arr_length(gpsSats)>=3 then | |
272 | ctrlTRGPos = getGPSlocation() | |
273 | end | |
274 | ||
275 | - | function QUEEN.broadcastFirmWare(port) |
275 | + | if ctrlTRGPos then ctrlTRGPos = vec_trunc(ctrlTRGPos) |
276 | else d.setLightColor(0xFF0000) d.setStatusText("No GPS:") end | |
277 | ||
278 | _,_,r_addr,_,dist,msg,x,y,z,trgCh = computer.pullSignal(0.5) | |
279 | ||
280 | if actsWhileMoving[msg] then | |
281 | - | return QUEEN |
281 | + | actsWhileMoving[msg](r_addr,x,y,z,dist) |
282 | end | |
283 | refreshGPSTable() | |
284 | until msg == "stop" or ctrlTRGPos | |
285 | ||
286 | if ctrlTRGPos then | |
287 | m.close(gpsChannel) | |
288 | d.setLightColor(0xFFFFFF) | |
289 | m.open(trgChannel) | |
290 | local mv = {x=0,y=0,z=0},msg,r_add,dist,x,y,z | |
291 | local trgUpdate = {} | |
292 | local currentAngle = 0 -- in radians | |
293 | local rotationInterval = 0.785 -- PI/4 | |
294 | repeat | |
295 | _,_,r_addr,_,dist,msg,x,y,z,trgCh = computer.pullSignal(0.5) | |
296 | ||
297 | if msg == "trg" then | |
298 | trgUpdate = {c={x=x,y=y,z=z},d=dist} | |
299 | end | |
300 | local trgPos = trgUpdate | |
301 | ||
302 | if trgPos.d and trgPos.d < 50 then | |
303 | trgPos.c = vec_trunc(trgPos.c) | |
304 | ||
305 | if currentAngle >= 6.3832 then currentAngle = 0 end | |
306 | local rotatedOffset = rotatePoint(currentAngle,offset) | |
307 | currentAngle = currentAngle + rotationInterval | |
308 | ||
309 | local trgPosOffset = add(trgPos.c, rotatedOffset) | |
310 | ||
311 | mv = sub(trgPosOffset,ctrlTRGPos) | |
312 | d.move(mv.x,mv.y,mv.z) | |
313 | ctrlTRGPos = trgPosOffset | |
314 | d.setLightColor(0x00FF00) | |
315 | d.setStatusText(d.name()) | |
316 | else | |
317 | d.setLightColor(0xFF0000) | |
318 | d.setStatusText("Out Of\nRange") | |
319 | d.move(-mv.x,-mv.y,-mv.z) | |
320 | end | |
321 | if actsWhileMoving[msg] then | |
322 | actsWhileMoving[msg](r_addr,x,y,z,dist) | |
323 | end | |
324 | until msg == "stop" | |
325 | end | |
326 | m.close(trgChannel) | |
327 | return d.name() | |
328 | end | |
329 | ]] | |
330 | , | |
331 | [[ | |
332 | d.setAcceleration(100) | |
333 | d.setLightColor(0x007B62) | |
334 | while true do | |
335 | _,_,r_addr,_,dist,msg,x,y,z,trgCh = computer.pullSignal(0.5) | |
336 | if d.name():match("^S%d+$") then | |
337 | if msg =="orbit"then d.setStatusText("orbitter") end | |
338 | if acts[msg] then | |
339 | acts[msg](r_addr,x,y,z,dist,trgCh) | |
340 | end | |
341 | end | |
342 | --d.setLightColor(0xFFAF00) | |
343 | --d.setLightColor(0x77FF77) | |
344 | end | |
345 | ]] | |
346 | } | |
347 | ||
348 | PAWN.master = "" --control tablet modem address, set before broadcasting firmware | |
349 | ||
350 | function PAWN.broadcastFirmWare(port) | |
351 | modem.broadcast(port, | |
352 | [[ | |
353 | master = ]]..PAWN.master..[[ | |
354 | ]] | |
355 | ) | |
356 | for _,part in ipairs(FIRMWARE) do | |
357 | modem.broadcast(port,part) | |
358 | end | |
359 | end | |
360 | ||
361 | return PAWN | |
362 |