1 // checkextension wrapper for log
\r
2 float sqrt(float f); // declared later
\r
3 float exp(float f); // declared later
\r
4 float pow(float f, float e); // declared later
\r
5 float checkextension(string s); // declared later
\r
6 float log_synth(float f)
\r
10 return sqrt(-1); // nan? -inf?
\r
12 return sqrt(-1); // ACTUALLY this should rather be -inf, but we cannot create a +inf in QC
\r
27 // two steps are good enough
\r
28 l = ((6-f) * f - 5) / 4.32808512266689022212;
\r
29 l += exp(-l) * f - 1;
\r
30 l += exp(-l) * f - 1;
\r
35 if(checkextension("DP_QC_LOG"))
\r
36 return log_builtin(f);
\r
38 return log_synth(f);
\r
41 string wordwrap_buffer;
\r
43 void wordwrap_buffer_put(string s)
\r
45 wordwrap_buffer = strcat(wordwrap_buffer, s);
\r
48 string wordwrap(string s, float l)
\r
51 wordwrap_buffer = "";
\r
52 wordwrap_cb(s, l, wordwrap_buffer_put);
\r
53 r = wordwrap_buffer;
\r
54 wordwrap_buffer = "";
\r
60 void wordwrap_buffer_sprint(string s)
\r
62 wordwrap_buffer = strcat(wordwrap_buffer, s);
\r
65 sprint(self, wordwrap_buffer);
\r
66 wordwrap_buffer = "";
\r
70 void wordwrap_sprint(string s, float l)
\r
72 wordwrap_buffer = "";
\r
73 wordwrap_cb(s, l, wordwrap_buffer_sprint);
\r
74 if(wordwrap_buffer != "")
\r
75 sprint(self, strcat(wordwrap_buffer, "\n"));
\r
76 wordwrap_buffer = "";
\r
82 string unescape(string in)
\r
85 local string str, s;
\r
87 // but it doesn't seem to be necessary in my tests at least
\r
92 for(i = 0; i < len; ++i)
\r
94 s = substring(in, i, 1);
\r
97 s = substring(in, i+1, 1);
\r
99 str = strcat(str, "\n");
\r
101 str = strcat(str, "\\");
\r
103 str = strcat(str, substring(in, i, 2));
\r
106 str = strcat(str, s);
\r
113 void wordwrap_cb(string s, float l, void(string) callback)
\r
116 local float lleft, i, j, wlen;
\r
120 for (i = 0;i < strlen(s);++i)
\r
122 if (substring(s, i, 2) == "\\n")
\r
128 else if (substring(s, i, 1) == "\n")
\r
133 else if (substring(s, i, 1) == " ")
\r
143 for (j = i+1;j < strlen(s);++j)
\r
144 // ^^ this skips over the first character of a word, which
\r
145 // is ALWAYS part of the word
\r
146 // this is safe since if i+1 == strlen(s), i will become
\r
147 // strlen(s)-1 at the end of this block and the function
\r
148 // will terminate. A space can't be the first character we
\r
149 // read here, and neither can a \n be the start, since these
\r
150 // two cases have been handled above.
\r
152 c = substring(s, j, 1);
\r
159 // we need to keep this tempstring alive even if substring is
\r
160 // called repeatedly, so call strcat even though we're not
\r
170 callback(substring(s, i, wlen));
\r
171 lleft = lleft - wlen;
\r
178 float dist_point_line(vector p, vector l0, vector ldir)
\r
180 ldir = normalize(ldir);
\r
182 // remove the component in line direction
\r
183 p = p - (p * ldir) * ldir;
\r
185 // vlen of the remaining vector
\r
189 void depthfirst(entity start, .entity up, .entity downleft, .entity right, void(entity, entity) funcPre, void(entity, entity) funcPost, entity pass)
\r
218 float median(float a, float b, float c)
\r
221 return bound(a, b, c);
\r
222 return bound(c, b, a);
\r
225 // converts a number to a string with the indicated number of decimals
\r
226 // works for up to 10 decimals!
\r
227 string ftos_decimals(float number, float decimals)
\r
233 // if negative, cut off the sign first
\r
235 return strcat("-", ftos_decimals(-number, decimals));
\r
236 // it now is always positive!
\r
239 number = floor(number * pow(10, decimals) + 0.5);
\r
242 result = ftos(number);
\r
243 len = strlen(result);
\r
244 // does it have a decimal point (should not happen)? If there is one, it is always at len-7)
\r
245 // if ftos had messed it up, which should never happen: "34278.000000"
\r
247 if(substring(result, len - 7, 1) == ".")
\r
249 dprint("ftos(integer) has comma? Can't be. Affected result: ", result, "\n");
\r
250 result = substring(result, 0, len - 7);
\r
255 return result; // don't insert a point for zero decimals
\r
256 // is it too short? If yes, insert leading zeroes
\r
257 if(len <= decimals)
\r
259 result = strcat(substring("0000000000", 0, decimals - len + 1), result);
\r
260 len = decimals + 1;
\r
262 // and now... INSERT THE POINT!
\r
263 tmp = substring(result, len - decimals, decimals);
\r
264 result = strcat(substring(result, 0, len - decimals), ".", tmp);
\r
269 vector colormapPaletteColor(float c, float isPants)
\r
273 case 0: return '0.800000 0.800000 0.800000';
\r
274 case 1: return '0.600000 0.400000 0.000000';
\r
275 case 2: return '0.000000 1.000000 0.501961';
\r
276 case 3: return '0.000000 1.000000 0.000000';
\r
277 case 4: return '1.000000 0.000000 0.000000';
\r
278 case 5: return '0.000000 0.658824 1.000000';
\r
279 case 6: return '0.000000 1.000000 1.000000';
\r
280 case 7: return '0.501961 1.000000 0.000000';
\r
281 case 8: return '0.501961 0.000000 1.000000';
\r
282 case 9: return '1.000000 0.000000 1.000000';
\r
283 case 10: return '1.000000 0.000000 0.501961';
\r
284 case 11: return '0.600000 0.600000 0.600000';
\r
285 case 12: return '1.000000 1.000000 0.000000';
\r
286 case 13: return '0.000000 0.313725 1.000000';
\r
287 case 14: return '1.000000 0.501961 0.000000';
\r
291 '1 0 0' * (0.502 + 0.498 * sin(time / 2.7182818285 + 0.0000000000))
\r
292 + '0 1 0' * (0.502 + 0.498 * sin(time / 2.7182818285 + 2.0943951024))
\r
293 + '0 0 1' * (0.502 + 0.498 * sin(time / 2.7182818285 + 4.1887902048));
\r
296 '1 0 0' * (0.502 + 0.498 * sin(time / 3.1415926536 + 5.2359877560))
\r
297 + '0 1 0' * (0.502 + 0.498 * sin(time / 3.1415926536 + 3.1415926536))
\r
298 + '0 0 1' * (0.502 + 0.498 * sin(time / 3.1415926536 + 1.0471975512));
\r
299 default: return '0.000 0.000 0.000';
\r
303 // unzone the string, and return it as tempstring. Safe to be called on string_null
\r
304 string fstrunzone(string s)
\r
309 sc = strcat(s, "");
\r
314 // Databases (hash tables)
\r
315 #define DB_BUCKETS 8192
\r
316 void db_save(float db, string pFilename)
\r
319 fh = fopen(pFilename, FILE_WRITE);
\r
322 print(strcat("^1Can't write DB to ", pFilename));
\r
325 n = buf_getsize(db);
\r
326 fputs(fh, strcat(ftos(DB_BUCKETS), "\n"));
\r
327 for(i = 0; i < n; ++i)
\r
328 fputs(fh, strcat(bufstr_get(db, i), "\n"));
\r
334 return buf_create();
\r
337 float db_load(string pFilename)
\r
339 float db, fh, i, j, n;
\r
344 fh = fopen(pFilename, FILE_READ);
\r
347 if(stof(fgets(fh)) == DB_BUCKETS)
\r
350 while((l = fgets(fh)))
\r
353 bufstr_set(db, i, l);
\r
359 // different count of buckets?
\r
360 // need to reorganize the database then (SLOW)
\r
361 while((l = fgets(fh)))
\r
363 n = tokenizebyseparator(l, "\\");
\r
364 for(j = 2; j < n; j += 2)
\r
365 db_put(db, argv(j-1), uri_unescape(argv(j)));
\r
372 void db_dump(float db, string pFilename)
\r
374 float fh, i, j, n, m;
\r
375 fh = fopen(pFilename, FILE_WRITE);
\r
377 error(strcat("Can't dump DB to ", pFilename));
\r
378 n = buf_getsize(db);
\r
380 for(i = 0; i < n; ++i)
\r
382 m = tokenizebyseparator(bufstr_get(db, i), "\\");
\r
383 for(j = 2; j < m; j += 2)
\r
384 fputs(fh, strcat("\\", argv(j-1), "\\", argv(j), "\n"));
\r
389 void db_close(float db)
\r
394 string db_get(float db, string pKey)
\r
397 h = mod(crc16(FALSE, pKey), DB_BUCKETS);
\r
398 return uri_unescape(infoget(bufstr_get(db, h), pKey));
\r
401 void db_put(float db, string pKey, string pValue)
\r
404 h = mod(crc16(FALSE, pKey), DB_BUCKETS);
\r
405 bufstr_set(db, h, infoadd(bufstr_get(db, h), pKey, uri_escape(pValue)));
\r
411 print("LOAD...\n");
\r
412 db = db_load("foo.db");
\r
413 print("LOADED. FILL...\n");
\r
414 for(i = 0; i < DB_BUCKETS; ++i)
\r
415 db_put(db, ftos(random()), "X");
\r
416 print("FILLED. SAVE...\n");
\r
417 db_save(db, "foo.db");
\r
418 print("SAVED. CLOSE...\n");
\r
420 print("CLOSED.\n");
\r
423 // Multiline text file buffers
\r
424 float buf_load(string pFilename)
\r
428 buf = buf_create();
\r
431 fh = fopen(pFilename, FILE_READ);
\r
435 while((l = fgets(fh)))
\r
437 bufstr_set(buf, i, l);
\r
444 void buf_save(float buf, string pFilename)
\r
447 fh = fopen(pFilename, FILE_WRITE);
\r
449 error(strcat("Can't write buf to ", pFilename));
\r
450 n = buf_getsize(buf);
\r
451 for(i = 0; i < n; ++i)
\r
452 fputs(fh, strcat(bufstr_get(buf, i), "\n"));
\r
456 string GametypeNameFromType(float g)
\r
458 if (g == GAME_DEATHMATCH) return "dm";
\r
459 else if (g == GAME_TEAM_DEATHMATCH) return "tdm";
\r
460 else if (g == GAME_DOMINATION) return "dom";
\r
461 else if (g == GAME_CTF) return "ctf";
\r
462 else if (g == GAME_LMS) return "lms";
\r
463 else if (g == GAME_ARENA) return "arena";
\r
464 else if (g == GAME_CA) return "ca";
\r
465 else if (g == GAME_KEYHUNT) return "kh";
\r
466 else if (g == GAME_ONSLAUGHT) return "ons";
\r
467 else if (g == GAME_ASSAULT) return "as";
\r
468 else if (g == GAME_RACE) return "rc";
\r
469 else if (g == GAME_CTS) return "cts";
\r
470 else if (g == GAME_RPG) return "rpg";
\r
474 string mmsss(float tenths)
\r
478 tenths = floor(tenths + 0.5);
\r
479 minutes = floor(tenths / 600);
\r
480 tenths -= minutes * 600;
\r
481 s = ftos(1000 + tenths);
\r
482 return strcat(ftos(minutes), ":", substring(s, 1, 2), ".", substring(s, 3, 1));
\r
485 string mmssss(float hundredths)
\r
489 hundredths = floor(hundredths + 0.5);
\r
490 minutes = floor(hundredths / 6000);
\r
491 hundredths -= minutes * 6000;
\r
492 s = ftos(10000 + hundredths);
\r
493 return strcat(ftos(minutes), ":", substring(s, 1, 2), ".", substring(s, 3, 2));
\r
496 string ScoreString(float pFlags, float pValue)
\r
501 pValue = floor(pValue + 0.5); // round
\r
503 if((pValue == 0) && (pFlags & (SFL_HIDE_ZERO | SFL_RANK | SFL_TIME)))
\r
505 else if(pFlags & SFL_RANK)
\r
507 valstr = ftos(pValue);
\r
508 l = strlen(valstr);
\r
509 if((l >= 2) && (substring(valstr, l - 2, 1) == "1"))
\r
510 valstr = strcat(valstr, "th");
\r
511 else if(substring(valstr, l - 1, 1) == "1")
\r
512 valstr = strcat(valstr, "st");
\r
513 else if(substring(valstr, l - 1, 1) == "2")
\r
514 valstr = strcat(valstr, "nd");
\r
515 else if(substring(valstr, l - 1, 1) == "3")
\r
516 valstr = strcat(valstr, "rd");
\r
518 valstr = strcat(valstr, "th");
\r
520 else if(pFlags & SFL_TIME)
\r
521 valstr = TIME_ENCODED_TOSTRING(pValue);
\r
523 valstr = ftos(pValue);
\r
528 vector cross(vector a, vector b)
\r
531 '1 0 0' * (a_y * b_z - a_z * b_y)
\r
532 + '0 1 0' * (a_z * b_x - a_x * b_z)
\r
533 + '0 0 1' * (a_x * b_y - a_y * b_x);
\r
536 // compressed vector format:
\r
537 // like MD3, just even shorter
\r
538 // 4 bit pitch (16 angles), 0 is -90, 8 is 0, 16 would be 90
\r
539 // 5 bit yaw (32 angles), 0=0, 8=90, 16=180, 24=270
\r
540 // 7 bit length (logarithmic encoding), 1/8 .. about 7844
\r
541 // length = 2^(length_encoded/8) / 8
\r
542 // if pitch is 90, yaw does nothing and therefore indicates the sign (yaw is then either 11111 or 11110); 11111 is pointing DOWN
\r
543 // thus, valid values are from 0000.11110.0000000 to 1111.11111.1111111
\r
544 // the special value 0 indicates the zero vector
\r
546 float lengthLogTable[128];
\r
548 float invertLengthLog(float x)
\r
550 float l, r, m, lerr, rerr;
\r
552 if(x >= lengthLogTable[127])
\r
554 if(x <= lengthLogTable[0])
\r
562 m = floor((l + r) / 2);
\r
563 if(lengthLogTable[m] < x)
\r
569 // now: r is >=, l is <
\r
570 lerr = (x - lengthLogTable[l]);
\r
571 rerr = (lengthLogTable[r] - x);
\r
577 vector decompressShortVector(float data)
\r
580 float pitch, yaw, len;
\r
583 pitch = (data & 0xF000) / 0x1000;
\r
584 yaw = (data & 0x0F80) / 0x80;
\r
585 len = (data & 0x007F);
\r
587 //print("\ndecompress: pitch ", ftos(pitch)); print("yaw ", ftos(yaw)); print("len ", ftos(len), "\n");
\r
600 yaw = .19634954084936207740 * yaw;
\r
601 pitch = .19634954084936207740 * pitch - 1.57079632679489661922;
\r
602 out_x = cos(yaw) * cos(pitch);
\r
603 out_y = sin(yaw) * cos(pitch);
\r
604 out_z = -sin(pitch);
\r
607 //print("decompressed: ", vtos(out), "\n");
\r
609 return out * lengthLogTable[len];
\r
612 float compressShortVector(vector vec)
\r
615 float pitch, yaw, len;
\r
618 //print("compress: ", vtos(vec), "\n");
\r
619 ang = vectoangles(vec);
\r
623 if(ang_x < -90 && ang_x > +90)
\r
624 error("BOGUS vectoangles");
\r
625 //print("angles: ", vtos(ang), "\n");
\r
627 pitch = floor(0.5 + (ang_x + 90) * 16 / 180) & 15; // -90..90 to 0..14
\r
636 yaw = floor(0.5 + ang_y * 32 / 360) & 31; // 0..360 to 0..32
\r
637 len = invertLengthLog(vlen(vec));
\r
639 //print("compressed: pitch ", ftos(pitch)); print("yaw ", ftos(yaw)); print("len ", ftos(len), "\n");
\r
641 return (pitch * 0x1000) + (yaw * 0x80) + len;
\r
644 void compressShortVector_init()
\r
649 for(i = 0; i < 128; ++i)
\r
651 lengthLogTable[i] = l;
\r
655 if(cvar("developer"))
\r
657 print("Verifying vector compression table...\n");
\r
658 for(i = 0x0F00; i < 0xFFFF; ++i)
\r
659 if(i != compressShortVector(decompressShortVector(i)))
\r
661 print("BROKEN vector compression: ", ftos(i));
\r
662 print(" -> ", vtos(decompressShortVector(i)));
\r
663 print(" -> ", ftos(compressShortVector(decompressShortVector(i))));
\r
672 float CheckWireframeBox(entity forent, vector v0, vector dvx, vector dvy, vector dvz)
\r
674 traceline(v0, v0 + dvx, TRUE, forent); if(trace_fraction < 1) return 0;
\r
675 traceline(v0, v0 + dvy, TRUE, forent); if(trace_fraction < 1) return 0;
\r
676 traceline(v0, v0 + dvz, TRUE, forent); if(trace_fraction < 1) return 0;
\r
677 traceline(v0 + dvx, v0 + dvx + dvy, TRUE, forent); if(trace_fraction < 1) return 0;
\r
678 traceline(v0 + dvx, v0 + dvx + dvz, TRUE, forent); if(trace_fraction < 1) return 0;
\r
679 traceline(v0 + dvy, v0 + dvy + dvx, TRUE, forent); if(trace_fraction < 1) return 0;
\r
680 traceline(v0 + dvy, v0 + dvy + dvz, TRUE, forent); if(trace_fraction < 1) return 0;
\r
681 traceline(v0 + dvz, v0 + dvz + dvx, TRUE, forent); if(trace_fraction < 1) return 0;
\r
682 traceline(v0 + dvz, v0 + dvz + dvy, TRUE, forent); if(trace_fraction < 1) return 0;
\r
683 traceline(v0 + dvx + dvy, v0 + dvx + dvy + dvz, TRUE, forent); if(trace_fraction < 1) return 0;
\r
684 traceline(v0 + dvx + dvz, v0 + dvx + dvy + dvz, TRUE, forent); if(trace_fraction < 1) return 0;
\r
685 traceline(v0 + dvy + dvz, v0 + dvx + dvy + dvz, TRUE, forent); if(trace_fraction < 1) return 0;
\r
690 string fixPriorityList(string order, float from, float to, float subtract, float complete)
\r
695 n = tokenize_console(order);
\r
697 for(i = 0; i < n; ++i)
\r
702 if(w >= from && w <= to)
\r
703 neworder = strcat(neworder, ftos(w), " ");
\r
707 if(w >= from && w <= to)
\r
708 neworder = strcat(neworder, ftos(w), " ");
\r
715 n = tokenize_console(neworder);
\r
716 for(w = to; w >= from; --w)
\r
718 for(i = 0; i < n; ++i)
\r
719 if(stof(argv(i)) == w)
\r
721 if(i == n) // not found
\r
722 neworder = strcat(neworder, ftos(w), " ");
\r
726 return substring(neworder, 0, strlen(neworder) - 1);
\r
729 string mapPriorityList(string order, string(string) mapfunc)
\r
734 n = tokenize_console(order);
\r
736 for(i = 0; i < n; ++i)
\r
737 neworder = strcat(neworder, mapfunc(argv(i)), " ");
\r
739 return substring(neworder, 0, strlen(neworder) - 1);
\r
742 string swapInPriorityList(string order, float i, float j)
\r
747 n = tokenize_console(order);
\r
749 if(i >= 0 && i < n && j >= 0 && j < n && i != j)
\r
752 for(w = 0; w < n; ++w)
\r
755 s = strcat(s, argv(j), " ");
\r
757 s = strcat(s, argv(i), " ");
\r
759 s = strcat(s, argv(w), " ");
\r
761 return substring(s, 0, strlen(s) - 1);
\r
767 float cvar_value_issafe(string s)
\r
769 if(strstrofs(s, "\"", 0) >= 0)
\r
771 if(strstrofs(s, "\\", 0) >= 0)
\r
773 if(strstrofs(s, ";", 0) >= 0)
\r
775 if(strstrofs(s, "$", 0) >= 0)
\r
777 if(strstrofs(s, "\r", 0) >= 0)
\r
779 if(strstrofs(s, "\n", 0) >= 0)
\r
785 void get_mi_min_max(float mode)
\r
790 strunzone(mi_shortname);
\r
791 mi_shortname = mapname;
\r
792 if(!strcasecmp(substring(mi_shortname, 0, 5), "maps/"))
\r
793 mi_shortname = substring(mi_shortname, 5, strlen(mi_shortname) - 5);
\r
794 if(!strcasecmp(substring(mi_shortname, strlen(mi_shortname) - 4, 4), ".bsp"))
\r
795 mi_shortname = substring(mi_shortname, 0, strlen(mi_shortname) - 4);
\r
796 mi_shortname = strzone(mi_shortname);
\r
808 MapInfo_Get_ByName(mi_shortname, 0, 0);
\r
809 if(MapInfo_Map_mins_x < MapInfo_Map_maxs_x)
\r
811 mi_min = MapInfo_Map_mins;
\r
812 mi_max = MapInfo_Map_maxs;
\r
820 tracebox('1 0 0' * mi_x,
\r
821 '0 1 0' * mi_y + '0 0 1' * mi_z,
\r
822 '0 1 0' * ma_y + '0 0 1' * ma_z,
\r
826 if(!trace_startsolid)
\r
827 mi_min_x = trace_endpos_x;
\r
829 tracebox('0 1 0' * mi_y,
\r
830 '1 0 0' * mi_x + '0 0 1' * mi_z,
\r
831 '1 0 0' * ma_x + '0 0 1' * ma_z,
\r
835 if(!trace_startsolid)
\r
836 mi_min_y = trace_endpos_y;
\r
838 tracebox('0 0 1' * mi_z,
\r
839 '1 0 0' * mi_x + '0 1 0' * mi_y,
\r
840 '1 0 0' * ma_x + '0 1 0' * ma_y,
\r
844 if(!trace_startsolid)
\r
845 mi_min_z = trace_endpos_z;
\r
847 tracebox('1 0 0' * ma_x,
\r
848 '0 1 0' * mi_y + '0 0 1' * mi_z,
\r
849 '0 1 0' * ma_y + '0 0 1' * ma_z,
\r
853 if(!trace_startsolid)
\r
854 mi_max_x = trace_endpos_x;
\r
856 tracebox('0 1 0' * ma_y,
\r
857 '1 0 0' * mi_x + '0 0 1' * mi_z,
\r
858 '1 0 0' * ma_x + '0 0 1' * ma_z,
\r
862 if(!trace_startsolid)
\r
863 mi_max_y = trace_endpos_y;
\r
865 tracebox('0 0 1' * ma_z,
\r
866 '1 0 0' * mi_x + '0 1 0' * mi_y,
\r
867 '1 0 0' * ma_x + '0 1 0' * ma_y,
\r
871 if(!trace_startsolid)
\r
872 mi_max_z = trace_endpos_z;
\r
877 void get_mi_min_max_texcoords(float mode)
\r
881 get_mi_min_max(mode);
\r
883 mi_picmin = mi_min;
\r
884 mi_picmax = mi_max;
\r
886 // extend mi_picmax to get a square aspect ratio
\r
887 // center the map in that area
\r
888 extend = mi_picmax - mi_picmin;
\r
889 if(extend_y > extend_x)
\r
891 mi_picmin_x -= (extend_y - extend_x) * 0.5;
\r
892 mi_picmax_x += (extend_y - extend_x) * 0.5;
\r
896 mi_picmin_y -= (extend_x - extend_y) * 0.5;
\r
897 mi_picmax_y += (extend_x - extend_y) * 0.5;
\r
900 // add another some percent
\r
901 extend = (mi_picmax - mi_picmin) * (1 / 64.0);
\r
902 mi_picmin -= extend;
\r
903 mi_picmax += extend;
\r
905 // calculate the texcoords
\r
906 mi_pictexcoord0 = mi_pictexcoord1 = mi_pictexcoord2 = mi_pictexcoord3 = '0 0 0';
\r
907 // first the two corners of the origin
\r
908 mi_pictexcoord0_x = (mi_min_x - mi_picmin_x) / (mi_picmax_x - mi_picmin_x);
\r
909 mi_pictexcoord0_y = (mi_min_y - mi_picmin_y) / (mi_picmax_y - mi_picmin_y);
\r
910 mi_pictexcoord2_x = (mi_max_x - mi_picmin_x) / (mi_picmax_x - mi_picmin_x);
\r
911 mi_pictexcoord2_y = (mi_max_y - mi_picmin_y) / (mi_picmax_y - mi_picmin_y);
\r
912 // then the other corners
\r
913 mi_pictexcoord1_x = mi_pictexcoord0_x;
\r
914 mi_pictexcoord1_y = mi_pictexcoord2_y;
\r
915 mi_pictexcoord3_x = mi_pictexcoord2_x;
\r
916 mi_pictexcoord3_y = mi_pictexcoord0_y;
\r
921 void cvar_settemp(string pKey, string pValue)
\r
923 error("cvar_settemp called from CSQC - use cvar_clientsettemp instead!");
\r
925 void cvar_settemp_restore()
\r
927 error("cvar_settemp_restore called from CSQC - use cvar_clientsettemp instead!");
\r
930 void cvar_settemp(string pKey, string pValue)
\r
933 string settemp_var;
\r
934 if(cvar_string(pKey) == pValue)
\r
936 i = cvar("settemp_idx");
\r
937 cvar_set("settemp_idx", ftos(i+1));
\r
938 settemp_var = strcat("_settemp_x", ftos(i));
\r
940 registercvar(settemp_var, "", 0);
\r
942 registercvar(settemp_var, "");
\r
944 cvar_set("settemp_list", strcat("1 ", pKey, " ", settemp_var, " ", cvar_string("settemp_list")));
\r
945 cvar_set(settemp_var, cvar_string(pKey));
\r
946 cvar_set(pKey, pValue);
\r
949 void cvar_settemp_restore()
\r
951 // undo what cvar_settemp did
\r
953 n = tokenize_console(cvar_string("settemp_list"));
\r
954 for(i = 0; i < n - 3; i += 3)
\r
955 cvar_set(argv(i + 1), cvar_string(argv(i + 2)));
\r
956 cvar_set("settemp_list", "0");
\r
960 float almost_equals(float a, float b)
\r
963 eps = (max(a, -a) + max(b, -b)) * 0.001;
\r
964 if(a - b < eps && b - a < eps)
\r
969 float almost_in_bounds(float a, float b, float c)
\r
972 eps = (max(a, -a) + max(c, -c)) * 0.001;
\r
973 return b == median(a - eps, b, c + eps);
\r
976 float power2of(float e)
\r
980 float log2of(float x)
\r
982 // NOTE: generated code
\r
1055 float rgb_mi_ma_to_hue(vector rgb, float mi, float ma)
\r
1059 else if(ma == rgb_x)
\r
1061 if(rgb_y >= rgb_z)
\r
1062 return (rgb_y - rgb_z) / (ma - mi);
\r
1064 return (rgb_y - rgb_z) / (ma - mi) + 6;
\r
1066 else if(ma == rgb_y)
\r
1067 return (rgb_z - rgb_x) / (ma - mi) + 2;
\r
1068 else // if(ma == rgb_z)
\r
1069 return (rgb_x - rgb_y) / (ma - mi) + 4;
\r
1072 vector hue_mi_ma_to_rgb(float hue, float mi, float ma)
\r
1076 hue -= 6 * floor(hue / 6);
\r
1078 //else if(ma == rgb_x)
\r
1079 // hue = 60 * (rgb_y - rgb_z) / (ma - mi);
\r
1083 rgb_y = hue * (ma - mi) + mi;
\r
1086 //else if(ma == rgb_y)
\r
1087 // hue = 60 * (rgb_z - rgb_x) / (ma - mi) + 120;
\r
1090 rgb_x = (2 - hue) * (ma - mi) + mi;
\r
1098 rgb_z = (hue - 2) * (ma - mi) + mi;
\r
1100 //else // if(ma == rgb_z)
\r
1101 // hue = 60 * (rgb_x - rgb_y) / (ma - mi) + 240;
\r
1105 rgb_y = (4 - hue) * (ma - mi) + mi;
\r
1110 rgb_x = (hue - 4) * (ma - mi) + mi;
\r
1114 //else if(ma == rgb_x)
\r
1115 // hue = 60 * (rgb_y - rgb_z) / (ma - mi);
\r
1116 else // if(hue <= 6)
\r
1120 rgb_z = (6 - hue) * (ma - mi) + mi;
\r
1126 vector rgb_to_hsv(vector rgb)
\r
1131 mi = min3(rgb_x, rgb_y, rgb_z);
\r
1132 ma = max3(rgb_x, rgb_y, rgb_z);
\r
1134 hsv_x = rgb_mi_ma_to_hue(rgb, mi, ma);
\r
1140 hsv_y = 1 - mi/ma;
\r
1145 vector hsv_to_rgb(vector hsv)
\r
1147 return hue_mi_ma_to_rgb(hsv_x, hsv_z * (1 - hsv_y), hsv_z);
\r
1150 vector rgb_to_hsl(vector rgb)
\r
1155 mi = min3(rgb_x, rgb_y, rgb_z);
\r
1156 ma = max3(rgb_x, rgb_y, rgb_z);
\r
1158 hsl_x = rgb_mi_ma_to_hue(rgb, mi, ma);
\r
1160 hsl_z = 0.5 * (mi + ma);
\r
1163 else if(hsl_z <= 0.5)
\r
1164 hsl_y = (ma - mi) / (2*hsl_z);
\r
1165 else // if(hsl_z > 0.5)
\r
1166 hsl_y = (ma - mi) / (2 - 2*hsl_z);
\r
1171 vector hsl_to_rgb(vector hsl)
\r
1173 float mi, ma, maminusmi;
\r
1176 maminusmi = hsl_y * 2 * hsl_z;
\r
1178 maminusmi = hsl_y * (2 - 2 * hsl_z);
\r
1180 // hsl_z = 0.5 * mi + 0.5 * ma
\r
1181 // maminusmi = - mi + ma
\r
1182 mi = hsl_z - 0.5 * maminusmi;
\r
1183 ma = hsl_z + 0.5 * maminusmi;
\r
1185 return hue_mi_ma_to_rgb(hsl_x, mi, ma);
\r
1188 string rgb_to_hexcolor(vector rgb)
\r
1193 DEC_TO_HEXDIGIT(floor(rgb_x * 15 + 0.5)),
\r
1194 DEC_TO_HEXDIGIT(floor(rgb_y * 15 + 0.5)),
\r
1195 DEC_TO_HEXDIGIT(floor(rgb_z * 15 + 0.5))
\r
1199 // requires that m2>m1 in all coordinates, and that m4>m3
\r
1200 float boxesoverlap(vector m1, vector m2, vector m3, vector m4) {return m2_x >= m3_x && m1_x <= m4_x && m2_y >= m3_y && m1_y <= m4_y && m2_z >= m3_z && m1_z <= m4_z;};
\r
1202 // requires the same, but is a stronger condition
\r
1203 float boxinsidebox(vector smins, vector smaxs, vector bmins, vector bmaxs) {return smins_x >= bmins_x && smaxs_x <= bmaxs_x && smins_y >= bmins_y && smaxs_y <= bmaxs_y && smins_z >= bmins_z && smaxs_z <= bmaxs_z;};
\r
1208 float textLengthUpToWidth(string theText, float maxWidth, vector theSize, textLengthUpToWidth_widthFunction_t w)
\r
1210 float ICanHasKallerz;
\r
1212 // detect color codes support in the width function
\r
1213 ICanHasKallerz = (w("^7", theSize) == 0);
\r
1216 // The following function is SLOW.
\r
1217 // For your safety and for the protection of those around you...
\r
1218 // DO NOT CALL THIS AT HOME.
\r
1219 // No really, don't.
\r
1220 if(w(theText, theSize) <= maxWidth)
\r
1221 return strlen(theText); // yeah!
\r
1223 // binary search for right place to cut string
\r
1225 float left, right, middle; // this always works
\r
1227 right = strlen(theText); // this always fails
\r
1230 middle = floor((left + right) / 2);
\r
1231 if(w(substring(theText, 0, middle), theSize) <= maxWidth)
\r
1236 while(left < right - 1);
\r
1238 if(ICanHasKallerz)
\r
1240 // NOTE: when color codes are involved, this binary search is,
\r
1241 // mathematically, BROKEN. However, it is obviously guaranteed to
\r
1242 // terminate, as the range still halves each time - but nevertheless, it is
\r
1243 // guaranteed that it finds ONE valid cutoff place (where "left" is in
\r
1244 // range, and "right" is outside).
\r
1246 // terencehill: the following code detects truncated ^xrgb tags (e.g. ^x or ^x4)
\r
1247 // and decrease left on the basis of the chars detected of the truncated tag
\r
1248 // Even if the ^xrgb tag is not complete/correct, left is decreased
\r
1249 // (sometimes too much but with a correct result)
\r
1250 // it fixes also ^[0-9]
\r
1251 while(left >= 1 && substring(theText, left-1, 1) == "^")
\r
1254 if (left >= 2 && substring(theText, left-2, 2) == "^x") // ^x/
\r
1256 else if (left >= 3 && substring(theText, left-3, 2) == "^x")
\r
1258 ch = str2chr(theText, left-1);
\r
1259 if( (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F') ) // ^xr/
\r
1262 else if (left >= 4 && substring(theText, left-4, 2) == "^x")
\r
1264 ch = str2chr(theText, left-2);
\r
1265 if ( (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F') )
\r
1267 ch = str2chr(theText, left-1);
\r
1268 if ( (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F') ) // ^xrg/
\r
1277 float textLengthUpToLength(string theText, float maxWidth, textLengthUpToLength_lenFunction_t w)
\r
1279 float ICanHasKallerz;
\r
1281 // detect color codes support in the width function
\r
1282 ICanHasKallerz = (w("^7") == 0);
\r
1285 // The following function is SLOW.
\r
1286 // For your safety and for the protection of those around you...
\r
1287 // DO NOT CALL THIS AT HOME.
\r
1288 // No really, don't.
\r
1289 if(w(theText) <= maxWidth)
\r
1290 return strlen(theText); // yeah!
\r
1292 // binary search for right place to cut string
\r
1294 float left, right, middle; // this always works
\r
1296 right = strlen(theText); // this always fails
\r
1299 middle = floor((left + right) / 2);
\r
1300 if(w(substring(theText, 0, middle)) <= maxWidth)
\r
1305 while(left < right - 1);
\r
1307 if(ICanHasKallerz)
\r
1309 // NOTE: when color codes are involved, this binary search is,
\r
1310 // mathematically, BROKEN. However, it is obviously guaranteed to
\r
1311 // terminate, as the range still halves each time - but nevertheless, it is
\r
1312 // guaranteed that it finds ONE valid cutoff place (where "left" is in
\r
1313 // range, and "right" is outside).
\r
1315 // terencehill: the following code detects truncated ^xrgb tags (e.g. ^x or ^x4)
\r
1316 // and decrease left on the basis of the chars detected of the truncated tag
\r
1317 // Even if the ^xrgb tag is not complete/correct, left is decreased
\r
1318 // (sometimes too much but with a correct result)
\r
1319 // it fixes also ^[0-9]
\r
1320 while(left >= 1 && substring(theText, left-1, 1) == "^")
\r
1323 if (left >= 2 && substring(theText, left-2, 2) == "^x") // ^x/
\r
1325 else if (left >= 3 && substring(theText, left-3, 2) == "^x")
\r
1327 ch = str2chr(theText, left-1);
\r
1328 if( (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F') ) // ^xr/
\r
1331 else if (left >= 4 && substring(theText, left-4, 2) == "^x")
\r
1333 ch = str2chr(theText, left-2);
\r
1334 if ( (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F') )
\r
1336 ch = str2chr(theText, left-1);
\r
1337 if ( (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F') ) // ^xrg/
\r
1346 string getWrappedLine(float w, vector theFontSize, textLengthUpToWidth_widthFunction_t tw)
\r
1352 s = getWrappedLine_remaining;
\r
1354 cantake = textLengthUpToWidth(s, w, theFontSize, tw);
\r
1355 if(cantake > 0 && cantake < strlen(s))
\r
1357 take = cantake - 1;
\r
1358 while(take > 0 && substring(s, take, 1) != " ")
\r
1362 getWrappedLine_remaining = substring(s, cantake, strlen(s) - cantake);
\r
1363 if(getWrappedLine_remaining == "")
\r
1364 getWrappedLine_remaining = string_null;
\r
1365 return substring(s, 0, cantake);
\r
1369 getWrappedLine_remaining = substring(s, take + 1, strlen(s) - take);
\r
1370 if(getWrappedLine_remaining == "")
\r
1371 getWrappedLine_remaining = string_null;
\r
1372 return substring(s, 0, take);
\r
1377 getWrappedLine_remaining = string_null;
\r
1382 string getWrappedLineLen(float w, textLengthUpToLength_lenFunction_t tw)
\r
1388 s = getWrappedLine_remaining;
\r
1390 cantake = textLengthUpToLength(s, w, tw);
\r
1391 if(cantake > 0 && cantake < strlen(s))
\r
1393 take = cantake - 1;
\r
1394 while(take > 0 && substring(s, take, 1) != " ")
\r
1398 getWrappedLine_remaining = substring(s, cantake, strlen(s) - cantake);
\r
1399 if(getWrappedLine_remaining == "")
\r
1400 getWrappedLine_remaining = string_null;
\r
1401 return substring(s, 0, cantake);
\r
1405 getWrappedLine_remaining = substring(s, take + 1, strlen(s) - take);
\r
1406 if(getWrappedLine_remaining == "")
\r
1407 getWrappedLine_remaining = string_null;
\r
1408 return substring(s, 0, take);
\r
1413 getWrappedLine_remaining = string_null;
\r
1418 string textShortenToWidth(string theText, float maxWidth, vector theFontSize, textLengthUpToWidth_widthFunction_t tw)
\r
1420 if(tw(theText, theFontSize) <= maxWidth)
\r
1423 return strcat(substring(theText, 0, textLengthUpToWidth(theText, maxWidth - tw("...", theFontSize), theFontSize, tw)), "...");
\r
1426 string textShortenToLength(string theText, float maxWidth, textLengthUpToLength_lenFunction_t tw)
\r
1428 if(tw(theText) <= maxWidth)
\r
1431 return strcat(substring(theText, 0, textLengthUpToLength(theText, maxWidth - tw("..."), tw)), "...");
\r
1434 float isGametypeInFilter(float gt, float tp, string pattern)
\r
1436 string subpattern, subpattern2, subpattern3;
\r
1437 subpattern = strcat(",", GametypeNameFromType(gt), ",");
\r
1439 subpattern2 = ",teams,";
\r
1441 subpattern2 = ",noteams,";
\r
1442 if(gt == GAME_RACE || gt == GAME_CTS)
\r
1443 subpattern3 = ",race,";
\r
1445 subpattern3 = string_null;
\r
1447 if(substring(pattern, 0, 1) == "-")
\r
1449 pattern = substring(pattern, 1, strlen(pattern) - 1);
\r
1450 if(strstrofs(strcat(",", pattern, ","), subpattern, 0) >= 0)
\r
1452 if(strstrofs(strcat(",", pattern, ","), subpattern2, 0) >= 0)
\r
1454 if(subpattern3 && strstrofs(strcat(",", pattern, ","), subpattern3, 0) >= 0)
\r
1459 if(substring(pattern, 0, 1) == "+")
\r
1460 pattern = substring(pattern, 1, strlen(pattern) - 1);
\r
1461 if(strstrofs(strcat(",", pattern, ","), subpattern, 0) < 0)
\r
1462 if(strstrofs(strcat(",", pattern, ","), subpattern2, 0) < 0)
\r
1463 if((!subpattern3) || strstrofs(strcat(",", pattern, ","), subpattern3, 0) < 0)
\r
1469 void shuffle(float n, swapfunc_t swap, entity pass)
\r
1472 for(i = 1; i < n; ++i)
\r
1474 // swap i-th item at a random position from 0 to i
\r
1475 // proof for even distribution:
\r
1478 // item n+1 gets at any position with chance 1/(n+1)
\r
1479 // all others will get their 1/n chance reduced by factor n/(n+1)
\r
1480 // to be on place n+1, their chance will be 1/(n+1)
\r
1481 // 1/n * n/(n+1) = 1/(n+1)
\r
1483 j = floor(random() * (i + 1));
\r
1489 string substring_range(string s, float b, float e)
\r
1491 return substring(s, b, e - b);
\r
1494 string swapwords(string str, float i, float j)
\r
1497 string s1, s2, s3, s4, s5;
\r
1498 float si, ei, sj, ej, s0, en;
\r
1499 n = tokenizebyseparator(str, " "); // must match g_maplist processing in ShuffleMaplist and "shuffle"
\r
1500 si = argv_start_index(i);
\r
1501 sj = argv_start_index(j);
\r
1502 ei = argv_end_index(i);
\r
1503 ej = argv_end_index(j);
\r
1504 s0 = argv_start_index(0);
\r
1505 en = argv_end_index(n-1);
\r
1506 s1 = substring_range(str, s0, si);
\r
1507 s2 = substring_range(str, si, ei);
\r
1508 s3 = substring_range(str, ei, sj);
\r
1509 s4 = substring_range(str, sj, ej);
\r
1510 s5 = substring_range(str, ej, en);
\r
1511 return strcat(s1, s4, s3, s2, s5);
\r
1514 string _shufflewords_str;
\r
1515 void _shufflewords_swapfunc(float i, float j, entity pass)
\r
1517 _shufflewords_str = swapwords(_shufflewords_str, i, j);
\r
1519 string shufflewords(string str)
\r
1522 _shufflewords_str = str;
\r
1523 n = tokenizebyseparator(str, " ");
\r
1524 shuffle(n, _shufflewords_swapfunc, world);
\r
1525 str = _shufflewords_str;
\r
1526 _shufflewords_str = string_null;
\r
1530 vector solve_quadratic(float a, float b, float c) // ax^2 + bx + c = 0
\r
1539 v_x = v_y = -c / b;
\r
1546 // actually, every number solves the equation!
\r
1557 if(a > 0) // put the smaller solution first
\r
1559 v_x = ((-b)-D) / (2*a);
\r
1560 v_y = ((-b)+D) / (2*a);
\r
1564 v_x = (-b+D) / (2*a);
\r
1565 v_y = (-b-D) / (2*a);
\r
1571 // complex solutions!
\r
1585 float _unacceptable_compiler_bug_1_a(float b, float c) { return b == c; }
\r
1586 float _unacceptable_compiler_bug_1_b() { return 1; }
\r
1587 float _unacceptable_compiler_bug_1_c(float d) { return 2 * d; }
\r
1588 float _unacceptable_compiler_bug_1_d() { return 1; }
\r
1590 void check_unacceptable_compiler_bugs()
\r
1592 if(cvar("_allow_unacceptable_compiler_bugs"))
\r
1594 tokenize_console("foo bar");
\r
1595 if(strcat(argv(0), substring("foo bar", 4, 7 - argv_start_index(1))) == "barbar")
\r
1596 error("fteqcc bug introduced with revision 3178 detected. Please upgrade fteqcc to a later revision, downgrade fteqcc to revision 3177, or pester Spike until he fixes it. You can set _allow_unacceptable_compiler_bugs 1 to skip this check, but expect stuff to be horribly broken then.");
\r
1599 float compressShotOrigin(vector v)
\r
1602 x = rint(v_x * 2);
\r
1603 y = rint(v_y * 4) + 128;
\r
1604 z = rint(v_z * 4) + 128;
\r
1605 if(x > 255 || x < 0)
\r
1607 print("shot origin ", vtos(v), " x out of bounds\n");
\r
1608 x = bound(0, x, 255);
\r
1610 if(y > 255 || y < 0)
\r
1612 print("shot origin ", vtos(v), " y out of bounds\n");
\r
1613 y = bound(0, y, 255);
\r
1615 if(z > 255 || z < 0)
\r
1617 print("shot origin ", vtos(v), " z out of bounds\n");
\r
1618 z = bound(0, z, 255);
\r
1620 return x * 0x10000 + y * 0x100 + z;
\r
1622 vector decompressShotOrigin(float f)
\r
1625 v_x = ((f & 0xFF0000) / 0x10000) / 2;
\r
1626 v_y = ((f & 0xFF00) / 0x100 - 128) / 4;
\r
1627 v_z = ((f & 0xFF) - 128) / 4;
\r
1631 void heapsort(float n, swapfunc_t swap, comparefunc_t cmp, entity pass)
\r
1633 float start, end, root, child;
\r
1636 start = floor((n - 2) / 2);
\r
1639 // siftdown(start, count-1);
\r
1641 while(root * 2 + 1 <= n-1)
\r
1643 child = root * 2 + 1;
\r
1645 if(cmp(child, child+1, pass) < 0)
\r
1647 if(cmp(root, child, pass) < 0)
\r
1649 swap(root, child, pass);
\r
1655 // end of siftdown
\r
1663 swap(0, end, pass);
\r
1665 // siftdown(0, end);
\r
1667 while(root * 2 + 1 <= end)
\r
1669 child = root * 2 + 1;
\r
1670 if(child < end && cmp(child, child+1, pass) < 0)
\r
1672 if(cmp(root, child, pass) < 0)
\r
1674 swap(root, child, pass);
\r
1680 // end of siftdown
\r
1684 void RandomSelection_Init()
\r
1686 RandomSelection_totalweight = 0;
\r
1687 RandomSelection_chosen_ent = world;
\r
1688 RandomSelection_chosen_float = 0;
\r
1689 RandomSelection_chosen_string = string_null;
\r
1690 RandomSelection_best_priority = -1;
\r
1692 void RandomSelection_Add(entity e, float f, string s, float weight, float priority)
\r
1694 if(priority > RandomSelection_best_priority)
\r
1696 RandomSelection_best_priority = priority;
\r
1697 RandomSelection_chosen_ent = e;
\r
1698 RandomSelection_chosen_float = f;
\r
1699 RandomSelection_chosen_string = s;
\r
1700 RandomSelection_totalweight = weight;
\r
1702 else if(priority == RandomSelection_best_priority)
\r
1704 RandomSelection_totalweight += weight;
\r
1705 if(random() * RandomSelection_totalweight <= weight)
\r
1707 RandomSelection_chosen_ent = e;
\r
1708 RandomSelection_chosen_float = f;
\r
1709 RandomSelection_chosen_string = s;
\r
1714 vector healtharmor_maxdamage(float h, float a, float armorblock)
\r
1716 // NOTE: we'll always choose the SMALLER value...
\r
1717 float healthdamage, armordamage, armorideal;
\r
1719 healthdamage = (h - 1) / (1 - armorblock); // damage we can take if we could use more health
\r
1720 armordamage = a + (h - 1); // damage we can take if we could use more armor
\r
1721 armorideal = healthdamage * armorblock;
\r
1723 if(armordamage < healthdamage)
\r
1725 v_x = armordamage;
\r
1730 v_x = healthdamage;
\r
1736 vector healtharmor_applydamage(float a, float armorblock, float damage)
\r
1739 v_y = bound(0, damage * armorblock, a); // save
\r
1740 v_x = bound(0, damage - v_y, damage); // take
\r
1745 string getcurrentmod()
\r
1749 m = cvar_string("fs_gamedir");
\r
1750 n = tokenize_console(m);
\r
1754 return argv(n - 1);
\r
1759 float ReadInt24_t()
\r
1762 v = ReadShort() * 256; // note: this is signed
\r
1763 v += ReadByte(); // note: this is unsigned
\r
1767 void WriteInt24_t(float dest, float val)
\r
1770 WriteShort(dest, (v = floor(val / 256)));
\r
1771 WriteByte(dest, val - v * 256); // 0..255
\r
1776 float float2range11(float f)
\r
1778 // continuous function mapping all reals into -1..1
\r
1779 return f / (fabs(f) + 1);
\r
1782 float float2range01(float f)
\r
1784 // continuous function mapping all reals into 0..1
\r
1785 return 0.5 + 0.5 * float2range11(f);
\r
1788 // from the GNU Scientific Library
\r
1789 float gsl_ran_gaussian_lastvalue;
\r
1790 float gsl_ran_gaussian_lastvalue_set;
\r
1791 float gsl_ran_gaussian(float sigma)
\r
1794 if(gsl_ran_gaussian_lastvalue_set)
\r
1796 gsl_ran_gaussian_lastvalue_set = 0;
\r
1797 return sigma * gsl_ran_gaussian_lastvalue;
\r
1801 a = random() * 2 * M_PI;
\r
1802 b = sqrt(-2 * log(random()));
\r
1803 gsl_ran_gaussian_lastvalue = cos(a) * b;
\r
1804 gsl_ran_gaussian_lastvalue_set = 1;
\r
1805 return sigma * sin(a) * b;
\r
1809 string car(string s)
\r
1812 o = strstrofs(s, " ", 0);
\r
1815 return substring(s, 0, o);
\r
1817 string cdr(string s)
\r
1820 o = strstrofs(s, " ", 0);
\r
1822 return string_null;
\r
1823 return substring(s, o + 1, strlen(s) - (o + 1));
\r
1825 float matchacl(string acl, string str)
\r
1832 t = car(acl); acl = cdr(acl);
\r
1834 if(substring(t, 0, 1) == "-")
\r
1837 t = substring(t, 1, strlen(t) - 1);
\r
1839 else if(substring(t, 0, 1) == "+")
\r
1840 t = substring(t, 1, strlen(t) - 1);
\r
1841 if(substring(t, -1, 1) == "*")
\r
1843 t = substring(t, 0, strlen(t) - 1);
\r
1844 s = substring(s, 0, strlen(t));
\r
1856 float startsWith(string haystack, string needle)
\r
1858 return substring(haystack, 0, strlen(needle)) == needle;
\r
1860 float startsWithNocase(string haystack, string needle)
\r
1862 return strcasecmp(substring(haystack, 0, strlen(needle)), needle) == 0;
\r