[Half-Life AMXX] / include / xs.inc Repository:
ViewVC logotype

Annotation of /include/xs.inc

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1 - (view) (download)

1 : ian 1 /* XS Library
2 :     * for AMX and AMXX
3 :     *
4 :     * Copyright (C) 2004 Pavol "PM" Marko
5 :     *
6 :     * This program is free software; you can redistribute it and/or modify it
7 :     * under the terms of the GNU General Public License as published by the
8 :     * Free Software Foundation; either version 2 of the License, or (at
9 :     * your option) any later version.
10 :     *
11 :     * This program is distributed in the hope that it will be useful, but
12 :     * WITHOUT ANY WARRANTY; without even the implied warranty of
13 :     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 :     * General Public License for more details.
15 :     *
16 :     * You should have received a copy of the GNU General Public License
17 :     * along with this program; if not, write to the Free Software Foundation,
18 :     * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 :     *
20 :     * In addition, as a special exception, the author gives permission to
21 :     * link the code of this program with the Half-Life Game Engine ("HL
22 :     * Engine") and Modified Game Libraries ("MODs") developed by Valve,
23 :     * L.L.C ("Valve"). You must obey the GNU General Public License in all
24 :     * respects for all of the code used other than the HL Engine and MODs
25 :     * from Valve. If you modify this file, you may extend this exception
26 :     * to your version of the file, but you are not obligated to do so. If
27 :     * you do not wish to do so, delete this exception statement from your
28 :     * version.
29 :     *
30 :     * Version 0.1
31 :     *
32 :     *
33 :     * MACROS THAT YOU CAN DEFINE BEFORE INCLUDING XS.INC:
34 :     * XS_FLEQ_TOLERANCE:
35 :     * Tolerance that is used for XS_FLEQ float nearly-equal comparisions
36 :     * DEFAULT: 0.000005
37 :     * XS_DEBUG
38 :     * Turn debug logging on
39 :     * DEFAULT: 0
40 :     * XS_LOGBUFFER_SIZE
41 :     * Buffer size for logging
42 :     * DEFAULT: 512
43 :     * XS_TASK_MAXPARAMS
44 :     * Maximal parameter count for managed tasks
45 :     * DEFAULT: 8
46 :     * XS_TASK_MAXPARAMSIZE
47 :     * Maximal size of string parameter for tasks
48 :     * Has to be power of 2 and has to be >= 8
49 :     * DEFAULT: 512
50 :     * XS_TASK_MANAGEDIDS
51 :     * Number of managed IDs for tasks.
52 :     * DEFAULT: 2048
53 :     * XS_REPLACEBUF_SIZE
54 :     * DEFAULT: 3072
55 :     *
56 :     *
57 :     * NOTES:
58 :     * On AMX, VexdUM is required for some math functions
59 :     *
60 :     * xs__ / XS__ (2 underscores) stuff is meant to be intern
61 :     *
62 :     * untested: never tested
63 :     * half-tested: succesfully used in other applications; not extensively tested in xs though
64 :     * tested: fully tested
65 :     *
66 :     * If you have any useful functions / ideas for functions, please tell me.
67 :     */
68 :    
69 :     #if defined _xs_included
70 :     #endinput
71 :     #endif
72 :     #define _xs_included
73 :    
74 :     // **** CONFIG CHECK
75 :    
76 :     #if !defined XS_FLEQ_TOLERANCE
77 :     #define XS_FLEQ_TOLERANCE 0.000005
78 :     #endif
79 :    
80 :     #if !defined XS_DEBUG
81 :     #define XS_DEBUG 0
82 :     #endif
83 :    
84 :     #if !defined XS_LOGBUFFER_SIZE
85 :     #define XS_LOGBUFFER_SIZE 512
86 :     #endif
87 :    
88 :     #if !defined XS_TASK_MAXPARAMS
89 :     #define XS_TASK_MAXPARAMS 8
90 :     #endif
91 :    
92 :     #if !defined XS_TASK_MAXPARAMSIZE
93 :     #define XS_TASK_MAXPARAMSIZE 512
94 :     #endif
95 :    
96 :     #if !defined XS_TASK_MANAGEDIDS
97 :     #define XS_TASK_MANAGEDIDS 2048
98 :     #endif
99 :    
100 :     #if !defined XS_REPLACEBUF_SIZE
101 :     #define XS_REPLACEBUF_SIZE 3072
102 :     #endif
103 :    
104 :     // **** Detect platform
105 :     #define XS_AMX 0
106 :     #define XS_AMXX 1
107 :    
108 :     #if defined _amxmodx_included
109 :     #define XS_PLATFORM XS_AMXX
110 :     #endif
111 :    
112 :     #if defined _amxmod_included && !defined _amxmodx_included
113 :     #define XS_PLATFORM XS_AMX
114 :     #endif
115 :    
116 :     #if !defined XS_PLATFORM
117 :     // Could not detect platform.
118 :     // Make sure you include amxmodx.inc or amxmod.inc before including xs.inc
119 :     #assert 0
120 :     #endinput
121 :     #endif
122 :    
123 :     // Turn on for release
124 :     #define XS__LIBRELEASE 1
125 :    
126 :     #if XS__LIBRELEASE
127 :     #define XS_LIBFUNC_ATTRIB stock
128 :     #else
129 :     #define XS_LIBFUNC_ATTRIB
130 :     #endif
131 :     #if XS__LIBRELEASE
132 :     #define XS_LIBVAR_ATTRIB stock
133 :     #else
134 :     #define XS_LIBVAR_ATTRIB new
135 :     #endif
136 :    
137 :    
138 :     // Hardcore
139 :     #pragma semicolon 1
140 :     /****** DEBUGGING / LOGING FUNCTIONS ******/
141 :     enum xs_logtypes
142 :     {
143 :     xs_debug,
144 :     xs_message,
145 :     xs_warning,
146 :     xs_error,
147 :     xs_fatalerror,
148 :     xs__assertionfailed,
149 :    
150 :     // must come last
151 :     xs_logtypes_count
152 :     }
153 :    
154 :     XS_LIBVAR_ATTRIB const xs__logtypenames[xs_logtypes_count][] = {"DEBUG", "", "WARNING", "ERROR", "FATAL ERROR", "DEBUG ASSERTION FAILED"};
155 :    
156 :     // tested
157 :     XS_LIBFUNC_ATTRIB xs_log(xs_logtypes:logtype, {Float,_}:...)
158 :     {
159 :     // WARNING: Don't try to use assert in here; it uses this func
160 :    
161 :     // Don't log debug if not in debug mode
162 :     #if !XS_DEBUG
163 :     if (logtype == xs_debug)
164 :     return;
165 :     #endif
166 :    
167 :     new buffer[XS_LOGBUFFER_SIZE+1];
168 :     buffer[XS_LOGBUFFER_SIZE]=0;
169 :     format_args(buffer, XS_LOGBUFFER_SIZE, 1 /* go from SECOND argument*/);
170 :     new bool:addLogTypeName = strlen(xs__logtypenames[logtype]) ? true : false;
171 :    
172 :     #if XS_PLATFORM == XS_AMX
173 :     new plugname[32];
174 :     new dummy[1];
175 :     get_plugin(-1, plugname, 31, dummy, 0, dummy, 0, dummy, 0, dummy, 0, dummy[0]);
176 :     // log into HL Logs
177 :     log_message("[AMX][%s]: %s%s%s", plugname, addLogTypeName ? xs__logtypenames[logtype] : "",
178 :     addLogTypeName ? ": " : "", buffer);
179 :     #else // assume AMXX
180 :    
181 :     // Use AMXX's logging system
182 :     log_amx("%s%s%s", addLogTypeName ? xs__logtypenames[logtype] : "",
183 :     addLogTypeName ? ": " : "", buffer);
184 :     #endif
185 :     }
186 :    
187 :     // Assertion
188 :     // tested
189 :     XS_LIBFUNC_ATTRIB xs_assertfunc({Float,_}:exp, const desc[])
190 :     {
191 :     // Check exp
192 :     if (exp)
193 :     return 1; // ok
194 :    
195 :     // not ok
196 :    
197 :     // print info
198 :     xs_log(xs__assertionfailed, "%s", desc);
199 :    
200 :     return 0;
201 :     }
202 :     #define xs_assert(%1,%2) if (!xs_assertfunc(%1,%2)) xs__global_null /= xs__global_null
203 :    
204 :    
205 :     // Assertion; only in debug mode
206 :     // untested; logical flow says it should work
207 :     #if XS_DEBUG
208 :     #define xs_assert_dbg(%1,%2) if (!xs_assertfunc(%1,%2)) xs__global_null /= xs__global_null
209 :     #else
210 :     #define xs_assert_dbg(%1,%2)
211 :     #endif
212 :    
213 :     new xs__global_null = 0;
214 :    
215 :     /****** MATH FUNCTIONS ******/
216 :    
217 :     /****** BASIC STUFF ******/
218 :    
219 :     #if XS_PLATFORM == XS_AMX
220 :     enum anglemode
221 :     {
222 :     radian = 0,
223 :     degrees,
224 :     grades
225 :     }
226 :     #endif
227 :    
228 :     // Returns -1 if num is negative, 0 if num is 0, 1 if num is positive
229 :     // tested
230 :     XS_LIBFUNC_ATTRIB xs_sign(num)
231 :     {
232 :     return (num < 0) ? -1 : ((num == 0) ? 0 : 1);
233 :     }
234 :    
235 :     // Returns -1 if num is negative, 0 if num is 0, 1 if num is positive
236 :     // tested
237 :     XS_LIBFUNC_ATTRIB xs_fsign(Float:num)
238 :     {
239 :     return (num < 0.0) ? -1 : ((num == 0.0) ? 0 : 1);
240 :     }
241 :    
242 :     // Returns absolute value
243 :     // tested
244 :     XS_LIBFUNC_ATTRIB xs_abs(num)
245 :     {
246 :     return (num < 0) ? -num : num;
247 :     }
248 :    
249 :     // is power of 2? (== can be expressed as 1<<i)
250 :     // tested
251 :     XS_LIBFUNC_ATTRIB xs_is_2power(x)
252 :     {
253 :     return (x!=0) && ((x&(x-1))==0);
254 :     }
255 :    
256 :     // degrees to radians
257 :     // tested
258 :     XS_LIBFUNC_ATTRIB Float:xs_deg2rad(Float:x)
259 :     {
260 :     return x * 0.017453292519943;
261 :     }
262 :    
263 :     // tested
264 :     XS_LIBFUNC_ATTRIB Float:xs_rad2deg(Float:x)
265 :     {
266 :     return x * 57.29577951308232;
267 :     }
268 :    
269 :     // untested, should work though
270 :     XS_LIBFUNC_ATTRIB Float:xs_gra2rad(Float:x)
271 :     {
272 :     return x * 0.015707963267948;
273 :     }
274 :    
275 :     // untested, should work though
276 :     XS_LIBFUNC_ATTRIB Float:xs_rad2gra(Float:x)
277 :     {
278 :     return x * 63.66197723675813;
279 :     }
280 :    
281 :     // Only works when there is no whitespace between %1, the comma and %2...
282 :     // tested
283 :     #define XS_FLEQ(%1,%2) (((%1) <= ((%2) + XS_FLEQ_TOLERANCE)) && ((%1) >= ((%2) - XS_FLEQ_TOLERANCE)))
284 :    
285 :     // 1/sqrt
286 :     // tested
287 :     XS_LIBFUNC_ATTRIB Float:xs_rsqrt(Float:x)
288 :     {
289 :     #if XS_PLATFORM == XS_AMX
290 :     // store half
291 :     new Float:xhalf = x * 0.5;
292 :    
293 :     // compute initial guess
294 :     new i = _:x;
295 :     i = 0x5f375a84 - (i >> 1);
296 :     x = Float:i;
297 :    
298 :     // refine 3 times
299 :     x = x * (1.5 - xhalf * x * x);
300 :     x = x * (1.5 - xhalf * x * x);
301 :     x = x * (1.5 - xhalf * x * x);
302 :    
303 :     return x;
304 :     #else
305 :     return 1.0 / floatsqroot(x);
306 :     #endif
307 :     }
308 :    
309 :     // sqrt
310 :     // tested
311 :     XS_LIBFUNC_ATTRIB Float:xs_sqrt(Float:x)
312 :     {
313 :     #if XS_PLATFORM == XS_AMX
314 :     // 1.0 / rsqrt should still be faster than loop-using-approximation-methods
315 :     return 1.0 / xs_rsqrt(x);
316 :     #else
317 :     return floatsqroot(x);
318 :     #endif
319 :     }
320 :    
321 :     // These functions generate errors if you use the macros with wrong parameter count.
322 :     stock Float:xs_fabs(Float:pa)
323 :     {
324 :     #pragma unused pa
325 :     new rawr = you_need_one_param_for_fabs;
326 :     rawr = warning_below_shows_line_number;
327 :     #pragma unused rawr
328 :     }
329 :     stock Float:xs_asin(Float:pa,Float:pb)
330 :     {
331 :     #pragma unused pa,pb
332 :     new rawr = you_need_two_params_for_asin;
333 :     rawr = warning_below_shows_line_number;
334 :     #pragma unused rawr
335 :     }
336 :     stock Float:xs_sin(Float:pa,Float:pb)
337 :     {
338 :     #pragma unused pa,pb
339 :     new rawr = you_need_two_params_for_sin;
340 :     #pragma unused rawr
341 :     }
342 :     stock Float:xs_acos(Float:pa,Float:pb)
343 :     {
344 :     #pragma unused pa,pb
345 :     new rawr = you_need_two_params_for_acos;
346 :     rawr = warning_below_shows_line_number;
347 :     #pragma unused rawr
348 :     }
349 :     stock Float:xs_cos(Float:pa,Float:pb)
350 :     {
351 :     #pragma unused pa,pb
352 :     new rawr = you_need_two_params_for_cos;
353 :     rawr = warning_below_shows_line_number;
354 :     #pragma unused rawr
355 :     }
356 :     stock Float:xs_atan(Float:pa,Float:pb)
357 :     {
358 :     #pragma unused pa,pb
359 :     new rawr = you_need_two_params_for_atan;
360 :     rawr = warning_below_shows_line_number;
361 :     #pragma unused rawr
362 :     }
363 :     stock Float:xs_atan2(Float:pa,Float:pb)
364 :     {
365 :     #pragma unused pa,pb
366 :     new rawr = you_need_two_params_for_atan2;
367 :     rawr = warning_below_shows_line_number;
368 :     #pragma unused rawr
369 :     }
370 :     stock Float:xs_tan(Float:pa, Float:pb)
371 :     {
372 :     #pragma unused pa,pb
373 :     new rawr = you_need_two_params_for_tan;
374 :     rawr = warning_below_shows_line_number;
375 :     #pragma unused rawr
376 :     }
377 :    
378 :     #if XS_PLATFORM == XS_AMX
379 :     #pragma semicolon 0
380 :     #include <VexdUM>
381 :     #pragma semicolon 1
382 :     // We need stocks to provide radian / degrees / grades functionality
383 :    
384 :     XS_LIBFUNC_ATTRIB Float:xs__2rad(Float:x, anglemode:mod)
385 :     {
386 :     switch (mod)
387 :     {
388 :     case radian:
389 :     return x;
390 :     case degrees:
391 :     return xs_deg2rad(x);
392 :     case grades:
393 :     return xs_gra2rad(x);
394 :     default:
395 :     xs_assert(0, "xs_asin, xs_sin, xs_acos, xs_cos, xs_atan, xs_atan2 or xs_tan called with invalid mod param");
396 :     }
397 :    
398 :     return 0.0; // compiler warning
399 :     }
400 :    
401 :     #define xs_fabs(%1) fabs(%1)
402 :     #define xs_asin(%1,%2) asin(xs__2rad(%1, %2))
403 :     #define xs_sin(%1,%2) sin(xs__2rad(%1, %2))
404 :     #define xs_acos(%1,%2) acos(xs__2rad(%1, %2))
405 :     #define xs_cos(%1,%2) cos(xs__2rad(%1, %2))
406 :     #define xs_atan(%1,%2) atan(xs__2rad(%1, %2))
407 :     #define xs_atan2(%1,%2) atan2(xs__2rad(%1, %2))
408 :     #define xs_tan(%1,%2) tan(xs__2rad(%1, %2))
409 :     #else
410 :     #define xs_fabs(%1) floatabs(%1)
411 :     #define xs_asin(%1,%2) floatasin(%1, %2)
412 :     #define xs_sin(%1,%2) floatsin(%1, %2)
413 :     #define xs_acos(%1,%2) floatacos(%1, %2)
414 :     #define xs_cos(%1,%2) floatcos(%1, %2)
415 :     #define xs_atan(%1,%2) floatatan(%1, %2)
416 :     #define xs_atan2(%1,%2) floatatan2(%1, %2)
417 :     #define xs_tan(%1,%2) floattan(%1, %2)
418 :     #endif
419 :    
420 :     /****** RANDOM NUMBERS ******/
421 :     // This routine comes from the book "Inner Loops" by Rick Booth, Addison-Wesley
422 :     // (ISBN 0-201-47960-5). This is a "multiplicative congruential random number
423 :     // generator" that has been extended to 31-bits
424 :    
425 :     XS_LIBVAR_ATTRIB xs__internalseed=0x546875;
426 :    
427 :     #define XS__IL_RMULT 1103515245
428 :    
429 :     // tested
430 :     XS_LIBFUNC_ATTRIB xs_seed(seed)
431 :     {
432 :     xs__internalseed = seed;
433 :     }
434 :    
435 :     // tested
436 :     XS_LIBFUNC_ATTRIB xs_irand()
437 :     {
438 :     new lo, hi, ll, lh, hh, hl;
439 :     new result;
440 :    
441 :     lo = xs__internalseed & 0xffff;
442 :     hi = xs__internalseed >> 16;
443 :     xs__internalseed = xs__internalseed * XS__IL_RMULT + 12345;
444 :     ll = lo * (XS__IL_RMULT & 0xffff);
445 :     lh = lo * (XS__IL_RMULT >> 16 );
446 :     hl = hi * (XS__IL_RMULT & 0xffff);
447 :     hh = hi * (XS__IL_RMULT >> 16 );
448 :     result = xs_abs(((ll + 12345) >> 16) + lh + hl + (hh << 16));
449 :     return result;
450 :     }
451 :    
452 :     // tested
453 :     XS_LIBFUNC_ATTRIB Float:xs_frand()
454 :     {
455 :     return float(xs_irand()) / float(xs_get_maxnum()); // -1/2 should be the biggest possible positive number
456 :     }
457 :    
458 :     // tested
459 :     XS_LIBFUNC_ATTRIB xs_irand_range(pmin, pmax)
460 :     {
461 :     xs_assert_dbg(pmax - pmin >= 0, "xs_irand_range: pmin > pmax");
462 :     new i = pmin + floatround(xs_frand() * float(pmax - pmin));
463 :     if (i > pmax)
464 :     i = pmax;
465 :     return i;
466 :     }
467 :    
468 :     /****** VECTORS & PLANES ******/
469 :    
470 :     // *** vectors
471 :    
472 :     // Set vec components to values
473 :     // tested
474 :     XS_LIBFUNC_ATTRIB xs_vec_set(Float:vec[], Float:x, Float:y, Float:z)
475 :     {
476 :     vec[0] = x;
477 :     vec[1] = y;
478 :     vec[2] = z;
479 :     }
480 :    
481 :     // Add vec
482 :     // tested
483 :     XS_LIBFUNC_ATTRIB xs_vec_add(const Float:in1[], const Float:in2[], Float:out[])
484 :     {
485 :     out[0] = in1[0] + in2[0];
486 :     out[1] = in1[1] + in2[1];
487 :     out[2] = in1[2] + in2[2];
488 :     }
489 :    
490 :     // Subtract vec
491 :     // untested, but should work
492 :     XS_LIBFUNC_ATTRIB xs_vec_sub(const Float:in1[], const Float:in2[], Float:out[])
493 :     {
494 :     out[0] = in1[0] - in2[0];
495 :     out[1] = in1[1] - in2[1];
496 :     out[2] = in1[2] - in2[2];
497 :     }
498 :    
499 :     // Are vectors equal?
500 :     // untested, but should work
501 :     XS_LIBFUNC_ATTRIB bool:xs_vec_equal(const Float:vec1[], const Float:vec2[])
502 :     {
503 :     return (vec1[0] == vec2[0]) && (vec1[1] == vec2[1]) && (vec1[2] == vec2[2]);
504 :     }
505 :    
506 :     // Are vectors nearly equal?
507 :     // tested
508 :     XS_LIBFUNC_ATTRIB bool:xs_vec_nearlyequal(const Float:vec1[], const Float:vec2[])
509 :     {
510 :     return XS_FLEQ(vec1[0], vec2[0]) && XS_FLEQ(vec1[1], vec2[1]) && XS_FLEQ(vec1[2], vec2[2]);
511 :     }
512 :    
513 :     // multiply vector by scalar
514 :     // tested
515 :     XS_LIBFUNC_ATTRIB xs_vec_mul_scalar(const Float:vec[], Float:scalar, Float:out[])
516 :     {
517 :     out[0] = vec[0] * scalar;
518 :     out[1] = vec[1] * scalar;
519 :     out[2] = vec[2] * scalar;
520 :     }
521 :    
522 :     // divide vector by scalar
523 :     // untested, but should work
524 :     XS_LIBFUNC_ATTRIB xs_vec_div_scalar(const Float:vec[], Float:scalar, Float:out[])
525 :     {
526 :     new Float:__tmp = 1.0 / scalar;
527 :     out[0] = vec[0] * __tmp;
528 :     out[1] = vec[1] * __tmp;
529 :     out[2] = vec[2] * __tmp;
530 :     }
531 :    
532 :     // Compute vector length
533 :     // tested
534 :     XS_LIBFUNC_ATTRIB Float:xs_vec_len(const Float:vec[])
535 :     {
536 :     return xs_sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]);
537 :     }
538 :    
539 :     // Normalize vec
540 :     // tested
541 :     XS_LIBFUNC_ATTRIB xs_vec_normalize(const Float:vec[], Float:out[])
542 :     {
543 :     new Float:invlen = xs_rsqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]);
544 :     out[0] = vec[0] * invlen;
545 :     out[1] = vec[1] * invlen;
546 :     out[2] = vec[2] * invlen;
547 :     }
548 :    
549 :     // Store the cross product of vec1 and vec2 in out
550 :     // tested
551 :     XS_LIBFUNC_ATTRIB xs_vec_cross(const Float:vec1[], const Float:vec2[], Float:out[])
552 :     {
553 :     out[0] = vec1[1]*vec2[2] - vec1[2]*vec2[1];
554 :     out[1] = vec1[2]*vec2[0] - vec1[0]*vec2[2];
555 :     out[2] = vec1[0]*vec2[1] - vec1[1]*vec2[0];
556 :     }
557 :    
558 :     // Compute vec1 dot vec2
559 :     // tested
560 :     XS_LIBFUNC_ATTRIB Float:xs_vec_dot(const Float:vec1[], const Float:vec2[])
561 :     {
562 :     return vec1[0]*vec2[0] + vec1[1]*vec2[1] + vec1[2]*vec2[2];
563 :     }
564 :    
565 :     // Negate vec into out
566 :     // untested, but should work
567 :     XS_LIBFUNC_ATTRIB xs_vec_neg(const Float:vec[], Float:out[])
568 :     {
569 :     out[0] = -vec[0];
570 :     out[1] = -vec[1];
571 :     out[2] = -vec[2];
572 :     }
573 :    
574 :     // Copy vec
575 :     // untested, but should work
576 :     XS_LIBFUNC_ATTRIB xs_vec_copy(const Float:vecIn[], Float:vecOut[])
577 :     {
578 :     vecOut[0] = vecIn[0];
579 :     vecOut[1] = vecIn[1];
580 :     vecOut[2] = vecIn[2];
581 :     }
582 :    
583 :     // Compute angle between vec1 and vec2
584 :     // tested
585 :     XS_LIBFUNC_ATTRIB Float:xs_vec_angle(const Float:vec1[], const Float:vec2[])
586 :     {
587 :     return xs_rad2deg(xs_acos(xs_vec_dot(vec1, vec2), radian));
588 :     }
589 :    
590 :     // Reflect vec about normal
591 :     // untested
592 :     XS_LIBFUNC_ATTRIB xs_vec_reflect(const Float:vec[], const Float:normal[], Float:out[])
593 :     {
594 :     // normalize(vec) - (normal * 2.0 * (tmp . normal)) * length(vec)
595 :    
596 :     new Float:tmp1[3];
597 :     xs_vec_normalize(vec, tmp1);
598 :    
599 :     // tmp1 - (normal * 2.0 * (tmp . normal)) * length(vec)
600 :    
601 :     new Float:tmp2[3];
602 :     xs_vec_mul_scalar(normal, 2.0, tmp2);
603 :     xs_vec_mul_scalar(tmp2, xs_vec_dot(tmp1, normal), tmp2);
604 :    
605 :     // tmp1 - tmp2 * length(vec)
606 :     xs_vec_mul_scalar(tmp2, xs_vec_len(vec), tmp2);
607 :    
608 :     // tmp1 - tmp2
609 :     xs_vec_sub(tmp1, tmp2, out);
610 :     }
611 :    
612 :     // Turn a 3D vector into a 2D vector
613 :     XS_LIBFUNC_ATTRIB xs_vec_make2d(const Float:vec[3], Float:out[2])
614 :     {
615 :     out[0] = vec[0];
616 :     out[1] = vec[1];
617 :     }
618 :    
619 :     // *** planes
620 :    
621 :     // normal
622 :     #define XS_PLANE_A 0
623 :     #define XS_PLANE_B 1
624 :     #define XS_PLANE_C 2
625 :     // plane shift distance
626 :     #define XS_PLANE_D 3
627 :    
628 :    
629 :     // Set a plane to specific values
630 :     // tested
631 :     XS_LIBFUNC_ATTRIB xs_plane_set(Float:plane[], Float:a, Float:b, Float:c, Float:d)
632 :     {
633 :     plane[XS_PLANE_A] = a;
634 :     plane[XS_PLANE_B] = b;
635 :     plane[XS_PLANE_C] = c;
636 :     plane[XS_PLANE_D] = d;
637 :     }
638 :    
639 :     // Construct a plane out of 3 points
640 :     // tested
641 :     XS_LIBFUNC_ATTRIB xs_plane_3p(Float:plane[], const Float:p1[], const Float:p2[], const Float:p3[])
642 :     {
643 :     new Float:normalA[3], Float:normalB[3];
644 :    
645 :     // normalA = Normalize(p3 - p1);
646 :     normalA[0] = p3[0] - p1[0];
647 :     normalA[1] = p3[1] - p1[1];
648 :     normalA[2] = p3[2] - p1[2];
649 :     xs_vec_normalize(normalA, normalA);
650 :    
651 :     // normalB = Normalize(p3 - p2);
652 :     normalB[0] = p3[0] - p2[0];
653 :     normalB[1] = p3[1] - p2[1];
654 :     normalB[2] = p3[2] - p2[2];
655 :     xs_vec_normalize(normalB, normalB);
656 :    
657 :     // plane normal = Normalize(normalA cross normalB)
658 :     xs_vec_cross(normalA, normalB, plane);
659 :     xs_vec_normalize(plane, plane);
660 :    
661 :     // plane shift distance = (-p1) dot plane normal
662 :     new Float:__tmp[3];
663 :     xs_vec_neg(plane, __tmp);
664 :     plane[XS_PLANE_D] = xs_vec_dot(__tmp, p1);
665 :    
666 :     }
667 :    
668 :     // untested, but should work
669 :     XS_LIBFUNC_ATTRIB bool:xs_plane_equal(const Float:plane1[], const Float:plane2[])
670 :     {
671 :     if ( (plane1[0] == plane2[0]) &&
672 :     (plane1[1] == plane2[1]) &&
673 :     (plane1[2] == plane2[2]) &&
674 :     (plane1[3] == plane2[3]))
675 :     return true;
676 :     return false;
677 :     }
678 :    
679 :     // untested, but should work
680 :     XS_LIBFUNC_ATTRIB bool:xs_plane_nearlyequal(const Float:plane1[], const Float:plane2[])
681 :     {
682 :     if ( XS_FLEQ(plane1[0], plane2[0]) &&
683 :     XS_FLEQ(plane1[1], plane2[1]) &&
684 :     XS_FLEQ(plane1[2], plane2[2]) &&
685 :     XS_FLEQ(plane1[3], plane2[3]))
686 :     return true;
687 :     return false;
688 :     }
689 :    
690 :     // Compute distance between plane and point
691 :     // tested
692 :     XS_LIBFUNC_ATTRIB Float:xs_plane_dst2point(const Float:plane[], const Float:point[])
693 :     {
694 :     // return normal dot point + D
695 :     return xs_vec_dot(plane, point) + plane[XS_PLANE_D];
696 :     }
697 :    
698 :     // Checks whether plane intersects with the ray starting and rayStart and going to rayDir direction.
699 :     // If yes, returns true and sets out to the intersection point
700 :     // Otherwise, returns false
701 :     // tested
702 :     XS_LIBFUNC_ATTRIB bool:xs_plane_rayintersect(const Float:plane[], const Float:rayStart[], const Float:rayDir[], Float:out[])
703 :     {
704 :     new Float:a = xs_vec_dot(plane, rayDir);
705 :    
706 :     if (a == 0.0)
707 :     return false; // ray is parallel to plane
708 :    
709 :     // if (distance plane<->(rayStart + rayDir) > distance plane<->rayStart) and both have the same sign, the ray
710 :     // goes away from the plane
711 :     new Float:rsplusrd[3];
712 :     xs_vec_add(rayStart, rayDir, rsplusrd);
713 :     new Float:dst1 = xs_plane_dst2point(plane, rsplusrd);
714 :     new Float:dst2 = xs_plane_dst2point(plane, rayStart);
715 :     if (xs_fabs(dst1) > xs_fabs(dst2) && xs_fsign(dst1) == xs_fsign(dst2))
716 :     return false;
717 :    
718 :    
719 :     // out = rayStart - rayDir * ((distance plane<->rayStart) / a)
720 :     new Float:__tmp[3];
721 :     xs_vec_mul_scalar(rayDir, xs_plane_dst2point(plane, rayStart) / a, __tmp);
722 :     // out = rayStart - tmp
723 :     xs_vec_sub(rayStart, __tmp, out);
724 :    
725 :     return true;
726 :     }
727 :    
728 :     // Is point on plane?
729 :     // tested
730 :     XS_LIBFUNC_ATTRIB bool:xs_point_onplane(const Float:plane[], const Float:point[])
731 :     {
732 :     return XS_FLEQ(xs_plane_dst2point(plane, point), 0.0);
733 :     }
734 :    
735 :     // Project point on plane
736 :     // tested
737 :     XS_LIBFUNC_ATTRIB xs_projpoint_onplane(const Float:plane[], const Float:point[], Float:out[])
738 :     {
739 :     new Float:__tmp[3];
740 :     // out = point - (plane normal * distance point<->plane)
741 :     xs_vec_copy(plane, __tmp);
742 :     xs_vec_mul_scalar(__tmp, xs_plane_dst2point(plane, point), __tmp);
743 :     xs_vec_sub(point, __tmp, out);
744 :     }
745 :    
746 :     // Copy plane
747 :     // untested, but should work
748 :     XS_LIBFUNC_ATTRIB xs_plane_copy(const Float:planeIn[], Float:planeOut[])
749 :     {
750 :     planeOut[0] = planeIn[0];
751 :     planeOut[1] = planeIn[1];
752 :     planeOut[2] = planeIn[2];
753 :     planeOut[3] = planeIn[3];
754 :     }
755 :    
756 :     /****** HL ENGINE SPECIFIC STUFF ******/
757 :     // Compute forward, right and up vector from angles
758 :     // half-tested
759 :    
760 :     // angle indexes
761 :     #define XS_PITCH 0 // up / down
762 :     #define XS_YAW 1 // left / right
763 :     #define XS_ROLL 2 // fall over
764 :    
765 :     XS_LIBFUNC_ATTRIB xs_anglevectors(const Float:angles[3], Float:fwd[3], Float:right[3], Float:up[3])
766 :     {
767 :     // sin (s) and cos (c) for yaw (y), pitch (p) and roll (r)
768 :     new Float:sr, Float:sp, Float:sy, Float:cr, Float:cp, Float:cy;
769 :    
770 :     sy = xs_sin(angles[XS_YAW], degrees);
771 :     cy = xs_cos(angles[XS_YAW], degrees);
772 :     sp = xs_sin(angles[XS_PITCH], degrees);
773 :     cp = xs_cos(angles[XS_PITCH], degrees);
774 :     sr = xs_sin(angles[XS_ROLL], degrees);
775 :     cr = xs_cos(angles[XS_ROLL], degrees);
776 :    
777 :     fwd[0] = cp*cy;
778 :     fwd[1] = cp*sy;
779 :     fwd[2] = -sp;
780 :    
781 :     right[0] = (-1*sr*sp*cy + -1*cr*-sy);
782 :     right[1] = (-1*sr*sp*sy + -1*cr*cy);
783 :     right[2] = -1*sr*cp;
784 :    
785 :     up[0] = (cr*sp*cy + -sr*-sy);
786 :     up[1] = (cr*sp*sy + -sr*cy);
787 :     up[2] = cr*cp;
788 :     }
789 :     /****** STRING FUNCS *******/
790 :    
791 :     // tested
792 :     XS_LIBFUNC_ATTRIB xs_strchr(const str[], chr)
793 :     {
794 :     for (new i = 0; str[i] != 0; ++i)
795 :     {
796 :     if (str[i] == chr)
797 :     return i;
798 :     }
799 :     return -1;
800 :     }
801 :    
802 :     // by JGHG, adapted
803 :     // removes charstotrim number of charactes from stringtotrim's
804 :     // - beginning if fromleft is true
805 :     // - end if fromleft is false
806 :     // tested
807 :     XS_LIBFUNC_ATTRIB xs_strtrim(stringtotrim[], charstotrim, bool:fromleft = true)
808 :     {
809 :     if (charstotrim <= 0)
810 :     return;
811 :    
812 :     if (fromleft)
813 :     {
814 :     new maxlen = strlen(stringtotrim);
815 :     if (charstotrim > maxlen)
816 :     charstotrim = maxlen;
817 :    
818 :     // In format, input and output regions can overlap
819 :     format(stringtotrim, maxlen, "%s", stringtotrim[charstotrim]);
820 :     }
821 :     else
822 :     {
823 :     new maxlen = strlen(stringtotrim) - charstotrim;
824 :     if (maxlen < 0)
825 :     maxlen = 0;
826 :    
827 :     // In format, input and output regions can overlap
828 :     format(stringtotrim, maxlen, "%s", stringtotrim);
829 :     }
830 :     }
831 :    
832 :     // by xeroblood, adapted
833 :     // copies characters from oldmsg to newmsg, starting at start and ending at end (_includes_ end).
834 :     // terminates newmsg with 0
835 :     // if outlen is positive, it specifies the maximal number of characters to be copied.
836 :     // otherwise, assumes that newmsg is at least end-start+1 characters long.
837 :     // tested
838 :     XS_LIBFUNC_ATTRIB xs_strmid(const oldmsg[], newmsg[], start, end, outlen=-1)
839 :     {
840 :     new len = strlen(oldmsg);
841 :    
842 :     if(start < 0)
843 :     start = 0;
844 :    
845 :     ++end; // Include end
846 :    
847 :     if(end <= start || end > len)
848 :     end = len;
849 :    
850 :     new j = 0, i = start;
851 :     for(; (i < end) && (outlen--);)
852 :     newmsg[j++] = oldmsg[i++];
853 :    
854 :     newmsg[j] = 0;
855 :     }
856 :    
857 :     // by xeroblood, adapted
858 :     // maxelems: maximal number of elements in output, elemsize: maximal size of one element
859 :     // tested
860 :     XS_LIBFUNC_ATTRIB xs_explode(const input[], output[][], delimiter, maxelems, elemsize)
861 :     {
862 :     new nIdx = 0;
863 :     new nLen = 0;
864 :    
865 :     new copied = 0;
866 :     while(nLen < strlen(input) && nIdx < maxelems)
867 :     {
868 :     copied = copyc(output[nIdx++], elemsize, input[nLen], delimiter);
869 :     if (copied == elemsize)
870 :     {
871 :     // maybe it got force-stopped because of maxsize
872 :     // so check whether we have to skip something
873 :     if (input[nLen + copied] != delimiter && input[nLen + copied] != 0)
874 :     {
875 :     new found = xs_strchr(input[nLen + copied], delimiter);
876 :     if (found == -1)
877 :     break;
878 :     copied += found;
879 :     }
880 :     }
881 :    
882 :     nLen += copied + 1; // +1: skip delimiter
883 :     }
884 :     return nIdx;
885 :     }
886 :    
887 :     // returns number of cells written.
888 :     XS_LIBFUNC_ATTRIB xs_implode(output[], outsize, delimiter, const input[][], elemsnum)
889 :     {
890 :     new pos = 0;
891 :     new copied;
892 :     for (new i = 0; i < elemsnum; ++i)
893 :     {
894 :     copied = copy(output[pos], outsize - pos, input[i]);
895 :     pos += copied;
896 :     if (pos >= outsize)
897 :     return outsize;
898 :     // append delimiter
899 :     output[pos] = delimiter;
900 :     ++pos;
901 :     // last check
902 :     if (pos >= outsize)
903 :     return outsize;
904 :     }
905 :    
906 :     output[--pos] = 0; // The last char would be delimiter, so skip it.
907 :     return pos;
908 :     }
909 :    
910 :    
911 :     XS_LIBVAR_ATTRIB xs__replace_buf[XS_REPLACEBUF_SIZE];
912 :     // Replace all occurencies of what in text with with
913 :     // Returns number of (also partially if trimmed by len) replaced items.
914 :     XS_LIBFUNC_ATTRIB xs_replace(text[], len, const what[], const with[])
915 :     {
916 :     new occur = 0;
917 :     new i = 0;
918 :     new bufPos = 0;
919 :     new replaceLen = strlen(with);
920 :     new whatLen = strlen(what);
921 :     for (; text[i]; ++i)
922 :     {
923 :     if (text[i] == what[0])
924 :     {
925 :     new posInWhat=0;
926 :     new j;
927 :     for (j = i; j-i < replaceLen && text[j]; ++j, ++posInWhat)
928 :     {
929 :     if (text[j] != what[posInWhat])
930 :     break;
931 :     }
932 :     if (whatLen == posInWhat)
933 :     {
934 :     for (new i2 = 0; i2 < replaceLen && bufPos < XS_REPLACEBUF_SIZE; ++i2)
935 :     xs__replace_buf[bufPos++] = with[i2];
936 :     i = j - 1;
937 :     ++occur;
938 :     if (bufPos >= XS_REPLACEBUF_SIZE)
939 :     return occur;
940 :     continue;
941 :     }
942 :     }
943 :     if (bufPos >= XS_REPLACEBUF_SIZE)
944 :     return occur;
945 :     xs__replace_buf[bufPos++] = text[i];
946 :     }
947 :     xs__replace_buf[bufPos] = 0;
948 :     copy(text, len, xs__replace_buf);
949 :     return occur;
950 :     }
951 :    
952 :     // replaces all occurencies of what in text with with
953 :     // Returns number of replaced items.
954 :     XS_LIBFUNC_ATTRIB xs_replace_char(text[], len, what, with)
955 :     {
956 :     // let the xs_replace function do the work
957 :     new arr[4];
958 :     arr[0] = what;
959 :     arr[1] = 0;
960 :     arr[2] = with;
961 :     arr[3] = 0;
962 :    
963 :     return xs_replace(text, len, arr[0], arr[2]);
964 :     }
965 :    
966 :     #if XS_PLATFORM == XS_AMX
967 :     // message_begin checking for AMX
968 :     xs__hook_message_begin(dest, msg_type, origin[3]={0,0,0}, player = 0)
969 :     {
970 :     xs_assert(xs_is_msg_valid(msg_type), "message_begin called with bogus message type");
971 :     return message_begin(dest, msg_type, origin, player);
972 :     }
973 :    
974 :     #define message_begin xs__hook_message_begin
975 :     #endif
976 :     /****** MISC FUNCS *******/
977 :     // sets namestr to name of the command identified by cid
978 :     // half-tested
979 :     XS_LIBFUNC_ATTRIB xs_concmd_name(cid, namestr[], namelen)
980 :     {
981 :     new dummy1;
982 :     new dummy2[1];
983 :     get_concmd(cid, namestr, namelen, dummy1, dummy2, 0, 0);
984 :     }
985 :    
986 :     // Checks whether there are at least num free visible slots
987 :     // half-tested
988 :     XS_LIBFUNC_ATTRIB bool:xs_freevisibleslots(num)
989 :     {
990 :     new maxplayers = get_cvar_num("sv_visiblemaxplayers");
991 :     if (maxplayers <= 0)
992 :     maxplayers = get_maxplayers();
993 :    
994 :     return (get_playersnum(1) <= maxplayers-num) ? true : false;
995 :     }
996 :    
997 :     // Returns biggest possible positive number
998 :     XS_LIBVAR_ATTRIB xs__maxnum = 0;
999 :     // tested
1000 :     XS_LIBFUNC_ATTRIB xs_get_maxnum()
1001 :     {
1002 :     if (!xs__maxnum)
1003 :     {
1004 :     // build it
1005 :     xs__maxnum = ((1 << (cellbits - 2)) - 1 ) | (1 << (cellbits - 2));
1006 :     /*
1007 :     new bits = get_cellsize() * 8 - 1;
1008 :     for (new i = 0; i < bits; ++i)
1009 :     xs__maxnum |= 1 << i;
1010 :     */
1011 :     }
1012 :     return xs__maxnum;
1013 :     }
1014 :    
1015 :     // tested
1016 :     XS_LIBFUNC_ATTRIB xs_get_minnum()
1017 :     {
1018 :     return xs_get_maxnum() + 1;
1019 :     }
1020 :    
1021 :    
1022 :     // *** The following two functions were created by Damaged Soul.
1023 :    
1024 :     // Max messages reserved by engine (DO NOT MODIFY)
1025 :     #define XS__MAX_ENGINE_MESSAGES 63
1026 :     // Max possible messages for mod, is 255 really the limit?
1027 :     #define XS__MAX_POSSIBLE_MESSAGES 255
1028 :    
1029 :     // Returns max number of messages for mod
1030 :     XS_LIBFUNC_ATTRIB xs_get_maxmessages()
1031 :     {
1032 :     new name[2];
1033 :    
1034 :     for (new i = XS__MAX_ENGINE_MESSAGES + 1; i <= XS__MAX_POSSIBLE_MESSAGES; i++)
1035 :     if (!get_user_msgname(i, name, 1))
1036 :     return i - 1;
1037 :    
1038 :     return XS__MAX_POSSIBLE_MESSAGES;
1039 :     }
1040 :    
1041 :     // Returns true if msgid is a valid message
1042 :     XS_LIBFUNC_ATTRIB bool:xs_is_msg_valid(msgid)
1043 :     {
1044 :     new name[2];
1045 :     new retval = get_user_msgname(msgid, name, 1);
1046 :    
1047 :     if (msgid < 1 || (msgid > XS__MAX_ENGINE_MESSAGES && !retval))
1048 :     return false;
1049 :    
1050 :     return true;
1051 :     }
1052 :    
1053 :     /****** MANAGED TASKS ******/
1054 :    
1055 :     // ***** managed task ids
1056 :     XS_LIBFUNC_ATTRIB xs_find_freetaskid()
1057 :     {
1058 :     for (new i = 1; i <= XS_TASK_MANAGEDIDS; ++i)
1059 :     {
1060 :     if (!task_exists(i))
1061 :     return i;
1062 :     }
1063 :     return -1;
1064 :     }
1065 :    
1066 :     // ***** managed tasks
1067 :     enum xs_paramtypes
1068 :     {
1069 :     xs_invalid = 0,
1070 :     xs_int,
1071 :     xs_float,
1072 :     xs_string
1073 :     }
1074 :    
1075 :     // new task
1076 :     XS_LIBVAR_ATTRIB xs__TaskParam[ 1 + // number of parameters
1077 :     XS_TASK_MAXPARAMS + // parameter types
1078 :     (XS_TASK_MAXPARAMSIZE char) * XS_TASK_MAXPARAMS]; // space for len + value
1079 :    
1080 :     XS_LIBVAR_ATTRIB Float:xs__TaskInterval = 0.0;
1081 :     XS_LIBVAR_ATTRIB xs__TaskFlags[5];
1082 :     XS_LIBVAR_ATTRIB xs__TaskFunc[48];
1083 :     XS_LIBVAR_ATTRIB xs__TaskId;
1084 :     XS_LIBVAR_ATTRIB xs__TaskRepeat;
1085 :    
1086 :     #define xs__TaskParamCount xs__TaskParam[0]
1087 :     #define xs__TaskParamType[%1] xs__TaskParam[1 + %1]
1088 :    
1089 :     #define xs__TaskParamValue[%1] xs__TaskParam[1 + XS_TASK_MAXPARAMS + (%1 * (XS_TASK_MAXPARAMSIZE char))]
1090 :    
1091 :    
1092 :     // incoming task
1093 :     XS_LIBVAR_ATTRIB xs__ITaskParam[ 1 + // number of parameters
1094 :     XS_TASK_MAXPARAMS + // parameter types
1095 :     (XS_TASK_MAXPARAMSIZE char) * XS_TASK_MAXPARAMS]; // space for len + value
1096 :     XS_LIBVAR_ATTRIB xs__ITaskId;
1097 :    
1098 :     #define xs__ITaskParamCount xs__ITaskParam[0]
1099 :     #define xs__ITaskParamType[%1] xs__ITaskParam[1 + %1]
1100 :    
1101 :     #define xs__ITaskParamValue[%1] xs__ITaskParam[1 + XS_TASK_MAXPARAMS + (%1 * (XS_TASK_MAXPARAMSIZE char))]
1102 :    
1103 :     // tested
1104 :     XS_LIBFUNC_ATTRIB xs_task_begin(Float:interval, const func[], id = 0, const flags[] = "", repeat = 0)
1105 :     {
1106 :     xs_assert(xs__TaskInterval == 0.0, "New xs_task_begin called before xs_task_end");
1107 :    
1108 :     xs__TaskInterval = interval;
1109 :     if (xs__TaskInterval < 0.1)
1110 :     xs__TaskInterval = 0.1;
1111 :    
1112 :     copy(xs__TaskFunc, 47, func);
1113 :     xs__TaskId = id;
1114 :     copy(xs__TaskFlags, 4, flags);
1115 :     xs__TaskRepeat = repeat;
1116 :    
1117 :     xs__TaskParamCount = 0;
1118 :     }
1119 :    
1120 :     // tested
1121 :     XS_LIBFUNC_ATTRIB xs_task_pushint(value, bool:__isfl=false /*internal use only*/)
1122 :     {
1123 :     xs_assert(xs__TaskInterval, "xs_task_push* called without xs_task_begin");
1124 :     if (xs__TaskParamCount >= XS_TASK_MAXPARAMS)
1125 :     return 0;
1126 :    
1127 :     xs__TaskParamType[xs__TaskParamCount] = __isfl ? xs_float : xs_int;
1128 :     xs__TaskParamValue[xs__TaskParamCount] = value;
1129 :    
1130 :     ++xs__TaskParamCount;
1131 :     return 1;
1132 :     }
1133 :    
1134 :     // tested
1135 :     XS_LIBFUNC_ATTRIB xs_task_pushfl(Float:value)
1136 :     {
1137 :     return xs_task_pushint(_:value, true);
1138 :     }
1139 :    
1140 :     // tested
1141 :     XS_LIBFUNC_ATTRIB xs_task_pushstr(const value[])
1142 :     {
1143 :     xs_assert(xs__TaskInterval, "xs_task_push* called without xs_task_begin");
1144 :     if (xs__TaskParamCount >= XS_TASK_MAXPARAMS)
1145 :     return 0;
1146 :    
1147 :     xs__TaskParamType[xs__TaskParamCount] = xs_string;
1148 :     strpack(xs__TaskParamValue[xs__TaskParamCount], value);
1149 :     ++xs__TaskParamCount;
1150 :     return 1;
1151 :     }
1152 :    
1153 :     // tested
1154 :     XS_LIBFUNC_ATTRIB xs_task_end()
1155 :     {
1156 :     xs_assert(xs__TaskInterval, "xs_task_end called without xs_task_begin");
1157 :    
1158 :     // find a task id if needed
1159 :     if (xs__TaskId == -1)
1160 :     {
1161 :     xs__TaskId = xs_find_freetaskid();
1162 :     if (xs__TaskId == -1)
1163 :     {
1164 :     // not found
1165 :     xs__TaskInterval = 0.0;
1166 :     return -1;
1167 :     }
1168 :     }
1169 :    
1170 :     set_task(xs__TaskInterval, xs__TaskFunc, xs__TaskId, xs__TaskParam,
1171 :     1 + xs__TaskParamCount * (XS_TASK_MAXPARAMSIZE char), xs__TaskFlags, xs__TaskRepeat);
1172 :    
1173 :     xs__TaskInterval = 0.0;
1174 :    
1175 :     return xs__TaskId;
1176 :     }
1177 :    
1178 :    
1179 :     // tested
1180 :     #define XS_MAKE_TASKFUNC(%1) public %1(const _xs__taskparam[], _xs__taskid) if(xs__task_setup(_xs__taskparam, _xs__taskid))
1181 :    
1182 :     // tested
1183 :     XS_LIBFUNC_ATTRIB xs__task_setup(const param[], taskid)
1184 :     {
1185 :     xs__ITaskId = taskid;
1186 :     new len = 1 + param[0] * (XS_TASK_MAXPARAMSIZE char);
1187 :     for (new i = 0; i < len; ++i)
1188 :     xs__ITaskParam[i] = param[i];
1189 :     return 1;
1190 :     }
1191 :    
1192 :     // tested
1193 :     XS_LIBFUNC_ATTRIB xs_task_readid()
1194 :     {
1195 :     return xs__ITaskId;
1196 :     }
1197 :    
1198 :     // tested
1199 :     XS_LIBFUNC_ATTRIB xs_task_paramcount()
1200 :     {
1201 :     return xs__ITaskParamCount;
1202 :     }
1203 :    
1204 :     // tested
1205 :     XS_LIBFUNC_ATTRIB xs_paramtypes:xs_task_paramtype(paramid)
1206 :     {
1207 :     if (paramid < 0 || paramid >= xs__ITaskParamCount)
1208 :     return xs_invalid;
1209 :    
1210 :     return xs_paramtypes:xs__ITaskParamType[paramid];
1211 :     }
1212 :    
1213 :     // tested
1214 :     XS_LIBFUNC_ATTRIB xs_task_paramint(paramid)
1215 :     {
1216 :     if (paramid < 0 || paramid >= xs__ITaskParamCount)
1217 :     return 0;
1218 :     if (xs__ITaskParamType[paramid] != _:xs_int)
1219 :     return 0;
1220 :    
1221 :     return xs__ITaskParamValue[paramid];
1222 :     }
1223 :    
1224 :     // tested
1225 :     XS_LIBFUNC_ATTRIB Float:xs_task_paramfl(paramid)
1226 :     {
1227 :     if (paramid < 0 || paramid >= xs__ITaskParamCount)
1228 :     return 0.0;
1229 :     if (xs__ITaskParamType[paramid] != _:xs_float)
1230 :     return 0.0;
1231 :    
1232 :     return Float:xs__ITaskParamValue[paramid];
1233 :     }
1234 :    
1235 :     // tested
1236 :     XS_LIBFUNC_ATTRIB xs_task_paramstr(paramid, out[], maxlen)
1237 :     {
1238 :     #pragma unused maxlen
1239 :    
1240 :     if (paramid < 0 || paramid >= xs__ITaskParamCount)
1241 :     return 0;
1242 :     if (xs__ITaskParamType[paramid] != _:xs_string)
1243 :     return 0;
1244 :    
1245 :     strunpack(out, xs__ITaskParamValue[paramid]);
1246 :     return 1;
1247 :     }
1248 :    
1249 :     #pragma semicolon 0

Contact
ViewVC Help
Powered by ViewVC 1.0.4