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
83 string draw_UseSkinFor(string pic)
\r
85 if(substring(pic, 0, 1) == "/")
\r
86 return substring(pic, 1, strlen(pic)-1);
\r
88 return strcat(draw_currentSkin, "/", pic);
\r
92 string unescape(string in)
\r
95 local string str, s;
\r
97 // but it doesn't seem to be necessary in my tests at least
\r
102 for(i = 0; i < len; ++i)
\r
104 s = substring(in, i, 1);
\r
107 s = substring(in, i+1, 1);
\r
109 str = strcat(str, "\n");
\r
111 str = strcat(str, "\\");
\r
113 str = strcat(str, substring(in, i, 2));
\r
116 str = strcat(str, s);
\r
123 void wordwrap_cb(string s, float l, void(string) callback)
\r
126 local float lleft, i, j, wlen;
\r
130 for (i = 0;i < strlen(s);++i)
\r
132 if (substring(s, i, 2) == "\\n")
\r
138 else if (substring(s, i, 1) == "\n")
\r
143 else if (substring(s, i, 1) == " ")
\r
153 for (j = i+1;j < strlen(s);++j)
\r
154 // ^^ this skips over the first character of a word, which
\r
155 // is ALWAYS part of the word
\r
156 // this is safe since if i+1 == strlen(s), i will become
\r
157 // strlen(s)-1 at the end of this block and the function
\r
158 // will terminate. A space can't be the first character we
\r
159 // read here, and neither can a \n be the start, since these
\r
160 // two cases have been handled above.
\r
162 c = substring(s, j, 1);
\r
169 // we need to keep this tempstring alive even if substring is
\r
170 // called repeatedly, so call strcat even though we're not
\r
180 callback(substring(s, i, wlen));
\r
181 lleft = lleft - wlen;
\r
188 float dist_point_line(vector p, vector l0, vector ldir)
\r
190 ldir = normalize(ldir);
\r
192 // remove the component in line direction
\r
193 p = p - (p * ldir) * ldir;
\r
195 // vlen of the remaining vector
\r
199 void depthfirst(entity start, .entity up, .entity downleft, .entity right, void(entity, entity) funcPre, void(entity, entity) funcPost, entity pass)
\r
228 float median(float a, float b, float c)
\r
231 return bound(a, b, c);
\r
232 return bound(c, b, a);
\r
235 // converts a number to a string with the indicated number of decimals
\r
236 // works for up to 10 decimals!
\r
237 string ftos_decimals(float number, float decimals)
\r
243 // if negative, cut off the sign first
\r
245 return strcat("-", ftos_decimals(-number, decimals));
\r
246 // it now is always positive!
\r
249 number = floor(number * pow(10, decimals) + 0.5);
\r
252 result = ftos(number);
\r
253 len = strlen(result);
\r
254 // does it have a decimal point (should not happen)? If there is one, it is always at len-7)
\r
255 // if ftos had messed it up, which should never happen: "34278.000000"
\r
257 if(substring(result, len - 7, 1) == ".")
\r
259 dprint("ftos(integer) has comma? Can't be. Affected result: ", result, "\n");
\r
260 result = substring(result, 0, len - 7);
\r
265 return result; // don't insert a point for zero decimals
\r
266 // is it too short? If yes, insert leading zeroes
\r
267 if(len <= decimals)
\r
269 result = strcat(substring("0000000000", 0, decimals - len + 1), result);
\r
270 len = decimals + 1;
\r
272 // and now... INSERT THE POINT!
\r
273 tmp = substring(result, len - decimals, decimals);
\r
274 result = strcat(substring(result, 0, len - decimals), ".", tmp);
\r
279 vector colormapPaletteColor(float c, float isPants)
\r
283 case 0: return '0.800000 0.800000 0.800000';
\r
284 case 1: return '0.600000 0.400000 0.000000';
\r
285 case 2: return '0.000000 1.000000 0.501961';
\r
286 case 3: return '0.000000 1.000000 0.000000';
\r
287 case 4: return '1.000000 0.000000 0.000000';
\r
288 case 5: return '0.000000 0.658824 1.000000';
\r
289 case 6: return '0.000000 1.000000 1.000000';
\r
290 case 7: return '0.501961 1.000000 0.000000';
\r
291 case 8: return '0.501961 0.000000 1.000000';
\r
292 case 9: return '1.000000 0.000000 1.000000';
\r
293 case 10: return '1.000000 0.000000 0.501961';
\r
294 case 11: return '0.600000 0.600000 0.600000';
\r
295 case 12: return '1.000000 1.000000 0.000000';
\r
296 case 13: return '0.000000 0.313725 1.000000';
\r
297 case 14: return '1.000000 0.501961 0.000000';
\r
301 '1 0 0' * (0.502 + 0.498 * sin(time / 2.7182818285 + 0.0000000000))
\r
302 + '0 1 0' * (0.502 + 0.498 * sin(time / 2.7182818285 + 2.0943951024))
\r
303 + '0 0 1' * (0.502 + 0.498 * sin(time / 2.7182818285 + 4.1887902048));
\r
306 '1 0 0' * (0.502 + 0.498 * sin(time / 3.1415926536 + 5.2359877560))
\r
307 + '0 1 0' * (0.502 + 0.498 * sin(time / 3.1415926536 + 3.1415926536))
\r
308 + '0 0 1' * (0.502 + 0.498 * sin(time / 3.1415926536 + 1.0471975512));
\r
309 default: return '0.000 0.000 0.000';
\r
313 // unzone the string, and return it as tempstring. Safe to be called on string_null
\r
314 string fstrunzone(string s)
\r
319 sc = strcat(s, "");
\r
324 // Databases (hash tables)
\r
325 #define DB_BUCKETS 8192
\r
326 void db_save(float db, string pFilename)
\r
329 fh = fopen(pFilename, FILE_WRITE);
\r
332 print(strcat("^1Can't write DB to ", pFilename));
\r
335 n = buf_getsize(db);
\r
336 fputs(fh, strcat(ftos(DB_BUCKETS), "\n"));
\r
337 for(i = 0; i < n; ++i)
\r
338 fputs(fh, strcat(bufstr_get(db, i), "\n"));
\r
344 return buf_create();
\r
347 float db_load(string pFilename)
\r
349 float db, fh, i, j, n;
\r
354 fh = fopen(pFilename, FILE_READ);
\r
357 if(stof(fgets(fh)) == DB_BUCKETS)
\r
360 while((l = fgets(fh)))
\r
363 bufstr_set(db, i, l);
\r
369 // different count of buckets?
\r
370 // need to reorganize the database then (SLOW)
\r
371 while((l = fgets(fh)))
\r
373 n = tokenizebyseparator(l, "\\");
\r
374 for(j = 2; j < n; j += 2)
\r
375 db_put(db, argv(j-1), uri_unescape(argv(j)));
\r
382 void db_dump(float db, string pFilename)
\r
384 float fh, i, j, n, m;
\r
385 fh = fopen(pFilename, FILE_WRITE);
\r
387 error(strcat("Can't dump DB to ", pFilename));
\r
388 n = buf_getsize(db);
\r
390 for(i = 0; i < n; ++i)
\r
392 m = tokenizebyseparator(bufstr_get(db, i), "\\");
\r
393 for(j = 2; j < m; j += 2)
\r
394 fputs(fh, strcat("\\", argv(j-1), "\\", argv(j), "\n"));
\r
399 void db_close(float db)
\r
404 string db_get(float db, string pKey)
\r
407 h = mod(crc16(FALSE, pKey), DB_BUCKETS);
\r
408 return uri_unescape(infoget(bufstr_get(db, h), pKey));
\r
411 void db_put(float db, string pKey, string pValue)
\r
414 h = mod(crc16(FALSE, pKey), DB_BUCKETS);
\r
415 bufstr_set(db, h, infoadd(bufstr_get(db, h), pKey, uri_escape(pValue)));
\r
421 print("LOAD...\n");
\r
422 db = db_load("foo.db");
\r
423 print("LOADED. FILL...\n");
\r
424 for(i = 0; i < DB_BUCKETS; ++i)
\r
425 db_put(db, ftos(random()), "X");
\r
426 print("FILLED. SAVE...\n");
\r
427 db_save(db, "foo.db");
\r
428 print("SAVED. CLOSE...\n");
\r
430 print("CLOSED.\n");
\r
433 // Multiline text file buffers
\r
434 float buf_load(string pFilename)
\r
438 buf = buf_create();
\r
441 fh = fopen(pFilename, FILE_READ);
\r
445 while((l = fgets(fh)))
\r
447 bufstr_set(buf, i, l);
\r
454 void buf_save(float buf, string pFilename)
\r
457 fh = fopen(pFilename, FILE_WRITE);
\r
459 error(strcat("Can't write buf to ", pFilename));
\r
460 n = buf_getsize(buf);
\r
461 for(i = 0; i < n; ++i)
\r
462 fputs(fh, strcat(bufstr_get(buf, i), "\n"));
\r
466 string GametypeNameFromType(float g)
\r
468 if (g == GAME_DEATHMATCH) return "dm";
\r
469 else if (g == GAME_TEAM_DEATHMATCH) return "tdm";
\r
470 else if (g == GAME_DOMINATION) return "dom";
\r
471 else if (g == GAME_CTF) return "ctf";
\r
472 else if (g == GAME_LMS) return "lms";
\r
473 else if (g == GAME_ARENA) return "arena";
\r
474 else if (g == GAME_CA) return "ca";
\r
475 else if (g == GAME_KEYHUNT) return "kh";
\r
476 else if (g == GAME_ONSLAUGHT) return "ons";
\r
477 else if (g == GAME_ASSAULT) return "as";
\r
478 else if (g == GAME_RACE) return "rc";
\r
479 else if (g == GAME_CTS) return "cts";
\r
480 else if (g == GAME_RPG) return "rpg";
\r
484 string mmsss(float tenths)
\r
488 tenths = floor(tenths + 0.5);
\r
489 minutes = floor(tenths / 600);
\r
490 tenths -= minutes * 600;
\r
491 s = ftos(1000 + tenths);
\r
492 return strcat(ftos(minutes), ":", substring(s, 1, 2), ".", substring(s, 3, 1));
\r
495 string mmssss(float hundredths)
\r
499 hundredths = floor(hundredths + 0.5);
\r
500 minutes = floor(hundredths / 6000);
\r
501 hundredths -= minutes * 6000;
\r
502 s = ftos(10000 + hundredths);
\r
503 return strcat(ftos(minutes), ":", substring(s, 1, 2), ".", substring(s, 3, 2));
\r
506 string ScoreString(float pFlags, float pValue)
\r
511 pValue = floor(pValue + 0.5); // round
\r
513 if((pValue == 0) && (pFlags & (SFL_HIDE_ZERO | SFL_RANK | SFL_TIME)))
\r
515 else if(pFlags & SFL_RANK)
\r
517 valstr = ftos(pValue);
\r
518 l = strlen(valstr);
\r
519 if((l >= 2) && (substring(valstr, l - 2, 1) == "1"))
\r
520 valstr = strcat(valstr, "th");
\r
521 else if(substring(valstr, l - 1, 1) == "1")
\r
522 valstr = strcat(valstr, "st");
\r
523 else if(substring(valstr, l - 1, 1) == "2")
\r
524 valstr = strcat(valstr, "nd");
\r
525 else if(substring(valstr, l - 1, 1) == "3")
\r
526 valstr = strcat(valstr, "rd");
\r
528 valstr = strcat(valstr, "th");
\r
530 else if(pFlags & SFL_TIME)
\r
531 valstr = TIME_ENCODED_TOSTRING(pValue);
\r
533 valstr = ftos(pValue);
\r
538 vector cross(vector a, vector b)
\r
541 '1 0 0' * (a_y * b_z - a_z * b_y)
\r
542 + '0 1 0' * (a_z * b_x - a_x * b_z)
\r
543 + '0 0 1' * (a_x * b_y - a_y * b_x);
\r
546 // compressed vector format:
\r
547 // like MD3, just even shorter
\r
548 // 4 bit pitch (16 angles), 0 is -90, 8 is 0, 16 would be 90
\r
549 // 5 bit yaw (32 angles), 0=0, 8=90, 16=180, 24=270
\r
550 // 7 bit length (logarithmic encoding), 1/8 .. about 7844
\r
551 // length = 2^(length_encoded/8) / 8
\r
552 // if pitch is 90, yaw does nothing and therefore indicates the sign (yaw is then either 11111 or 11110); 11111 is pointing DOWN
\r
553 // thus, valid values are from 0000.11110.0000000 to 1111.11111.1111111
\r
554 // the special value 0 indicates the zero vector
\r
556 float lengthLogTable[128];
\r
558 float invertLengthLog(float x)
\r
560 float l, r, m, lerr, rerr;
\r
562 if(x >= lengthLogTable[127])
\r
564 if(x <= lengthLogTable[0])
\r
572 m = floor((l + r) / 2);
\r
573 if(lengthLogTable[m] < x)
\r
579 // now: r is >=, l is <
\r
580 lerr = (x - lengthLogTable[l]);
\r
581 rerr = (lengthLogTable[r] - x);
\r
587 vector decompressShortVector(float data)
\r
590 float pitch, yaw, len;
\r
593 pitch = (data & 0xF000) / 0x1000;
\r
594 yaw = (data & 0x0F80) / 0x80;
\r
595 len = (data & 0x007F);
\r
597 //print("\ndecompress: pitch ", ftos(pitch)); print("yaw ", ftos(yaw)); print("len ", ftos(len), "\n");
\r
610 yaw = .19634954084936207740 * yaw;
\r
611 pitch = .19634954084936207740 * pitch - 1.57079632679489661922;
\r
612 out_x = cos(yaw) * cos(pitch);
\r
613 out_y = sin(yaw) * cos(pitch);
\r
614 out_z = -sin(pitch);
\r
617 //print("decompressed: ", vtos(out), "\n");
\r
619 return out * lengthLogTable[len];
\r
622 float compressShortVector(vector vec)
\r
625 float pitch, yaw, len;
\r
628 //print("compress: ", vtos(vec), "\n");
\r
629 ang = vectoangles(vec);
\r
633 if(ang_x < -90 && ang_x > +90)
\r
634 error("BOGUS vectoangles");
\r
635 //print("angles: ", vtos(ang), "\n");
\r
637 pitch = floor(0.5 + (ang_x + 90) * 16 / 180) & 15; // -90..90 to 0..14
\r
646 yaw = floor(0.5 + ang_y * 32 / 360) & 31; // 0..360 to 0..32
\r
647 len = invertLengthLog(vlen(vec));
\r
649 //print("compressed: pitch ", ftos(pitch)); print("yaw ", ftos(yaw)); print("len ", ftos(len), "\n");
\r
651 return (pitch * 0x1000) + (yaw * 0x80) + len;
\r
654 void compressShortVector_init()
\r
659 for(i = 0; i < 128; ++i)
\r
661 lengthLogTable[i] = l;
\r
665 if(cvar("developer"))
\r
667 print("Verifying vector compression table...\n");
\r
668 for(i = 0x0F00; i < 0xFFFF; ++i)
\r
669 if(i != compressShortVector(decompressShortVector(i)))
\r
671 print("BROKEN vector compression: ", ftos(i));
\r
672 print(" -> ", vtos(decompressShortVector(i)));
\r
673 print(" -> ", ftos(compressShortVector(decompressShortVector(i))));
\r
682 float CheckWireframeBox(entity forent, vector v0, vector dvx, vector dvy, vector dvz)
\r
684 traceline(v0, v0 + dvx, TRUE, forent); if(trace_fraction < 1) return 0;
\r
685 traceline(v0, v0 + dvy, TRUE, forent); if(trace_fraction < 1) return 0;
\r
686 traceline(v0, v0 + dvz, TRUE, forent); if(trace_fraction < 1) return 0;
\r
687 traceline(v0 + dvx, v0 + dvx + dvy, TRUE, forent); if(trace_fraction < 1) return 0;
\r
688 traceline(v0 + dvx, v0 + dvx + dvz, TRUE, forent); if(trace_fraction < 1) return 0;
\r
689 traceline(v0 + dvy, v0 + dvy + dvx, TRUE, forent); if(trace_fraction < 1) return 0;
\r
690 traceline(v0 + dvy, v0 + dvy + dvz, TRUE, forent); if(trace_fraction < 1) return 0;
\r
691 traceline(v0 + dvz, v0 + dvz + dvx, TRUE, forent); if(trace_fraction < 1) return 0;
\r
692 traceline(v0 + dvz, v0 + dvz + dvy, TRUE, forent); if(trace_fraction < 1) return 0;
\r
693 traceline(v0 + dvx + dvy, v0 + dvx + dvy + dvz, TRUE, forent); if(trace_fraction < 1) return 0;
\r
694 traceline(v0 + dvx + dvz, v0 + dvx + dvy + dvz, TRUE, forent); if(trace_fraction < 1) return 0;
\r
695 traceline(v0 + dvy + dvz, v0 + dvx + dvy + dvz, TRUE, forent); if(trace_fraction < 1) return 0;
\r
700 string fixPriorityList(string order, float from, float to, float subtract, float complete)
\r
705 n = tokenize_console(order);
\r
707 for(i = 0; i < n; ++i)
\r
712 if(w >= from && w <= to)
\r
713 neworder = strcat(neworder, ftos(w), " ");
\r
717 if(w >= from && w <= to)
\r
718 neworder = strcat(neworder, ftos(w), " ");
\r
725 n = tokenize_console(neworder);
\r
726 for(w = to; w >= from; --w)
\r
728 for(i = 0; i < n; ++i)
\r
729 if(stof(argv(i)) == w)
\r
731 if(i == n) // not found
\r
732 neworder = strcat(neworder, ftos(w), " ");
\r
736 return substring(neworder, 0, strlen(neworder) - 1);
\r
739 string mapPriorityList(string order, string(string) mapfunc)
\r
744 n = tokenize_console(order);
\r
746 for(i = 0; i < n; ++i)
\r
747 neworder = strcat(neworder, mapfunc(argv(i)), " ");
\r
749 return substring(neworder, 0, strlen(neworder) - 1);
\r
752 string swapInPriorityList(string order, float i, float j)
\r
757 n = tokenize_console(order);
\r
759 if(i >= 0 && i < n && j >= 0 && j < n && i != j)
\r
762 for(w = 0; w < n; ++w)
\r
765 s = strcat(s, argv(j), " ");
\r
767 s = strcat(s, argv(i), " ");
\r
769 s = strcat(s, argv(w), " ");
\r
771 return substring(s, 0, strlen(s) - 1);
\r
777 float cvar_value_issafe(string s)
\r
779 if(strstrofs(s, "\"", 0) >= 0)
\r
781 if(strstrofs(s, "\\", 0) >= 0)
\r
783 if(strstrofs(s, ";", 0) >= 0)
\r
785 if(strstrofs(s, "$", 0) >= 0)
\r
787 if(strstrofs(s, "\r", 0) >= 0)
\r
789 if(strstrofs(s, "\n", 0) >= 0)
\r
795 void get_mi_min_max(float mode)
\r
800 strunzone(mi_shortname);
\r
801 mi_shortname = mapname;
\r
802 if(!strcasecmp(substring(mi_shortname, 0, 5), "maps/"))
\r
803 mi_shortname = substring(mi_shortname, 5, strlen(mi_shortname) - 5);
\r
804 if(!strcasecmp(substring(mi_shortname, strlen(mi_shortname) - 4, 4), ".bsp"))
\r
805 mi_shortname = substring(mi_shortname, 0, strlen(mi_shortname) - 4);
\r
806 mi_shortname = strzone(mi_shortname);
\r
818 MapInfo_Get_ByName(mi_shortname, 0, 0);
\r
819 if(MapInfo_Map_mins_x < MapInfo_Map_maxs_x)
\r
821 mi_min = MapInfo_Map_mins;
\r
822 mi_max = MapInfo_Map_maxs;
\r
830 tracebox('1 0 0' * mi_x,
\r
831 '0 1 0' * mi_y + '0 0 1' * mi_z,
\r
832 '0 1 0' * ma_y + '0 0 1' * ma_z,
\r
836 if(!trace_startsolid)
\r
837 mi_min_x = trace_endpos_x;
\r
839 tracebox('0 1 0' * mi_y,
\r
840 '1 0 0' * mi_x + '0 0 1' * mi_z,
\r
841 '1 0 0' * ma_x + '0 0 1' * ma_z,
\r
845 if(!trace_startsolid)
\r
846 mi_min_y = trace_endpos_y;
\r
848 tracebox('0 0 1' * mi_z,
\r
849 '1 0 0' * mi_x + '0 1 0' * mi_y,
\r
850 '1 0 0' * ma_x + '0 1 0' * ma_y,
\r
854 if(!trace_startsolid)
\r
855 mi_min_z = trace_endpos_z;
\r
857 tracebox('1 0 0' * ma_x,
\r
858 '0 1 0' * mi_y + '0 0 1' * mi_z,
\r
859 '0 1 0' * ma_y + '0 0 1' * ma_z,
\r
863 if(!trace_startsolid)
\r
864 mi_max_x = trace_endpos_x;
\r
866 tracebox('0 1 0' * ma_y,
\r
867 '1 0 0' * mi_x + '0 0 1' * mi_z,
\r
868 '1 0 0' * ma_x + '0 0 1' * ma_z,
\r
872 if(!trace_startsolid)
\r
873 mi_max_y = trace_endpos_y;
\r
875 tracebox('0 0 1' * ma_z,
\r
876 '1 0 0' * mi_x + '0 1 0' * mi_y,
\r
877 '1 0 0' * ma_x + '0 1 0' * ma_y,
\r
881 if(!trace_startsolid)
\r
882 mi_max_z = trace_endpos_z;
\r
887 void get_mi_min_max_texcoords(float mode)
\r
891 get_mi_min_max(mode);
\r
893 mi_picmin = mi_min;
\r
894 mi_picmax = mi_max;
\r
896 // extend mi_picmax to get a square aspect ratio
\r
897 // center the map in that area
\r
898 extend = mi_picmax - mi_picmin;
\r
899 if(extend_y > extend_x)
\r
901 mi_picmin_x -= (extend_y - extend_x) * 0.5;
\r
902 mi_picmax_x += (extend_y - extend_x) * 0.5;
\r
906 mi_picmin_y -= (extend_x - extend_y) * 0.5;
\r
907 mi_picmax_y += (extend_x - extend_y) * 0.5;
\r
910 // add another some percent
\r
911 extend = (mi_picmax - mi_picmin) * (1 / 64.0);
\r
912 mi_picmin -= extend;
\r
913 mi_picmax += extend;
\r
915 // calculate the texcoords
\r
916 mi_pictexcoord0 = mi_pictexcoord1 = mi_pictexcoord2 = mi_pictexcoord3 = '0 0 0';
\r
917 // first the two corners of the origin
\r
918 mi_pictexcoord0_x = (mi_min_x - mi_picmin_x) / (mi_picmax_x - mi_picmin_x);
\r
919 mi_pictexcoord0_y = (mi_min_y - mi_picmin_y) / (mi_picmax_y - mi_picmin_y);
\r
920 mi_pictexcoord2_x = (mi_max_x - mi_picmin_x) / (mi_picmax_x - mi_picmin_x);
\r
921 mi_pictexcoord2_y = (mi_max_y - mi_picmin_y) / (mi_picmax_y - mi_picmin_y);
\r
922 // then the other corners
\r
923 mi_pictexcoord1_x = mi_pictexcoord0_x;
\r
924 mi_pictexcoord1_y = mi_pictexcoord2_y;
\r
925 mi_pictexcoord3_x = mi_pictexcoord2_x;
\r
926 mi_pictexcoord3_y = mi_pictexcoord0_y;
\r
931 void cvar_settemp(string pKey, string pValue)
\r
933 error("cvar_settemp called from CSQC - use cvar_clientsettemp instead!");
\r
935 void cvar_settemp_restore()
\r
937 error("cvar_settemp_restore called from CSQC - use cvar_clientsettemp instead!");
\r
940 void cvar_settemp(string pKey, string pValue)
\r
943 string settemp_var;
\r
944 if(cvar_string(pKey) == pValue)
\r
946 i = cvar("settemp_idx");
\r
947 cvar_set("settemp_idx", ftos(i+1));
\r
948 settemp_var = strcat("_settemp_x", ftos(i));
\r
950 registercvar(settemp_var, "", 0);
\r
952 registercvar(settemp_var, "");
\r
954 cvar_set("settemp_list", strcat("1 ", pKey, " ", settemp_var, " ", cvar_string("settemp_list")));
\r
955 cvar_set(settemp_var, cvar_string(pKey));
\r
956 cvar_set(pKey, pValue);
\r
959 void cvar_settemp_restore()
\r
961 // undo what cvar_settemp did
\r
963 n = tokenize_console(cvar_string("settemp_list"));
\r
964 for(i = 0; i < n - 3; i += 3)
\r
965 cvar_set(argv(i + 1), cvar_string(argv(i + 2)));
\r
966 cvar_set("settemp_list", "0");
\r
970 float almost_equals(float a, float b)
\r
973 eps = (max(a, -a) + max(b, -b)) * 0.001;
\r
974 if(a - b < eps && b - a < eps)
\r
979 float almost_in_bounds(float a, float b, float c)
\r
982 eps = (max(a, -a) + max(c, -c)) * 0.001;
\r
983 return b == median(a - eps, b, c + eps);
\r
986 float power2of(float e)
\r
990 float log2of(float x)
\r
992 // NOTE: generated code
\r
1065 float rgb_mi_ma_to_hue(vector rgb, float mi, float ma)
\r
1069 else if(ma == rgb_x)
\r
1071 if(rgb_y >= rgb_z)
\r
1072 return (rgb_y - rgb_z) / (ma - mi);
\r
1074 return (rgb_y - rgb_z) / (ma - mi) + 6;
\r
1076 else if(ma == rgb_y)
\r
1077 return (rgb_z - rgb_x) / (ma - mi) + 2;
\r
1078 else // if(ma == rgb_z)
\r
1079 return (rgb_x - rgb_y) / (ma - mi) + 4;
\r
1082 vector hue_mi_ma_to_rgb(float hue, float mi, float ma)
\r
1086 hue -= 6 * floor(hue / 6);
\r
1088 //else if(ma == rgb_x)
\r
1089 // hue = 60 * (rgb_y - rgb_z) / (ma - mi);
\r
1093 rgb_y = hue * (ma - mi) + mi;
\r
1096 //else if(ma == rgb_y)
\r
1097 // hue = 60 * (rgb_z - rgb_x) / (ma - mi) + 120;
\r
1100 rgb_x = (2 - hue) * (ma - mi) + mi;
\r
1108 rgb_z = (hue - 2) * (ma - mi) + mi;
\r
1110 //else // if(ma == rgb_z)
\r
1111 // hue = 60 * (rgb_x - rgb_y) / (ma - mi) + 240;
\r
1115 rgb_y = (4 - hue) * (ma - mi) + mi;
\r
1120 rgb_x = (hue - 4) * (ma - mi) + mi;
\r
1124 //else if(ma == rgb_x)
\r
1125 // hue = 60 * (rgb_y - rgb_z) / (ma - mi);
\r
1126 else // if(hue <= 6)
\r
1130 rgb_z = (6 - hue) * (ma - mi) + mi;
\r
1136 vector rgb_to_hsv(vector rgb)
\r
1141 mi = min3(rgb_x, rgb_y, rgb_z);
\r
1142 ma = max3(rgb_x, rgb_y, rgb_z);
\r
1144 hsv_x = rgb_mi_ma_to_hue(rgb, mi, ma);
\r
1150 hsv_y = 1 - mi/ma;
\r
1155 vector hsv_to_rgb(vector hsv)
\r
1157 return hue_mi_ma_to_rgb(hsv_x, hsv_z * (1 - hsv_y), hsv_z);
\r
1160 vector rgb_to_hsl(vector rgb)
\r
1165 mi = min3(rgb_x, rgb_y, rgb_z);
\r
1166 ma = max3(rgb_x, rgb_y, rgb_z);
\r
1168 hsl_x = rgb_mi_ma_to_hue(rgb, mi, ma);
\r
1170 hsl_z = 0.5 * (mi + ma);
\r
1173 else if(hsl_z <= 0.5)
\r
1174 hsl_y = (ma - mi) / (2*hsl_z);
\r
1175 else // if(hsl_z > 0.5)
\r
1176 hsl_y = (ma - mi) / (2 - 2*hsl_z);
\r
1181 vector hsl_to_rgb(vector hsl)
\r
1183 float mi, ma, maminusmi;
\r
1186 maminusmi = hsl_y * 2 * hsl_z;
\r
1188 maminusmi = hsl_y * (2 - 2 * hsl_z);
\r
1190 // hsl_z = 0.5 * mi + 0.5 * ma
\r
1191 // maminusmi = - mi + ma
\r
1192 mi = hsl_z - 0.5 * maminusmi;
\r
1193 ma = hsl_z + 0.5 * maminusmi;
\r
1195 return hue_mi_ma_to_rgb(hsl_x, mi, ma);
\r
1198 string rgb_to_hexcolor(vector rgb)
\r
1203 DEC_TO_HEXDIGIT(floor(rgb_x * 15 + 0.5)),
\r
1204 DEC_TO_HEXDIGIT(floor(rgb_y * 15 + 0.5)),
\r
1205 DEC_TO_HEXDIGIT(floor(rgb_z * 15 + 0.5))
\r
1209 // requires that m2>m1 in all coordinates, and that m4>m3
\r
1210 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
1212 // requires the same, but is a stronger condition
\r
1213 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
1218 float textLengthUpToWidth(string theText, float maxWidth, vector theSize, textLengthUpToWidth_widthFunction_t w)
\r
1220 float ICanHasKallerz;
\r
1222 // detect color codes support in the width function
\r
1223 ICanHasKallerz = (w("^7", theSize) == 0);
\r
1226 // The following function is SLOW.
\r
1227 // For your safety and for the protection of those around you...
\r
1228 // DO NOT CALL THIS AT HOME.
\r
1229 // No really, don't.
\r
1230 if(w(theText, theSize) <= maxWidth)
\r
1231 return strlen(theText); // yeah!
\r
1233 // binary search for right place to cut string
\r
1235 float left, right, middle; // this always works
\r
1237 right = strlen(theText); // this always fails
\r
1240 middle = floor((left + right) / 2);
\r
1241 if(w(substring(theText, 0, middle), theSize) <= maxWidth)
\r
1246 while(left < right - 1);
\r
1248 if(ICanHasKallerz)
\r
1250 // NOTE: when color codes are involved, this binary search is,
\r
1251 // mathematically, BROKEN. However, it is obviously guaranteed to
\r
1252 // terminate, as the range still halves each time - but nevertheless, it is
\r
1253 // guaranteed that it finds ONE valid cutoff place (where "left" is in
\r
1254 // range, and "right" is outside).
\r
1256 // terencehill: the following code detects truncated ^xrgb tags (e.g. ^x or ^x4)
\r
1257 // and decrease left on the basis of the chars detected of the truncated tag
\r
1258 // Even if the ^xrgb tag is not complete/correct, left is decreased
\r
1259 // (sometimes too much but with a correct result)
\r
1260 // it fixes also ^[0-9]
\r
1261 while(left >= 1 && substring(theText, left-1, 1) == "^")
\r
1264 if (left >= 2 && substring(theText, left-2, 2) == "^x") // ^x/
\r
1266 else if (left >= 3 && substring(theText, left-3, 2) == "^x")
\r
1268 ch = str2chr(theText, left-1);
\r
1269 if( (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F') ) // ^xr/
\r
1272 else if (left >= 4 && substring(theText, left-4, 2) == "^x")
\r
1274 ch = str2chr(theText, left-2);
\r
1275 if ( (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F') )
\r
1277 ch = str2chr(theText, left-1);
\r
1278 if ( (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F') ) // ^xrg/
\r
1287 float textLengthUpToLength(string theText, float maxWidth, textLengthUpToLength_lenFunction_t w)
\r
1289 float ICanHasKallerz;
\r
1291 // detect color codes support in the width function
\r
1292 ICanHasKallerz = (w("^7") == 0);
\r
1295 // The following function is SLOW.
\r
1296 // For your safety and for the protection of those around you...
\r
1297 // DO NOT CALL THIS AT HOME.
\r
1298 // No really, don't.
\r
1299 if(w(theText) <= maxWidth)
\r
1300 return strlen(theText); // yeah!
\r
1302 // binary search for right place to cut string
\r
1304 float left, right, middle; // this always works
\r
1306 right = strlen(theText); // this always fails
\r
1309 middle = floor((left + right) / 2);
\r
1310 if(w(substring(theText, 0, middle)) <= maxWidth)
\r
1315 while(left < right - 1);
\r
1317 if(ICanHasKallerz)
\r
1319 // NOTE: when color codes are involved, this binary search is,
\r
1320 // mathematically, BROKEN. However, it is obviously guaranteed to
\r
1321 // terminate, as the range still halves each time - but nevertheless, it is
\r
1322 // guaranteed that it finds ONE valid cutoff place (where "left" is in
\r
1323 // range, and "right" is outside).
\r
1325 // terencehill: the following code detects truncated ^xrgb tags (e.g. ^x or ^x4)
\r
1326 // and decrease left on the basis of the chars detected of the truncated tag
\r
1327 // Even if the ^xrgb tag is not complete/correct, left is decreased
\r
1328 // (sometimes too much but with a correct result)
\r
1329 // it fixes also ^[0-9]
\r
1330 while(left >= 1 && substring(theText, left-1, 1) == "^")
\r
1333 if (left >= 2 && substring(theText, left-2, 2) == "^x") // ^x/
\r
1335 else if (left >= 3 && substring(theText, left-3, 2) == "^x")
\r
1337 ch = str2chr(theText, left-1);
\r
1338 if( (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F') ) // ^xr/
\r
1341 else if (left >= 4 && substring(theText, left-4, 2) == "^x")
\r
1343 ch = str2chr(theText, left-2);
\r
1344 if ( (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F') )
\r
1346 ch = str2chr(theText, left-1);
\r
1347 if ( (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F') ) // ^xrg/
\r
1356 string getWrappedLine(float w, vector theFontSize, textLengthUpToWidth_widthFunction_t tw)
\r
1362 s = getWrappedLine_remaining;
\r
1364 cantake = textLengthUpToWidth(s, w, theFontSize, tw);
\r
1365 if(cantake > 0 && cantake < strlen(s))
\r
1367 take = cantake - 1;
\r
1368 while(take > 0 && substring(s, take, 1) != " ")
\r
1372 getWrappedLine_remaining = substring(s, cantake, strlen(s) - cantake);
\r
1373 if(getWrappedLine_remaining == "")
\r
1374 getWrappedLine_remaining = string_null;
\r
1375 return substring(s, 0, cantake);
\r
1379 getWrappedLine_remaining = substring(s, take + 1, strlen(s) - take);
\r
1380 if(getWrappedLine_remaining == "")
\r
1381 getWrappedLine_remaining = string_null;
\r
1382 return substring(s, 0, take);
\r
1387 getWrappedLine_remaining = string_null;
\r
1392 string getWrappedLineLen(float w, textLengthUpToLength_lenFunction_t tw)
\r
1398 s = getWrappedLine_remaining;
\r
1400 cantake = textLengthUpToLength(s, w, tw);
\r
1401 if(cantake > 0 && cantake < strlen(s))
\r
1403 take = cantake - 1;
\r
1404 while(take > 0 && substring(s, take, 1) != " ")
\r
1408 getWrappedLine_remaining = substring(s, cantake, strlen(s) - cantake);
\r
1409 if(getWrappedLine_remaining == "")
\r
1410 getWrappedLine_remaining = string_null;
\r
1411 return substring(s, 0, cantake);
\r
1415 getWrappedLine_remaining = substring(s, take + 1, strlen(s) - take);
\r
1416 if(getWrappedLine_remaining == "")
\r
1417 getWrappedLine_remaining = string_null;
\r
1418 return substring(s, 0, take);
\r
1423 getWrappedLine_remaining = string_null;
\r
1428 string textShortenToWidth(string theText, float maxWidth, vector theFontSize, textLengthUpToWidth_widthFunction_t tw)
\r
1430 if(tw(theText, theFontSize) <= maxWidth)
\r
1433 return strcat(substring(theText, 0, textLengthUpToWidth(theText, maxWidth - tw("...", theFontSize), theFontSize, tw)), "...");
\r
1436 string textShortenToLength(string theText, float maxWidth, textLengthUpToLength_lenFunction_t tw)
\r
1438 if(tw(theText) <= maxWidth)
\r
1441 return strcat(substring(theText, 0, textLengthUpToLength(theText, maxWidth - tw("..."), tw)), "...");
\r
1444 float isGametypeInFilter(float gt, float tp, string pattern)
\r
1446 string subpattern, subpattern2, subpattern3;
\r
1447 subpattern = strcat(",", GametypeNameFromType(gt), ",");
\r
1449 subpattern2 = ",teams,";
\r
1451 subpattern2 = ",noteams,";
\r
1452 if(gt == GAME_RACE || gt == GAME_CTS)
\r
1453 subpattern3 = ",race,";
\r
1455 subpattern3 = string_null;
\r
1457 if(substring(pattern, 0, 1) == "-")
\r
1459 pattern = substring(pattern, 1, strlen(pattern) - 1);
\r
1460 if(strstrofs(strcat(",", pattern, ","), subpattern, 0) >= 0)
\r
1462 if(strstrofs(strcat(",", pattern, ","), subpattern2, 0) >= 0)
\r
1464 if(subpattern3 && strstrofs(strcat(",", pattern, ","), subpattern3, 0) >= 0)
\r
1469 if(substring(pattern, 0, 1) == "+")
\r
1470 pattern = substring(pattern, 1, strlen(pattern) - 1);
\r
1471 if(strstrofs(strcat(",", pattern, ","), subpattern, 0) < 0)
\r
1472 if(strstrofs(strcat(",", pattern, ","), subpattern2, 0) < 0)
\r
1473 if((!subpattern3) || strstrofs(strcat(",", pattern, ","), subpattern3, 0) < 0)
\r
1479 void shuffle(float n, swapfunc_t swap, entity pass)
\r
1482 for(i = 1; i < n; ++i)
\r
1484 // swap i-th item at a random position from 0 to i
\r
1485 // proof for even distribution:
\r
1488 // item n+1 gets at any position with chance 1/(n+1)
\r
1489 // all others will get their 1/n chance reduced by factor n/(n+1)
\r
1490 // to be on place n+1, their chance will be 1/(n+1)
\r
1491 // 1/n * n/(n+1) = 1/(n+1)
\r
1493 j = floor(random() * (i + 1));
\r
1499 string substring_range(string s, float b, float e)
\r
1501 return substring(s, b, e - b);
\r
1504 string swapwords(string str, float i, float j)
\r
1507 string s1, s2, s3, s4, s5;
\r
1508 float si, ei, sj, ej, s0, en;
\r
1509 n = tokenizebyseparator(str, " "); // must match g_maplist processing in ShuffleMaplist and "shuffle"
\r
1510 si = argv_start_index(i);
\r
1511 sj = argv_start_index(j);
\r
1512 ei = argv_end_index(i);
\r
1513 ej = argv_end_index(j);
\r
1514 s0 = argv_start_index(0);
\r
1515 en = argv_end_index(n-1);
\r
1516 s1 = substring_range(str, s0, si);
\r
1517 s2 = substring_range(str, si, ei);
\r
1518 s3 = substring_range(str, ei, sj);
\r
1519 s4 = substring_range(str, sj, ej);
\r
1520 s5 = substring_range(str, ej, en);
\r
1521 return strcat(s1, s4, s3, s2, s5);
\r
1524 string _shufflewords_str;
\r
1525 void _shufflewords_swapfunc(float i, float j, entity pass)
\r
1527 _shufflewords_str = swapwords(_shufflewords_str, i, j);
\r
1529 string shufflewords(string str)
\r
1532 _shufflewords_str = str;
\r
1533 n = tokenizebyseparator(str, " ");
\r
1534 shuffle(n, _shufflewords_swapfunc, world);
\r
1535 str = _shufflewords_str;
\r
1536 _shufflewords_str = string_null;
\r
1540 vector solve_quadratic(float a, float b, float c) // ax^2 + bx + c = 0
\r
1549 v_x = v_y = -c / b;
\r
1556 // actually, every number solves the equation!
\r
1567 if(a > 0) // put the smaller solution first
\r
1569 v_x = ((-b)-D) / (2*a);
\r
1570 v_y = ((-b)+D) / (2*a);
\r
1574 v_x = (-b+D) / (2*a);
\r
1575 v_y = (-b-D) / (2*a);
\r
1581 // complex solutions!
\r
1595 float _unacceptable_compiler_bug_1_a(float b, float c) { return b == c; }
\r
1596 float _unacceptable_compiler_bug_1_b() { return 1; }
\r
1597 float _unacceptable_compiler_bug_1_c(float d) { return 2 * d; }
\r
1598 float _unacceptable_compiler_bug_1_d() { return 1; }
\r
1600 void check_unacceptable_compiler_bugs()
\r
1602 if(cvar("_allow_unacceptable_compiler_bugs"))
\r
1604 tokenize_console("foo bar");
\r
1605 if(strcat(argv(0), substring("foo bar", 4, 7 - argv_start_index(1))) == "barbar")
\r
1606 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
1609 float compressShotOrigin(vector v)
\r
1612 x = rint(v_x * 2);
\r
1613 y = rint(v_y * 4) + 128;
\r
1614 z = rint(v_z * 4) + 128;
\r
1615 if(x > 255 || x < 0)
\r
1617 print("shot origin ", vtos(v), " x out of bounds\n");
\r
1618 x = bound(0, x, 255);
\r
1620 if(y > 255 || y < 0)
\r
1622 print("shot origin ", vtos(v), " y out of bounds\n");
\r
1623 y = bound(0, y, 255);
\r
1625 if(z > 255 || z < 0)
\r
1627 print("shot origin ", vtos(v), " z out of bounds\n");
\r
1628 z = bound(0, z, 255);
\r
1630 return x * 0x10000 + y * 0x100 + z;
\r
1632 vector decompressShotOrigin(float f)
\r
1635 v_x = ((f & 0xFF0000) / 0x10000) / 2;
\r
1636 v_y = ((f & 0xFF00) / 0x100 - 128) / 4;
\r
1637 v_z = ((f & 0xFF) - 128) / 4;
\r
1641 void heapsort(float n, swapfunc_t swap, comparefunc_t cmp, entity pass)
\r
1643 float start, end, root, child;
\r
1646 start = floor((n - 2) / 2);
\r
1649 // siftdown(start, count-1);
\r
1651 while(root * 2 + 1 <= n-1)
\r
1653 child = root * 2 + 1;
\r
1655 if(cmp(child, child+1, pass) < 0)
\r
1657 if(cmp(root, child, pass) < 0)
\r
1659 swap(root, child, pass);
\r
1665 // end of siftdown
\r
1673 swap(0, end, pass);
\r
1675 // siftdown(0, end);
\r
1677 while(root * 2 + 1 <= end)
\r
1679 child = root * 2 + 1;
\r
1680 if(child < end && cmp(child, child+1, pass) < 0)
\r
1682 if(cmp(root, child, pass) < 0)
\r
1684 swap(root, child, pass);
\r
1690 // end of siftdown
\r
1694 void RandomSelection_Init()
\r
1696 RandomSelection_totalweight = 0;
\r
1697 RandomSelection_chosen_ent = world;
\r
1698 RandomSelection_chosen_float = 0;
\r
1699 RandomSelection_chosen_string = string_null;
\r
1700 RandomSelection_best_priority = -1;
\r
1702 void RandomSelection_Add(entity e, float f, string s, float weight, float priority)
\r
1704 if(priority > RandomSelection_best_priority)
\r
1706 RandomSelection_best_priority = priority;
\r
1707 RandomSelection_chosen_ent = e;
\r
1708 RandomSelection_chosen_float = f;
\r
1709 RandomSelection_chosen_string = s;
\r
1710 RandomSelection_totalweight = weight;
\r
1712 else if(priority == RandomSelection_best_priority)
\r
1714 RandomSelection_totalweight += weight;
\r
1715 if(random() * RandomSelection_totalweight <= weight)
\r
1717 RandomSelection_chosen_ent = e;
\r
1718 RandomSelection_chosen_float = f;
\r
1719 RandomSelection_chosen_string = s;
\r
1724 vector healtharmor_maxdamage(float h, float a, float armorblock)
\r
1726 // NOTE: we'll always choose the SMALLER value...
\r
1727 float healthdamage, armordamage, armorideal;
\r
1729 healthdamage = (h - 1) / (1 - armorblock); // damage we can take if we could use more health
\r
1730 armordamage = a + (h - 1); // damage we can take if we could use more armor
\r
1731 armorideal = healthdamage * armorblock;
\r
1733 if(armordamage < healthdamage)
\r
1735 v_x = armordamage;
\r
1740 v_x = healthdamage;
\r
1746 vector healtharmor_applydamage(float a, float armorblock, float damage)
\r
1749 v_y = bound(0, damage * armorblock, a); // save
\r
1750 v_x = bound(0, damage - v_y, damage); // take
\r
1755 string getcurrentmod()
\r
1759 m = cvar_string("fs_gamedir");
\r
1760 n = tokenize_console(m);
\r
1764 return argv(n - 1);
\r
1767 vector vec2(vector v)
\r
1775 float ReadInt24_t()
\r
1778 v = ReadShort() * 256; // note: this is signed
\r
1779 v += ReadByte(); // note: this is unsigned
\r
1783 void WriteInt24_t(float dest, float val)
\r
1786 WriteShort(dest, (v = floor(val / 256)));
\r
1787 WriteByte(dest, val - v * 256); // 0..255
\r
1792 float float2range11(float f)
\r
1794 // continuous function mapping all reals into -1..1
\r
1795 return f / (fabs(f) + 1);
\r
1798 float float2range01(float f)
\r
1800 // continuous function mapping all reals into 0..1
\r
1801 return 0.5 + 0.5 * float2range11(f);
\r
1804 // from the GNU Scientific Library
\r
1805 float gsl_ran_gaussian_lastvalue;
\r
1806 float gsl_ran_gaussian_lastvalue_set;
\r
1807 float gsl_ran_gaussian(float sigma)
\r
1810 if(gsl_ran_gaussian_lastvalue_set)
\r
1812 gsl_ran_gaussian_lastvalue_set = 0;
\r
1813 return sigma * gsl_ran_gaussian_lastvalue;
\r
1817 a = random() * 2 * M_PI;
\r
1818 b = sqrt(-2 * log(random()));
\r
1819 gsl_ran_gaussian_lastvalue = cos(a) * b;
\r
1820 gsl_ran_gaussian_lastvalue_set = 1;
\r
1821 return sigma * sin(a) * b;
\r
1825 string car(string s)
\r
1828 o = strstrofs(s, " ", 0);
\r
1831 return substring(s, 0, o);
\r
1833 string cdr(string s)
\r
1836 o = strstrofs(s, " ", 0);
\r
1838 return string_null;
\r
1839 return substring(s, o + 1, strlen(s) - (o + 1));
\r
1841 float matchacl(string acl, string str)
\r
1848 t = car(acl); acl = cdr(acl);
\r
1850 if(substring(t, 0, 1) == "-")
\r
1853 t = substring(t, 1, strlen(t) - 1);
\r
1855 else if(substring(t, 0, 1) == "+")
\r
1856 t = substring(t, 1, strlen(t) - 1);
\r
1857 if(substring(t, -1, 1) == "*")
\r
1859 t = substring(t, 0, strlen(t) - 1);
\r
1860 s = substring(s, 0, strlen(t));
\r
1872 float startsWith(string haystack, string needle)
\r
1874 return substring(haystack, 0, strlen(needle)) == needle;
\r
1876 float startsWithNocase(string haystack, string needle)
\r
1878 return strcasecmp(substring(haystack, 0, strlen(needle)), needle) == 0;
\r