corrade-lsl-templates – Diff between revs 5 and 29
?pathlinks?
Rev 5 | Rev 29 | |||
---|---|---|---|---|
1 | /////////////////////////////////////////////////////////////////////////// |
1 | /////////////////////////////////////////////////////////////////////////// |
|
2 | // Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 // |
2 | // Copyright (C) Wizardry and Steamworks 2014 - License: CC BY 2.0 // |
|
3 | /////////////////////////////////////////////////////////////////////////// |
3 | /////////////////////////////////////////////////////////////////////////// |
|
4 | // |
4 | // |
|
5 | // This is an automatic teleporter, and patrol script for the Corrade |
5 | // This is an automatic teleporter, and patrol script for the Corrade |
|
6 | // Second Life / OpenSim bot. You can find more details about the bot |
6 | // Second Life / OpenSim bot. You can find more details about the bot |
|
7 | // by following the URL: http://was.fm/secondlife/scripted_agents/corrade |
7 | // by following the URL: http://was.fm/secondlife/scripted_agents/corrade |
|
8 | // |
8 | // |
|
9 | // The purpose of this script is to demonstrate patroling with Corrade and |
9 | // The purpose of this script is to demonstrate patroling with Corrade and |
|
10 | // you are free to use, change, and commercialize it under the GNU/GPLv3 |
10 | // you are free to use, change, and commercialize it under the CC BY 2.0 |
|
11 | // license which can be found at: http://www.gnu.org/licenses/gpl.html |
11 | // license which can be found at: https://creativecommons.org/licenses/by/2.0 |
|
12 | // |
12 | // |
|
13 | /////////////////////////////////////////////////////////////////////////// |
13 | /////////////////////////////////////////////////////////////////////////// |
|
14 | |
14 | |
|
15 | /////////////////////////////////////////////////////////////////////////// |
15 | /////////////////////////////////////////////////////////////////////////// |
|
16 | // Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 // |
16 | // Copyright (C) 2014 Wizardry and Steamworks - License: CC BY 2.0 // |
|
17 | /////////////////////////////////////////////////////////////////////////// |
17 | /////////////////////////////////////////////////////////////////////////// |
|
18 | string wasKeyValueGet(string k, string data) { |
18 | string wasKeyValueGet(string k, string data) { |
|
19 | if(llStringLength(data) == 0) return ""; |
19 | if(llStringLength(data) == 0) return ""; |
|
20 | if(llStringLength(k) == 0) return ""; |
20 | if(llStringLength(k) == 0) return ""; |
|
21 | list a = llParseString2List(data, ["&", "="], []); |
21 | list a = llParseString2List(data, ["&", "="], []); |
|
22 | integer i = llListFindList(a, [ k ]); |
22 | integer i = llListFindList(a, [ k ]); |
|
23 | if(i != -1) return llList2String(a, i+1); |
23 | if(i != -1) return llList2String(a, i+1); |
|
24 | return ""; |
24 | return ""; |
|
25 | } |
25 | } |
|
26 | |
26 | |
|
27 | /////////////////////////////////////////////////////////////////////////// |
27 | /////////////////////////////////////////////////////////////////////////// |
|
28 | // Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3 // |
28 | // Copyright (C) 2013 Wizardry and Steamworks - License: CC BY 2.0 // |
|
29 | /////////////////////////////////////////////////////////////////////////// |
29 | /////////////////////////////////////////////////////////////////////////// |
|
30 | string wasKeyValueEncode(list data) { |
30 | string wasKeyValueEncode(list data) { |
|
31 | list k = llList2ListStrided(data, 0, -1, 2); |
31 | list k = llList2ListStrided(data, 0, -1, 2); |
|
32 | list v = llList2ListStrided(llDeleteSubList(data, 0, 0), 0, -1, 2); |
32 | list v = llList2ListStrided(llDeleteSubList(data, 0, 0), 0, -1, 2); |
|
33 | data = []; |
33 | data = []; |
|
34 | do { |
34 | do { |
|
35 | data += llList2String(k, 0) + "=" + llList2String(v, 0); |
35 | data += llList2String(k, 0) + "=" + llList2String(v, 0); |
|
36 | k = llDeleteSubList(k, 0, 0); |
36 | k = llDeleteSubList(k, 0, 0); |
|
37 | v = llDeleteSubList(v, 0, 0); |
37 | v = llDeleteSubList(v, 0, 0); |
|
38 | } while(llGetListLength(k) != 0); |
38 | } while(llGetListLength(k) != 0); |
|
39 | return llDumpList2String(data, "&"); |
39 | return llDumpList2String(data, "&"); |
|
40 | } |
40 | } |
|
41 | |
41 | |
|
42 | /////////////////////////////////////////////////////////////////////////// |
42 | /////////////////////////////////////////////////////////////////////////// |
|
43 | // Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3 // |
43 | // Copyright (C) 2013 Wizardry and Steamworks - License: CC BY 2.0 // |
|
44 | /////////////////////////////////////////////////////////////////////////// |
44 | /////////////////////////////////////////////////////////////////////////// |
|
45 | list wasDualQuicksort(list a, list b) { |
45 | list wasDualQuicksort(list a, list b) { |
|
46 | if(llGetListLength(a) <= 1) return a+b; |
46 | if(llGetListLength(a) <= 1) return a+b; |
|
47 | |
47 | |
|
48 | float pivot_a = llList2Float(a, 0); |
48 | float pivot_a = llList2Float(a, 0); |
|
49 | a = llDeleteSubList(a, 0, 0); |
49 | a = llDeleteSubList(a, 0, 0); |
|
50 | vector pivot_b = llList2Vector(b, 0); |
50 | vector pivot_b = llList2Vector(b, 0); |
|
51 | b = llDeleteSubList(b, 0, 0); |
51 | b = llDeleteSubList(b, 0, 0); |
|
52 | |
52 | |
|
53 | list less = []; |
53 | list less = []; |
|
54 | list less_b = []; |
54 | list less_b = []; |
|
55 | list more = []; |
55 | list more = []; |
|
56 | list more_b = []; |
56 | list more_b = []; |
|
57 | |
57 | |
|
58 | do { |
58 | do { |
|
59 | if(llList2Float(a, 0) > pivot_a) { |
59 | if(llList2Float(a, 0) > pivot_a) { |
|
60 | less += llList2List(a, 0, 0); |
60 | less += llList2List(a, 0, 0); |
|
61 | less_b += llList2List(b, 0, 0); |
61 | less_b += llList2List(b, 0, 0); |
|
62 | jump continue; |
62 | jump continue; |
|
63 | } |
63 | } |
|
64 | more += llList2List(a, 0, 0); |
64 | more += llList2List(a, 0, 0); |
|
65 | more_b += llList2List(b, 0, 0); |
65 | more_b += llList2List(b, 0, 0); |
|
66 | @continue; |
66 | @continue; |
|
67 | a = llDeleteSubList(a, 0, 0); |
67 | a = llDeleteSubList(a, 0, 0); |
|
68 | b = llDeleteSubList(b, 0, 0); |
68 | b = llDeleteSubList(b, 0, 0); |
|
69 | } while(llGetListLength(a)); |
69 | } while(llGetListLength(a)); |
|
70 | return wasDualQuicksort(less, less_b) + [ pivot_a ] + [ pivot_b ] + wasDualQuicksort(more, more_b); |
70 | return wasDualQuicksort(less, less_b) + [ pivot_a ] + [ pivot_b ] + wasDualQuicksort(more, more_b); |
|
71 | } |
71 | } |
|
72 | |
72 | |
|
73 | /////////////////////////////////////////////////////////////////////////// |
73 | /////////////////////////////////////////////////////////////////////////// |
|
74 | // Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 // |
74 | // Copyright (C) 2014 Wizardry and Steamworks - License: CC BY 2.0 // |
|
75 | /////////////////////////////////////////////////////////////////////////// |
75 | /////////////////////////////////////////////////////////////////////////// |
|
76 | // determines whether the segment AB intersects the segment CD |
76 | // determines whether the segment AB intersects the segment CD |
|
77 | integer wasSegmentIntersect(vector A, vector B, vector C, vector D) { |
77 | integer wasSegmentIntersect(vector A, vector B, vector C, vector D) { |
|
78 | vector s1 = <B.x - A.x, B.y - A.y, B.z - A.z>; |
78 | vector s1 = <B.x - A.x, B.y - A.y, B.z - A.z>; |
|
79 | vector s2 = <D.x - C.x, D.y - C.y, D.y - C.z>; |
79 | vector s2 = <D.x - C.x, D.y - C.y, D.y - C.z>; |
|
80 | |
80 | |
|
81 | float d = (s1.x * s2.y -s2.x * s1.y); |
81 | float d = (s1.x * s2.y -s2.x * s1.y); |
|
82 | |
82 | |
|
83 | if(d == 0) return FALSE; |
83 | if(d == 0) return FALSE; |
|
84 | |
84 | |
|
85 | float s = (s1.x * (A.y - C.y) - s1.y * (A.x - C.x)) / d; |
85 | float s = (s1.x * (A.y - C.y) - s1.y * (A.x - C.x)) / d; |
|
86 | float t = (s2.x * (A.y - C.y) - s2.y * (A.x - C.x)) / d; |
86 | float t = (s2.x * (A.y - C.y) - s2.y * (A.x - C.x)) / d; |
|
87 | |
87 | |
|
88 | // intersection at <A.x + (t * s1.x), A.y + (t * s1.y), A.z + (t * s1.z)>; |
88 | // intersection at <A.x + (t * s1.x), A.y + (t * s1.y), A.z + (t * s1.z)>; |
|
89 | return (integer)(s >= 0 && s <= 1 && t >= 0 && t <= 1 && |
89 | return (integer)(s >= 0 && s <= 1 && t >= 0 && t <= 1 && |
|
90 | A.z + t*(B.z - A.z) == C.z + s*(D.z - C.z)); |
90 | A.z + t*(B.z - A.z) == C.z + s*(D.z - C.z)); |
|
91 | } |
91 | } |
|
92 | |
92 | |
|
93 | /////////////////////////////////////////////////////////////////////////// |
93 | /////////////////////////////////////////////////////////////////////////// |
|
94 | // Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3 // |
94 | // Copyright (C) 2013 Wizardry and Steamworks - License: CC BY 2.0 // |
|
95 | // www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html // |
95 | // www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html // |
|
96 | /////////////////////////////////////////////////////////////////////////// |
96 | /////////////////////////////////////////////////////////////////////////// |
|
97 | integer wasPointInPolygon(vector p, list polygon) { |
97 | integer wasPointInPolygon(vector p, list polygon) { |
|
98 | integer inside = FALSE; |
98 | integer inside = FALSE; |
|
99 | integer i = 0; |
99 | integer i = 0; |
|
100 | integer nvert = llGetListLength(polygon); |
100 | integer nvert = llGetListLength(polygon); |
|
101 | integer j = nvert-1; |
101 | integer j = nvert-1; |
|
102 | do { |
102 | do { |
|
103 | vector pi = llList2Vector(polygon, i); |
103 | vector pi = llList2Vector(polygon, i); |
|
104 | vector pj = llList2Vector(polygon, j); |
104 | vector pj = llList2Vector(polygon, j); |
|
105 | if ((pi.y > p.y) != (pj.y > p.y)) |
105 | if ((pi.y > p.y) != (pj.y > p.y)) |
|
106 | if(p.x < (pj.x - pi.x) * (p.y - pi.y) / (pj.y - pi.y) + pi.x) |
106 | if(p.x < (pj.x - pi.x) * (p.y - pi.y) / (pj.y - pi.y) + pi.x) |
|
107 | inside = !inside; |
107 | inside = !inside; |
|
108 | j = i++; |
108 | j = i++; |
|
109 | } while(i<nvert); |
109 | } while(i<nvert); |
|
110 | return inside; |
110 | return inside; |
|
111 | } |
111 | } |
|
112 | |
112 | |
|
113 | /////////////////////////////////////////////////////////////////////////// |
113 | /////////////////////////////////////////////////////////////////////////// |
|
114 | // Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3 // |
114 | // Copyright (C) 2013 Wizardry and Steamworks - License: CC BY 2.0 // |
|
115 | // www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html // |
115 | // www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html // |
|
116 | /////////////////////////////////////////////////////////////////////////// |
116 | /////////////////////////////////////////////////////////////////////////// |
|
117 | list wasPointToPolygon(list polygon, vector point) { |
117 | list wasPointToPolygon(list polygon, vector point) { |
|
118 | integer i = llGetListLength(polygon)-1; |
118 | integer i = llGetListLength(polygon)-1; |
|
119 | list l = []; |
119 | list l = []; |
|
120 | do { |
120 | do { |
|
121 | l = llListInsertList(l, (list)llVecDist(point, llList2Vector(polygon, i)), 0); |
121 | l = llListInsertList(l, (list)llVecDist(point, llList2Vector(polygon, i)), 0); |
|
122 | } while(--i>-1); |
122 | } while(--i>-1); |
|
123 | l = wasDualQuicksort(l, polygon); |
123 | l = wasDualQuicksort(l, polygon); |
|
124 | return [llList2Float(l, 0), llList2Vector(l, 1)]; |
124 | return [llList2Float(l, 0), llList2Vector(l, 1)]; |
|
125 | |
125 | |
|
126 | } |
126 | } |
|
127 | |
127 | |
|
128 | /////////////////////////////////////////////////////////////////////////// |
128 | /////////////////////////////////////////////////////////////////////////// |
|
129 | // Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3 // |
129 | // Copyright (C) 2013 Wizardry and Steamworks - License: CC BY 2.0 // |
|
130 | // www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html // |
130 | // www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html // |
|
131 | /////////////////////////////////////////////////////////////////////////// |
131 | /////////////////////////////////////////////////////////////////////////// |
|
132 | vector wasPolygonCentroid(list polygon, vector start, float tollerance, integer power) { |
132 | vector wasPolygonCentroid(list polygon, vector start, float tollerance, integer power) { |
|
133 | // calculate the distance to the point farthest away from the start. |
133 | // calculate the distance to the point farthest away from the start. |
|
134 | list wpf = wasPointToPolygon(polygon, start); |
134 | list wpf = wasPointToPolygon(polygon, start); |
|
135 | float dist = llList2Float(wpf, 0); |
135 | float dist = llList2Float(wpf, 0); |
|
136 | vector next = llList2Vector(wpf, 1); |
136 | vector next = llList2Vector(wpf, 1); |
|
137 | |
137 | |
|
138 | // now calculate the next jump point |
138 | // now calculate the next jump point |
|
139 | next = start + ((dist/power)/dist) * (next-start); |
139 | next = start + ((dist/power)/dist) * (next-start); |
|
140 | |
140 | |
|
141 | // if it falls withing the tollerance range, return it; |
141 | // if it falls withing the tollerance range, return it; |
|
142 | if(llVecMag(start-next) < tollerance) return next; |
142 | if(llVecMag(start-next) < tollerance) return next; |
|
143 | return wasPolygonCentroid(polygon, next, tollerance, power*power); |
143 | return wasPolygonCentroid(polygon, next, tollerance, power*power); |
|
144 | } |
144 | } |
|
145 | |
145 | |
|
146 | /////////////////////////////////////////////////////////////////////////// |
146 | /////////////////////////////////////////////////////////////////////////// |
|
147 | // Copyright (C) 2011 Wizardry and Steamworks - License: GNU GPLv3 // |
147 | // Copyright (C) 2011 Wizardry and Steamworks - License: CC BY 2.0 // |
|
148 | /////////////////////////////////////////////////////////////////////////// |
148 | /////////////////////////////////////////////////////////////////////////// |
|
149 | vector wasCirclePoint(float radius) { |
149 | vector wasCirclePoint(float radius) { |
|
150 | float x = llPow(-1, 1 + (integer) llFrand(2)) * llFrand(radius*2); |
150 | float x = llPow(-1, 1 + (integer) llFrand(2)) * llFrand(radius*2); |
|
151 | float y = llPow(-1, 1 + (integer) llFrand(2)) * llFrand(radius*2); |
151 | float y = llPow(-1, 1 + (integer) llFrand(2)) * llFrand(radius*2); |
|
152 | if(llPow(x,2) + llPow(y,2) <= llPow(radius,2)) |
152 | if(llPow(x,2) + llPow(y,2) <= llPow(radius,2)) |
|
153 | return <x, y, 0>; |
153 | return <x, y, 0>; |
|
154 | return wasCirclePoint(radius); |
154 | return wasCirclePoint(radius); |
|
155 | } |
155 | } |
|
156 | |
156 | |
|
157 | /////////////////////////////////////////////////////////////////////////// |
157 | /////////////////////////////////////////////////////////////////////////// |
|
158 | // Copyright (C) 2011 Wizardry and Steamworks - License: GNU GPLv3 // |
158 | // Copyright (C) 2011 Wizardry and Steamworks - License: CC BY 2.0 // |
|
159 | /////////////////////////////////////////////////////////////////////////// |
159 | /////////////////////////////////////////////////////////////////////////// |
|
160 | vector wasPolygonPoint(list polygon) { |
160 | vector wasPolygonPoint(list polygon) { |
|
161 | vector c = wasPolygonCentroid(polygon, llList2Vector(polygon, 0), 0.05, 2); |
161 | vector c = wasPolygonCentroid(polygon, llList2Vector(polygon, 0), 0.05, 2); |
|
162 | float r = llList2Float(wasPointToPolygon(polygon, c), 0); |
162 | float r = llList2Float(wasPointToPolygon(polygon, c), 0); |
|
163 | vector d; |
163 | vector d; |
|
164 | do { |
164 | do { |
|
165 | d = c + wasCirclePoint(r); |
165 | d = c + wasCirclePoint(r); |
|
166 | } while(wasPointInPolygon(d, polygon) == FALSE); |
166 | } while(wasPointInPolygon(d, polygon) == FALSE); |
|
167 | return d; |
167 | return d; |
|
168 | } |
168 | } |
|
169 | |
169 | |
|
170 | /////////////////////////////////////////////////////////////////////////// |
170 | /////////////////////////////////////////////////////////////////////////// |
|
171 | // Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 // |
171 | // Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0 // |
|
172 | /////////////////////////////////////////////////////////////////////////// |
172 | /////////////////////////////////////////////////////////////////////////// |
|
173 | // determines whether the path between the current positon m and the |
173 | // determines whether the path between the current positon m and the |
|
174 | // computed next position d will intersect any two sides of the polygon |
174 | // computed next position d will intersect any two sides of the polygon |
|
175 | vector wasPolygonPath(vector m, list polygon) { |
175 | vector wasPolygonPath(vector m, list polygon) { |
|
176 | integer c = llGetListLength(polygon) - 1; |
176 | integer c = llGetListLength(polygon) - 1; |
|
177 | vector d = wasPolygonPoint(polygon); |
177 | vector d = wasPolygonPoint(polygon); |
|
178 | integer i = 0; |
178 | integer i = 0; |
|
179 | do { |
179 | do { |
|
180 | vector s = llList2Vector(polygon, c); |
180 | vector s = llList2Vector(polygon, c); |
|
181 | vector p = llList2Vector(polygon, c-1); |
181 | vector p = llList2Vector(polygon, c-1); |
|
182 | // project in plane |
182 | // project in plane |
|
183 | if(wasSegmentIntersect( |
183 | if(wasSegmentIntersect( |
|
184 | <m.x, m.y, 0>, |
184 | <m.x, m.y, 0>, |
|
185 | <d.x, d.y, 0>, |
185 | <d.x, d.y, 0>, |
|
186 | <s.x, s.y, 0>, |
186 | <s.x, s.y, 0>, |
|
187 | <p.x, p.y, 0>)) |
187 | <p.x, p.y, 0>)) |
|
188 | ++i; |
188 | ++i; |
|
189 | } while(--c > 0); |
189 | } while(--c > 0); |
|
190 | if(i > 1) return wasPolygonPath(m, polygon); |
190 | if(i > 1) return wasPolygonPath(m, polygon); |
|
191 | return d; |
191 | return d; |
|
192 | } |
192 | } |
|
193 | |
193 | |
|
194 | /////////////////////////////////////////////////////////////////////////// |
194 | /////////////////////////////////////////////////////////////////////////// |
|
195 | // Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 // |
195 | // Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0 // |
|
196 | /////////////////////////////////////////////////////////////////////////// |
196 | /////////////////////////////////////////////////////////////////////////// |
|
197 | // escapes a string in conformance with RFC1738 |
197 | // escapes a string in conformance with RFC1738 |
|
198 | string wasURLEscape(string i) { |
198 | string wasURLEscape(string i) { |
|
199 | string o = ""; |
199 | string o = ""; |
|
200 | do { |
200 | do { |
|
201 | string c = llGetSubString(i, 0, 0); |
201 | string c = llGetSubString(i, 0, 0); |
|
202 | i = llDeleteSubString(i, 0, 0); |
202 | i = llDeleteSubString(i, 0, 0); |
|
203 | if(c == "") jump continue; |
203 | if(c == "") jump continue; |
|
204 | if(c == " ") { |
204 | if(c == " ") { |
|
205 | o += "+"; |
205 | o += "+"; |
|
206 | jump continue; |
206 | jump continue; |
|
207 | } |
207 | } |
|
208 | if(c == "\n") { |
208 | if(c == "\n") { |
|
209 | o += "%0D" + llEscapeURL(c); |
209 | o += "%0D" + llEscapeURL(c); |
|
210 | jump continue; |
210 | jump continue; |
|
211 | } |
211 | } |
|
212 | o += llEscapeURL(c); |
212 | o += llEscapeURL(c); |
|
213 | @continue; |
213 | @continue; |
|
214 | } while(i != ""); |
214 | } while(i != ""); |
|
215 | return o; |
215 | return o; |
|
216 | } |
216 | } |
|
217 | |
217 | |
|
218 | // corrade data |
218 | // corrade data |
|
219 | string CORRADE = ""; |
219 | string CORRADE = ""; |
|
220 | string GROUP = ""; |
220 | string GROUP = ""; |
|
221 | string PASSWORD = ""; |
221 | string PASSWORD = ""; |
|
222 | float RADIUS = 0; |
222 | float RADIUS = 0; |
|
223 | float WAIT = 0; |
223 | float WAIT = 0; |
|
224 | list POLYGON = []; |
224 | list POLYGON = []; |
|
225 | |
225 | |
|
226 | // for holding Corrade's current location |
226 | // for holding Corrade's current location |
|
227 | vector location = ZERO_VECTOR; |
227 | vector location = ZERO_VECTOR; |
|
228 | |
228 | |
|
229 | // for holding the callback URL |
229 | // for holding the callback URL |
|
230 | string callback = ""; |
230 | string callback = ""; |
|
231 | |
231 | |
|
232 | // for notecard reading |
232 | // for notecard reading |
|
233 | integer line = 0; |
233 | integer line = 0; |
|
234 | |
234 | |
|
235 | // key-value data will be read into this list |
235 | // key-value data will be read into this list |
|
236 | list tuples = []; |
236 | list tuples = []; |
|
237 | |
237 | |
|
238 | default { |
238 | default { |
|
239 | state_entry() { |
239 | state_entry() { |
|
240 | if(llGetInventoryType("configuration") != INVENTORY_NOTECARD) { |
240 | if(llGetInventoryType("configuration") != INVENTORY_NOTECARD) { |
|
241 | llOwnerSay("Sorry, could not find an inventory notecard."); |
241 | llOwnerSay("Sorry, could not find an inventory notecard."); |
|
242 | return; |
242 | return; |
|
243 | } |
243 | } |
|
244 | // DEBUG |
244 | // DEBUG |
|
245 | llOwnerSay("Reading configuration file..."); |
245 | llOwnerSay("Reading configuration file..."); |
|
246 | llGetNotecardLine("configuration", line); |
246 | llGetNotecardLine("configuration", line); |
|
247 | } |
247 | } |
|
248 | dataserver(key id, string data) { |
248 | dataserver(key id, string data) { |
|
249 | if(data == EOF) { |
249 | if(data == EOF) { |
|
250 | // invariant, length(tuples) % 2 == 0 |
250 | // invariant, length(tuples) % 2 == 0 |
|
251 | if(llGetListLength(tuples) % 2 != 0) { |
251 | if(llGetListLength(tuples) % 2 != 0) { |
|
252 | llOwnerSay("Error in configuration notecard."); |
252 | llOwnerSay("Error in configuration notecard."); |
|
253 | return; |
253 | return; |
|
254 | } |
254 | } |
|
255 | CORRADE = llList2String( |
255 | CORRADE = llList2String( |
|
256 | tuples, |
256 | tuples, |
|
257 | llListFindList( |
257 | llListFindList( |
|
258 | tuples, |
258 | tuples, |
|
259 | [ |
259 | [ |
|
260 | "corrade" |
260 | "corrade" |
|
261 | ] |
261 | ] |
|
262 | ) |
262 | ) |
|
263 | +1); |
263 | +1); |
|
264 | if(CORRADE == "") { |
264 | if(CORRADE == "") { |
|
265 | llOwnerSay("Error in configuration notecard: corrade"); |
265 | llOwnerSay("Error in configuration notecard: corrade"); |
|
266 | return; |
266 | return; |
|
267 | } |
267 | } |
|
268 | GROUP = llList2String( |
268 | GROUP = llList2String( |
|
269 | tuples, |
269 | tuples, |
|
270 | llListFindList( |
270 | llListFindList( |
|
271 | tuples, |
271 | tuples, |
|
272 | [ |
272 | [ |
|
273 | "group" |
273 | "group" |
|
274 | ] |
274 | ] |
|
275 | ) |
275 | ) |
|
276 | +1); |
276 | +1); |
|
277 | if(GROUP == "") { |
277 | if(GROUP == "") { |
|
278 | llOwnerSay("Error in configuration notecard: group"); |
278 | llOwnerSay("Error in configuration notecard: group"); |
|
279 | return; |
279 | return; |
|
280 | } |
280 | } |
|
281 | PASSWORD = llList2String( |
281 | PASSWORD = llList2String( |
|
282 | tuples, |
282 | tuples, |
|
283 | llListFindList( |
283 | llListFindList( |
|
284 | tuples, |
284 | tuples, |
|
285 | [ |
285 | [ |
|
286 | "password" |
286 | "password" |
|
287 | ] |
287 | ] |
|
288 | ) |
288 | ) |
|
289 | +1); |
289 | +1); |
|
290 | if(PASSWORD == "") { |
290 | if(PASSWORD == "") { |
|
291 | llOwnerSay("Error in configuration notecard: password"); |
291 | llOwnerSay("Error in configuration notecard: password"); |
|
292 | return; |
292 | return; |
|
293 | } |
293 | } |
|
294 | |
294 | |
|
295 | // BEGIN POLYGON |
295 | // BEGIN POLYGON |
|
296 | integer i = llGetListLength(tuples)-1; |
296 | integer i = llGetListLength(tuples)-1; |
|
297 | do { |
297 | do { |
|
298 | string n = llList2String(tuples, i); |
298 | string n = llList2String(tuples, i); |
|
299 | if(llSubStringIndex(n, "point_") != -1) { |
299 | if(llSubStringIndex(n, "point_") != -1) { |
|
300 | list l = llParseString2List(n, ["_"], []); |
300 | list l = llParseString2List(n, ["_"], []); |
|
301 | if(llList2String(l, 0) == "point") { |
301 | if(llList2String(l, 0) == "point") { |
|
302 | integer x = llList2Integer( |
302 | integer x = llList2Integer( |
|
303 | l, |
303 | l, |
|
304 | 1 |
304 | 1 |
|
305 | )-1; |
305 | )-1; |
|
306 | // extend the polygon to the number of points |
306 | // extend the polygon to the number of points |
|
307 | while(llGetListLength(POLYGON) < x) |
307 | while(llGetListLength(POLYGON) < x) |
|
308 | POLYGON += ""; |
308 | POLYGON += ""; |
|
309 | // and insert the point at the location |
309 | // and insert the point at the location |
|
310 | POLYGON = llListReplaceList( |
310 | POLYGON = llListReplaceList( |
|
311 | POLYGON, |
311 | POLYGON, |
|
312 | (list)( |
312 | (list)( |
|
313 | (vector)( |
313 | (vector)( |
|
314 | "<" + llList2CSV( |
314 | "<" + llList2CSV( |
|
315 | llParseString2List( |
315 | llParseString2List( |
|
316 | llList2String( |
316 | llList2String( |
|
317 | tuples, |
317 | tuples, |
|
318 | llListFindList( |
318 | llListFindList( |
|
319 | tuples, |
319 | tuples, |
|
320 | (list)n |
320 | (list)n |
|
321 | ) |
321 | ) |
|
322 | +1 |
322 | +1 |
|
323 | ), |
323 | ), |
|
324 | ["<", ",", ">"], |
324 | ["<", ",", ">"], |
|
325 | [] |
325 | [] |
|
326 | ) |
326 | ) |
|
327 | ) + ">") |
327 | ) + ">") |
|
328 | ), |
328 | ), |
|
329 | x, |
329 | x, |
|
330 | x |
330 | x |
|
331 | ); |
331 | ); |
|
332 | } |
332 | } |
|
333 | } |
333 | } |
|
334 | } while(--i>-1); |
334 | } while(--i>-1); |
|
335 | // now clean up any empty slots |
335 | // now clean up any empty slots |
|
336 | i = llGetListLength(POLYGON)-1; |
336 | i = llGetListLength(POLYGON)-1; |
|
337 | do { |
337 | do { |
|
338 | if(llList2String(POLYGON, i) == "") |
338 | if(llList2String(POLYGON, i) == "") |
|
339 | POLYGON = llDeleteSubList(POLYGON, i, i); |
339 | POLYGON = llDeleteSubList(POLYGON, i, i); |
|
340 | } while(--i > -1); |
340 | } while(--i > -1); |
|
341 | // END POLYGON |
341 | // END POLYGON |
|
342 | |
342 | |
|
343 | WAIT = llList2Float( |
343 | WAIT = llList2Float( |
|
344 | tuples, |
344 | tuples, |
|
345 | llListFindList( |
345 | llListFindList( |
|
346 | tuples, |
346 | tuples, |
|
347 | [ |
347 | [ |
|
348 | "wait" |
348 | "wait" |
|
349 | ] |
349 | ] |
|
350 | ) |
350 | ) |
|
351 | +1); |
351 | +1); |
|
352 | if(WAIT == 0) { |
352 | if(WAIT == 0) { |
|
353 | llOwnerSay("Error in configuration notecard: wait"); |
353 | llOwnerSay("Error in configuration notecard: wait"); |
|
354 | return; |
354 | return; |
|
355 | } |
355 | } |
|
356 | // DEBUG |
356 | // DEBUG |
|
357 | llOwnerSay("Read configuration file..."); |
357 | llOwnerSay("Read configuration file..."); |
|
358 | state url; |
358 | state url; |
|
359 | } |
359 | } |
|
360 | if(data == "") jump continue; |
360 | if(data == "") jump continue; |
|
361 | integer i = llSubStringIndex(data, "#"); |
361 | integer i = llSubStringIndex(data, "#"); |
|
362 | if(i != -1) data = llDeleteSubString(data, i, -1); |
362 | if(i != -1) data = llDeleteSubString(data, i, -1); |
|
363 | list o = llParseString2List(data, ["="], []); |
363 | list o = llParseString2List(data, ["="], []); |
|
364 | // get rid of starting and ending quotes |
364 | // get rid of starting and ending quotes |
|
365 | string k = llDumpList2String( |
365 | string k = llDumpList2String( |
|
366 | llParseString2List( |
366 | llParseString2List( |
|
367 | llStringTrim( |
367 | llStringTrim( |
|
368 | llList2String( |
368 | llList2String( |
|
369 | o, |
369 | o, |
|
370 | 0 |
370 | 0 |
|
371 | ), |
371 | ), |
|
372 | STRING_TRIM), |
372 | STRING_TRIM), |
|
373 | ["\""], [] |
373 | ["\""], [] |
|
374 | ), "\""); |
374 | ), "\""); |
|
375 | string v = llDumpList2String( |
375 | string v = llDumpList2String( |
|
376 | llParseString2List( |
376 | llParseString2List( |
|
377 | llStringTrim( |
377 | llStringTrim( |
|
378 | llList2String( |
378 | llList2String( |
|
379 | o, |
379 | o, |
|
380 | 1 |
380 | 1 |
|
381 | ), |
381 | ), |
|
382 | STRING_TRIM), |
382 | STRING_TRIM), |
|
383 | ["\""], [] |
383 | ["\""], [] |
|
384 | ), "\""); |
384 | ), "\""); |
|
385 | if(k == "" || v == "") jump continue; |
385 | if(k == "" || v == "") jump continue; |
|
386 | tuples += k; |
386 | tuples += k; |
|
387 | tuples += v; |
387 | tuples += v; |
|
388 | @continue; |
388 | @continue; |
|
389 | llGetNotecardLine("configuration", ++line); |
389 | llGetNotecardLine("configuration", ++line); |
|
390 | } |
390 | } |
|
391 | on_rez(integer num) { |
391 | on_rez(integer num) { |
|
392 | llResetScript(); |
392 | llResetScript(); |
|
393 | } |
393 | } |
|
394 | changed(integer change) { |
394 | changed(integer change) { |
|
395 | if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) { |
395 | if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) { |
|
396 | llResetScript(); |
396 | llResetScript(); |
|
397 | } |
397 | } |
|
398 | } |
398 | } |
|
399 | } |
399 | } |
|
400 | |
400 | |
|
401 | state url { |
401 | state url { |
|
402 | state_entry() { |
402 | state_entry() { |
|
403 | // DEBUG |
403 | // DEBUG |
|
404 | llOwnerSay("Requesting URL..."); |
404 | llOwnerSay("Requesting URL..."); |
|
405 | llRequestURL(); |
405 | llRequestURL(); |
|
406 | } |
406 | } |
|
407 | http_request(key id, string method, string body) { |
407 | http_request(key id, string method, string body) { |
|
408 | if(method != URL_REQUEST_GRANTED) return; |
408 | if(method != URL_REQUEST_GRANTED) return; |
|
409 | callback = body; |
409 | callback = body; |
|
410 | // DEBUG |
410 | // DEBUG |
|
411 | llOwnerSay("Got URL..."); |
411 | llOwnerSay("Got URL..."); |
|
412 | state detect; |
412 | state detect; |
|
413 | } |
413 | } |
|
414 | on_rez(integer num) { |
414 | on_rez(integer num) { |
|
415 | llResetScript(); |
415 | llResetScript(); |
|
416 | } |
416 | } |
|
417 | changed(integer change) { |
417 | changed(integer change) { |
|
418 | if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) { |
418 | if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) { |
|
419 | llResetScript(); |
419 | llResetScript(); |
|
420 | } |
420 | } |
|
421 | } |
421 | } |
|
422 | } |
422 | } |
|
423 | |
423 | |
|
424 | state detect { |
424 | state detect { |
|
425 | state_entry() { |
425 | state_entry() { |
|
426 | // DEBUG |
426 | // DEBUG |
|
427 | llOwnerSay("Detecting if Corrade is online..."); |
427 | llOwnerSay("Detecting if Corrade is online..."); |
|
428 | llSetTimerEvent(5); |
428 | llSetTimerEvent(5); |
|
429 | } |
429 | } |
|
430 | timer() { |
430 | timer() { |
|
431 | llRequestAgentData((key)CORRADE, DATA_ONLINE); |
431 | llRequestAgentData((key)CORRADE, DATA_ONLINE); |
|
432 | } |
432 | } |
|
433 | dataserver(key id, string data) { |
433 | dataserver(key id, string data) { |
|
434 | if(data != "1") { |
434 | if(data != "1") { |
|
435 | // DEBUG |
435 | // DEBUG |
|
436 | llOwnerSay("Corrade is not online, sleeping..."); |
436 | llOwnerSay("Corrade is not online, sleeping..."); |
|
437 | llSetTimerEvent(30); |
437 | llSetTimerEvent(30); |
|
438 | return; |
438 | return; |
|
439 | } |
439 | } |
|
440 | llSensor("", (key)CORRADE, AGENT, 10, TWO_PI); |
440 | llSensor("", (key)CORRADE, AGENT, 10, TWO_PI); |
|
441 | } |
441 | } |
|
442 | no_sensor() { |
442 | no_sensor() { |
|
443 | // DEBUG |
443 | // DEBUG |
|
444 | llOwnerSay("Teleporting Corrade..."); |
444 | llOwnerSay("Teleporting Corrade..."); |
|
445 | llInstantMessage((key)CORRADE, |
445 | llInstantMessage((key)CORRADE, |
|
446 | wasKeyValueEncode( |
446 | wasKeyValueEncode( |
|
447 | [ |
447 | [ |
|
448 | "command", "teleport", |
448 | "command", "teleport", |
|
449 | "group", wasURLEscape(GROUP), |
449 | "group", wasURLEscape(GROUP), |
|
450 | "password", wasURLEscape(PASSWORD), |
450 | "password", wasURLEscape(PASSWORD), |
|
451 | "entity", "region", |
451 | "entity", "region", |
|
452 | "region", wasURLEscape(llGetRegionName()), |
452 | "region", wasURLEscape(llGetRegionName()), |
|
453 | "position", wasURLEscape( |
453 | "position", wasURLEscape( |
|
454 | (string)( |
454 | (string)( |
|
455 | llGetPos() + wasCirclePoint(RADIUS) |
455 | llGetPos() + wasCirclePoint(RADIUS) |
|
456 | ) |
456 | ) |
|
457 | ), |
457 | ), |
|
458 | "callback", callback |
458 | "callback", callback |
|
459 | ] |
459 | ] |
|
460 | ) |
460 | ) |
|
461 | ); |
461 | ); |
|
462 | llSensorRepeat("", (key)CORRADE, AGENT, 10, TWO_PI, 60); |
462 | llSensorRepeat("", (key)CORRADE, AGENT, 10, TWO_PI, 60); |
|
463 | } |
463 | } |
|
464 | sensor(integer num) { |
464 | sensor(integer num) { |
|
465 | llSetTimerEvent(0); |
465 | llSetTimerEvent(0); |
|
466 | state wander; |
466 | state wander; |
|
467 | } |
467 | } |
|
468 | http_request(key id, string method, string body) { |
468 | http_request(key id, string method, string body) { |
|
469 | llHTTPResponse(id, 200, "OK"); |
469 | llHTTPResponse(id, 200, "OK"); |
|
470 | if(wasKeyValueGet("command", body) != "teleport" || |
470 | if(wasKeyValueGet("command", body) != "teleport" || |
|
471 | wasKeyValueGet("success", body) != "True") { |
471 | wasKeyValueGet("success", body) != "True") { |
|
472 | // DEBUG |
472 | // DEBUG |
|
473 | llOwnerSay("Teleport failed..."); |
473 | llOwnerSay("Teleport failed..."); |
|
474 | return; |
474 | return; |
|
475 | } |
475 | } |
|
476 | llSetTimerEvent(0); |
476 | llSetTimerEvent(0); |
|
477 | state wander; |
477 | state wander; |
|
478 | } |
478 | } |
|
479 | on_rez(integer num) { |
479 | on_rez(integer num) { |
|
480 | llResetScript(); |
480 | llResetScript(); |
|
481 | } |
481 | } |
|
482 | changed(integer change) { |
482 | changed(integer change) { |
|
483 | if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) { |
483 | if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) { |
|
484 | llResetScript(); |
484 | llResetScript(); |
|
485 | } |
485 | } |
|
486 | } |
486 | } |
|
487 | } |
487 | } |
|
488 | |
488 | |
|
489 | state wander { |
489 | state wander { |
|
490 | state_entry() { |
490 | state_entry() { |
|
491 | // DEBUG |
491 | // DEBUG |
|
492 | llOwnerSay("Wandering ready..."); |
492 | llOwnerSay("Wandering ready..."); |
|
493 | // initialize location from current location |
493 | // initialize location from current location |
|
494 | location = llGetPos(); |
494 | location = llGetPos(); |
|
495 | llSetTimerEvent(1 + llFrand(WAIT)); |
495 | llSetTimerEvent(1 + llFrand(WAIT)); |
|
496 | } |
496 | } |
|
497 | timer() { |
497 | timer() { |
|
498 | llRequestAgentData((key)CORRADE, DATA_ONLINE); |
498 | llRequestAgentData((key)CORRADE, DATA_ONLINE); |
|
499 | } |
499 | } |
|
500 | dataserver(key id, string data) { |
500 | dataserver(key id, string data) { |
|
501 | if(data != "1") { |
501 | if(data != "1") { |
|
502 | // DEBUG |
502 | // DEBUG |
|
503 | llOwnerSay("Corrade is not online, sleeping..."); |
503 | llOwnerSay("Corrade is not online, sleeping..."); |
|
504 | llResetScript(); |
504 | llResetScript(); |
|
505 | return; |
505 | return; |
|
506 | } |
506 | } |
|
507 | // DEBUG |
507 | // DEBUG |
|
508 | //llOwnerSay("Sending stop..."); |
508 | //llOwnerSay("Sending stop..."); |
|
509 | llInstantMessage(CORRADE, |
509 | llInstantMessage(CORRADE, |
|
510 | wasKeyValueEncode( |
510 | wasKeyValueEncode( |
|
511 | [ |
511 | [ |
|
512 | "command", "autopilot", |
512 | "command", "autopilot", |
|
513 | "group", wasURLEscape(GROUP), |
513 | "group", wasURLEscape(GROUP), |
|
514 | "password", wasURLEscape(PASSWORD), |
514 | "password", wasURLEscape(PASSWORD), |
|
515 | "action", "stop", |
515 | "action", "stop", |
|
516 | "callback", wasURLEscape(callback) |
516 | "callback", wasURLEscape(callback) |
|
517 | ] |
517 | ] |
|
518 | ) |
518 | ) |
|
519 | ); |
519 | ); |
|
520 | } |
520 | } |
|
521 | http_request(key id, string method, string body) { |
521 | http_request(key id, string method, string body) { |
|
522 | llHTTPResponse(id, 200, "OK"); |
522 | llHTTPResponse(id, 200, "OK"); |
|
523 | if(wasKeyValueGet("command", body) != "autopilot" || |
523 | if(wasKeyValueGet("command", body) != "autopilot" || |
|
524 | wasKeyValueGet("success", body) != "True") { |
524 | wasKeyValueGet("success", body) != "True") { |
|
525 | // DEBUG |
525 | // DEBUG |
|
526 | llOwnerSay("Could not get Corrade to stop, restarting script..."); |
526 | llOwnerSay("Could not get Corrade to stop, restarting script..."); |
|
527 | llResetScript(); |
527 | llResetScript(); |
|
528 | } |
528 | } |
|
529 | // DEBUG |
529 | // DEBUG |
|
530 | llOwnerSay("Sending next move..."); |
530 | llOwnerSay("Sending next move..."); |
|
531 | // get the next location |
531 | // get the next location |
|
532 | location = wasPolygonPath(location, POLYGON); |
532 | location = wasPolygonPath(location, POLYGON); |
|
533 | vector pos = llGetPos(); |
533 | vector pos = llGetPos(); |
|
534 | llInstantMessage(CORRADE, |
534 | llInstantMessage(CORRADE, |
|
535 | wasKeyValueEncode( |
535 | wasKeyValueEncode( |
|
536 | [ |
536 | [ |
|
537 | "command", "autopilot", |
537 | "command", "autopilot", |
|
538 | "group", wasURLEscape(GROUP), |
538 | "group", wasURLEscape(GROUP), |
|
539 | "password", wasURLEscape(PASSWORD), |
539 | "password", wasURLEscape(PASSWORD), |
|
540 | "position", wasURLEscape( |
540 | "position", wasURLEscape( |
|
541 | (string)(<location.x, location.y, pos.z>) |
541 | (string)(<location.x, location.y, pos.z>) |
|
542 | ), |
542 | ), |
|
543 | "action", "start" |
543 | "action", "start" |
|
544 | ] |
544 | ] |
|
545 | ) |
545 | ) |
|
546 | ); |
546 | ); |
|
547 | llSetTimerEvent(1 + llFrand(WAIT)); |
547 | llSetTimerEvent(1 + llFrand(WAIT)); |
|
548 | } |
548 | } |
|
549 | on_rez(integer num) { |
549 | on_rez(integer num) { |
|
550 | llResetScript(); |
550 | llResetScript(); |
|
551 | } |
551 | } |
|
552 | changed(integer change) { |
552 | changed(integer change) { |
|
553 | if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) { |
553 | if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) { |
|
554 | llResetScript(); |
554 | llResetScript(); |
|
555 | } |
555 | } |
|
556 | } |
556 | } |
|
557 | } |
557 | } |
|
558 | |
558 | |