X-Git-Url: http://git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fcommon%2Futil.qc;h=3567a2b095d522857ec2e2e4454de22c3e2d3dd5;hb=ba1679d72b9a726f53c206467c665ed8b75c5426;hp=87636d24e8446fddd1566e1b6c2e5edf9601e428;hpb=3b4e6bcd28b6b3d16304f54fc584c52ce2e57e49;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/common/util.qc b/qcsrc/common/util.qc index 87636d24e..3567a2b09 100644 --- a/qcsrc/common/util.qc +++ b/qcsrc/common/util.qc @@ -1,33 +1,153 @@ #include "util.qh" #if defined(CSQC) - #include "../client/defs.qh" #include "constants.qh" - #include "../client/mutators/events.qh" + #include #include "mapinfo.qh" #include "notifications/all.qh" + #include "scores.qh" #include #elif defined(MENUQC) #elif defined(SVQC) #include "constants.qh" - #include "../server/autocvars.qh" - #include "../server/defs.qh" - #include "../server/mutators/events.qh" + #include #include "notifications/all.qh" #include + #include "scores.qh" #include "mapinfo.qh" #endif +#ifdef SVQC +float tracebox_inverted (vector v1, vector mi, vector ma, vector v2, float nomonsters, entity forent, float stopatentity, entity ignorestopatentity) // returns the number of traces done, for benchmarking +{ + vector pos, dir, t; + float nudge; + entity stopentity; + + //nudge = 2 * cvar("collision_impactnudge"); // why not? + nudge = 0.5; + + dir = normalize(v2 - v1); + + pos = v1 + dir * nudge; + + float c; + c = 0; + + for (;;) + { + if(pos * dir >= v2 * dir) + { + // went too far + trace_fraction = 1; + trace_endpos = v2; + return c; + } + + tracebox(pos, mi, ma, v2, nomonsters, forent); + ++c; + + if(c == 50) + { + LOG_TRACE("When tracing from ", vtos(v1), " to ", vtos(v2)); + LOG_TRACE(" Nudging gets us nowhere at ", vtos(pos)); + LOG_TRACE(" trace_endpos is ", vtos(trace_endpos)); + LOG_TRACE(" trace distance is ", ftos(vlen(pos - trace_endpos))); + } + + stopentity = trace_ent; + + if(trace_startsolid) + { + // we started inside solid. + // then trace from endpos to pos + t = trace_endpos; + tracebox(t, mi, ma, pos, nomonsters, forent); + ++c; + if(trace_startsolid) + { + // t is still inside solid? bad + // force advance, then, and retry + pos = t + dir * nudge; + + // but if we hit an entity, stop RIGHT before it + if(stopatentity && stopentity && stopentity != ignorestopatentity) + { + trace_ent = stopentity; + trace_endpos = t; + trace_fraction = ((trace_endpos - v1) * dir) / ((v2 - v1) * dir); + return c; + } + } + else + { + // we actually LEFT solid! + trace_fraction = ((trace_endpos - v1) * dir) / ((v2 - v1) * dir); + return c; + } + } + else + { + // pos is outside solid?!? but why?!? never mind, just return it. + trace_endpos = pos; + trace_fraction = ((trace_endpos - v1) * dir) / ((v2 - v1) * dir); + return c; + } + } +} + +void traceline_inverted (vector v1, vector v2, float nomonsters, entity forent, float stopatentity, entity ignorestopatentity) +{ + tracebox_inverted(v1, '0 0 0', '0 0 0', v2, nomonsters, forent, stopatentity, ignorestopatentity); +} +#endif + #ifdef GAMEQC +/* +================== +findbetterlocation + +Returns a point at least 12 units away from walls +(useful for explosion animations, although the blast is performed where it really happened) +Ripped from DPMod +================== +*/ +vector findbetterlocation (vector org, float mindist) +{ + vector vec = mindist * '1 0 0'; + int c = 0; + while (c < 6) + { + traceline (org, org + vec, true, NULL); + vec = vec * -1; + if (trace_fraction < 1) + { + vector loc = trace_endpos; + traceline (loc, loc + vec, true, NULL); + if (trace_fraction >= 1) + org = loc + vec; + } + if (c & 1) + { + float h = vec.y; + vec.y = vec.x; + vec.x = vec.z; + vec.z = h; + } + c = c + 1; + } + + return org; +} + /* * Get "real" origin, in worldspace, even if ent is attached to something else. */ vector real_origin(entity ent) { - entity e; vector v = ((ent.absmin + ent.absmax) * 0.5); + entity e = ent.tag_entity; - e = ent.tag_entity; while(e) { v = v + ((e.absmin + e.absmax) * 0.5); @@ -97,7 +217,8 @@ void wordwrap_cb(string s, float l, void(string) callback) s = strzone(s); lleft = l; - for (i = 0;i < strlen(s);++i) + int len = strlen(s); + for (i = 0; i < len; ++i) { if (substring(s, i, 2) == "\\n") { @@ -115,12 +236,12 @@ void wordwrap_cb(string s, float l, void(string) callback) if (lleft > 0) { callback(" "); - lleft = lleft - 1; + --lleft; } } else { - for (j = i+1;j < strlen(s);++j) + for (j = i+1; j < len; ++j) // ^^ this skips over the first character of a word, which // is ALWAYS part of the word // this is safe since if i+1 == strlen(s), i will become @@ -148,7 +269,7 @@ void wordwrap_cb(string s, float l, void(string) callback) lleft = l; } callback(substring(s, i, wlen)); - lleft = lleft - wlen; + lleft -= wlen; i = j - 1; } } @@ -184,6 +305,7 @@ void depthfirst(entity start, .entity up, .entity downleft, .entity right, void( } } +#ifdef GAMEQC string ScoreString(int pFlags, float pValue) { string valstr; @@ -194,20 +316,7 @@ string ScoreString(int pFlags, float pValue) if((pValue == 0) && (pFlags & (SFL_HIDE_ZERO | SFL_RANK | SFL_TIME))) valstr = ""; else if(pFlags & SFL_RANK) - { - valstr = ftos(pValue); - l = strlen(valstr); - if((l >= 2) && (substring(valstr, l - 2, 1) == "1")) - valstr = strcat(valstr, "th"); - else if(substring(valstr, l - 1, 1) == "1") - valstr = strcat(valstr, "st"); - else if(substring(valstr, l - 1, 1) == "2") - valstr = strcat(valstr, "nd"); - else if(substring(valstr, l - 1, 1) == "3") - valstr = strcat(valstr, "rd"); - else - valstr = strcat(valstr, "th"); - } + valstr = count_ordinal(pValue); else if(pFlags & SFL_TIME) valstr = TIME_ENCODED_TOSTRING(pValue); else @@ -215,6 +324,7 @@ string ScoreString(int pFlags, float pValue) return valstr; } +#endif // compressed vector format: // like MD3, just even shorter @@ -228,13 +338,13 @@ string ScoreString(int pFlags, float pValue) float lengthLogTable[128]; -float invertLengthLog(float x) +float invertLengthLog(float dist) { int l, r, m; - if(x >= lengthLogTable[127]) + if(dist >= lengthLogTable[127]) return 127; - if(x <= lengthLogTable[0]) + if(dist <= lengthLogTable[0]) return 0; l = 0; @@ -243,15 +353,15 @@ float invertLengthLog(float x) while(r - l > 1) { m = floor((l + r) / 2); - if(lengthLogTable[m] < x) + if(lengthLogTable[m] < dist) l = m; else r = m; } // now: r is >=, l is < - float lerr = (x - lengthLogTable[l]); - float rerr = (lengthLogTable[r] - x); + float lerr = (dist - lengthLogTable[l]); + float rerr = (lengthLogTable[r] - dist); if(lerr < rerr) return l; return r; @@ -263,26 +373,26 @@ vector decompressShortVector(int data) if(data == 0) return '0 0 0'; float p = (data & 0xF000) / 0x1000; - float y = (data & 0x0F80) / 0x80; + float q = (data & 0x0F80) / 0x80; int len = (data & 0x007F); - //print("\ndecompress: p ", ftos(p)); print("y ", ftos(y)); print("len ", ftos(len), "\n"); + //print("\ndecompress: p ", ftos(p)); print("q ", ftos(q)); print("len ", ftos(len), "\n"); if(p == 0) { out.x = 0; out.y = 0; - if(y == 31) + if(q == 31) out.z = -1; else out.z = +1; } else { - y = .19634954084936207740 * y; + q = .19634954084936207740 * q; p = .19634954084936207740 * p - 1.57079632679489661922; - out.x = cos(y) * cos(p); - out.y = sin(y) * cos(p); + out.x = cos(q) * cos(p); + out.y = sin(q) * cos(p); out.z = -sin(p); } @@ -326,7 +436,7 @@ float compressShortVector(vector vec) STATIC_INIT(compressShortVector) { float l = 1; - float f = pow(2, 1/8); + float f = (2 ** (1/8)); int i; for(i = 0; i < 128; ++i) { @@ -334,19 +444,20 @@ STATIC_INIT(compressShortVector) l *= f; } - if(cvar("developer")) + if(cvar("developer") > 0) { - LOG_INFO("Verifying vector compression table...\n"); + LOG_TRACE("Verifying vector compression table..."); for(i = 0x0F00; i < 0xFFFF; ++i) if(i != compressShortVector(decompressShortVector(i))) { - LOG_INFO("BROKEN vector compression: ", ftos(i)); - LOG_INFO(" -> ", vtos(decompressShortVector(i))); - LOG_INFO(" -> ", ftos(compressShortVector(decompressShortVector(i)))); - LOG_INFO("\n"); - error("b0rk"); + LOG_FATALF( + "BROKEN vector compression: %s -> %s -> %s", + ftos(i), + vtos(decompressShortVector(i)), + ftos(compressShortVector(decompressShortVector(i))) + ); } - LOG_INFO("Done.\n"); + LOG_TRACE("Done."); } } @@ -397,8 +508,8 @@ string fixPriorityList(string order, float from, float to, float subtract, float n = tokenize_console(neworder); for(w = to; w >= from; --w) { - int wflags = Weapons_from(w).spawnflags; - if((wflags & WEP_FLAG_HIDDEN) && (wflags & WEP_FLAG_MUTATORBLOCKED) && !(wflags & WEP_FLAG_NORMAL)) + int wflags = REGISTRY_GET(Weapons, w).spawnflags; + if(wflags & WEP_FLAG_SPECIALATTACK) continue; for(i = 0; i < n; ++i) if(stof(argv(i)) == w) @@ -414,11 +525,11 @@ string fixPriorityList(string order, float from, float to, float subtract, float string mapPriorityList(string order, string(string) mapfunc) { string neworder; - float i, n; + float n; n = tokenize_console(order); neworder = ""; - for(i = 0; i < n; ++i) + for(float i = 0; i < n; ++i) neworder = strcat(neworder, mapfunc(argv(i)), " "); return substring(neworder, 0, strlen(neworder) - 1); @@ -426,15 +537,12 @@ string mapPriorityList(string order, string(string) mapfunc) string swapInPriorityList(string order, float i, float j) { - string s; - float w, n; - - n = tokenize_console(order); + float n = tokenize_console(order); if(i >= 0 && i < n && j >= 0 && j < n && i != j) { - s = ""; - for(w = 0; w < n; ++w) + string s = ""; + for(float w = 0; w < n; ++w) { if(w == i) s = strcat(s, argv(j), " "); @@ -454,14 +562,12 @@ void get_mi_min_max(float mode) { vector mi, ma; - if(mi_shortname) - strunzone(mi_shortname); - mi_shortname = mapname; - if(!strcasecmp(substring(mi_shortname, 0, 5), "maps/")) - mi_shortname = substring(mi_shortname, 5, strlen(mi_shortname) - 5); - if(!strcasecmp(substring(mi_shortname, strlen(mi_shortname) - 4, 4), ".bsp")) - mi_shortname = substring(mi_shortname, 0, strlen(mi_shortname) - 4); - mi_shortname = strzone(mi_shortname); + string s = mapname; + if(!strcasecmp(substring(s, 0, 5), "maps/")) + s = substring(s, 5, strlen(s) - 5); + if(!strcasecmp(substring(s, strlen(s) - 4, 4), ".bsp")) + s = substring(s, 0, strlen(s) - 4); + strcpy(mi_shortname, s); #ifdef CSQC mi = world.mins; @@ -599,7 +705,7 @@ float cvar_settemp(string tmp_cvar, string tmp_value) if(!cvar_type(tmp_cvar)) { - LOG_INFOF("Error: cvar %s doesn't exist!\n", tmp_cvar); + LOG_INFOF("Error: cvar %s doesn't exist!", tmp_cvar); return 0; } @@ -641,7 +747,7 @@ int cvar_settemp_restore() ++j; } else - LOG_INFOF("Error: cvar %s doesn't exist anymore! It can still be restored once it's manually recreated.\n", it.netname); + LOG_INFOF("Error: cvar %s doesn't exist anymore! It can still be restored once it's manually recreated.", it.netname); }); #else @@ -655,7 +761,7 @@ int cvar_settemp_restore() ++j; } else - print(sprintf("Error: cvar %s doesn't exist anymore! It can still be restored once it's manually recreated.\n", e.netname)); + print(sprintf("Error: cvar %s doesn't exist anymore! It can still be restored once it's manually recreated.", e.netname)); } #endif @@ -672,7 +778,6 @@ bool isCaretEscaped(string theText, float pos) int skipIncompleteTag(string theText, float pos, int len) { - int i = 0, ch = 0; int tag_start = -1; if(substring(theText, pos - 1, 1) == "^") @@ -680,7 +785,7 @@ int skipIncompleteTag(string theText, float pos, int len) if(isCaretEscaped(theText, pos - 1) || pos >= len) return 0; - ch = str2chr(theText, pos); + int ch = str2chr(theText, pos); if(ch >= '0' && ch <= '9') return 1; // ^[0-9] color code found else if (ch == 'x') @@ -690,7 +795,7 @@ int skipIncompleteTag(string theText, float pos, int len) } else { - for(i = 2; pos - i >= 0 && i <= 4; ++i) + for(int i = 2; pos - i >= 0 && i <= 4; ++i) { if(substring(theText, pos - i, 2) == "^x") { @@ -784,8 +889,7 @@ string find_last_color_code(string s) if (start == -1) // no caret found return ""; int len = strlen(s)-1; - int i; - for(i = len; i >= start; --i) + for(int i = len; i >= start; --i) { if(substring(s, i, 1) != "^") continue; @@ -1073,26 +1177,25 @@ vector get_shotvelocity(vector myvel, vector mydir, float spd, float newton_styl float compressShotOrigin(vector v) { - float x, y, z; - x = rint(v.x * 2); - y = rint(v.y * 4) + 128; - z = rint(v.z * 4) + 128; - if(x > 255 || x < 0) + float rx = rint(v.x * 2); + float ry = rint(v.y * 4) + 128; + float rz = rint(v.z * 4) + 128; + if(rx > 255 || rx < 0) { - LOG_INFO("shot origin ", vtos(v), " x out of bounds\n"); - x = bound(0, x, 255); + LOG_DEBUG("shot origin ", vtos(v), " x out of bounds\n"); + rx = bound(0, rx, 255); } - if(y > 255 || y < 0) + if(ry > 255 || ry < 0) { - LOG_INFO("shot origin ", vtos(v), " y out of bounds\n"); - y = bound(0, y, 255); + LOG_DEBUG("shot origin ", vtos(v), " y out of bounds\n"); + ry = bound(0, ry, 255); } - if(z > 255 || z < 0) + if(rz > 255 || rz < 0) { - LOG_INFO("shot origin ", vtos(v), " z out of bounds\n"); - z = bound(0, z, 255); + LOG_DEBUG("shot origin ", vtos(v), " z out of bounds\n"); + rz = bound(0, rz, 255); } - return x * 0x10000 + y * 0x100 + z; + return rx * 0x10000 + ry * 0x100 + rz; } vector decompressShotOrigin(int f) { @@ -1133,6 +1236,8 @@ vector healtharmor_applydamage(float a, float armorblock, int deathtype, float d vector v; if (DEATH_IS(deathtype, DEATH_DROWN)) // Why should armor help here... armorblock = 0; + if (deathtype & HITTYPE_ARMORPIERCE) + armorblock = 0; v.y = bound(0, damage * armorblock, a); // save v.x = bound(0, damage - v.y, damage); // take v.z = 0; @@ -1181,11 +1286,19 @@ float matchacl(string acl, string str) if(s == t) { r = d; + break; // if we found a killing case, apply it! other settings may be allowed in the future, but this one is caught } } return r; } +ERASEABLE +void write_String_To_File(int fh, string str, bool alsoprint) +{ + fputs(fh, str); + if (alsoprint) LOG_INFO(str); +} + string get_model_datafilename(string m, float sk, string fil) { if(m) @@ -1273,7 +1386,12 @@ float get_model_parameters(string m, float sk) case "reserved": get_model_parameters_species = SPECIES_RESERVED; break; } if(c == "sex") + { + if (s == "Male") s = _("Male"); + else if (s == "Female") s = _("Female"); + else if (s == "Undisclosed") s = _("Undisclosed"); get_model_parameters_sex = s; + } if(c == "weight") get_model_parameters_weight = stof(s); if(c == "age") @@ -1312,6 +1430,158 @@ float get_model_parameters(string m, float sk) return 1; } +string translate_key(string key) +{ + if (prvm_language == "en") return key; + + if (substring(key, 0, 1) == "<") + { + if (key == "") return _(""); + if (key == "") return _(""); + } + + switch(key) + { + case "TAB": return _("TAB"); + case "ENTER": return _("ENTER"); + case "ESCAPE": return _("ESCAPE"); + case "SPACE": return _("SPACE"); + + case "BACKSPACE": return _("BACKSPACE"); + case "UPARROW": return _("UPARROW"); + case "DOWNARROW": return _("DOWNARROW"); + case "LEFTARROW": return _("LEFTARROW"); + case "RIGHTARROW": return _("RIGHTARROW"); + + case "ALT": return _("ALT"); + case "CTRL": return _("CTRL"); + case "SHIFT": return _("SHIFT"); + + case "INS": return _("INS"); + case "DEL": return _("DEL"); + case "PGDN": return _("PGDN"); + case "PGUP": return _("PGUP"); + case "HOME": return _("HOME"); + case "END": return _("END"); + + case "PAUSE": return _("PAUSE"); + + case "NUMLOCK": return _("NUMLOCK"); + case "CAPSLOCK": return _("CAPSLOCK"); + case "SCROLLOCK": return _("SCROLLOCK"); + + case "SEMICOLON": return _("SEMICOLON"); + case "TILDE": return _("TILDE"); + case "BACKQUOTE": return _("BACKQUOTE"); + case "QUOTE": return _("QUOTE"); + case "APOSTROPHE": return _("APOSTROPHE"); + case "BACKSLASH": return _("BACKSLASH"); + } + + if (substring(key, 0, 1) == "F") + { + string subkey = substring(key, 1, -1); + if (IS_DIGIT(substring(key, 3, 1))) // check only first digit + { + return sprintf(_("F%d"), stof(subkey)); + } + // continue in case there is another key name starting with F + } + + if (substring(key, 0, 3) == "KP_") + { + string subkey = substring(key, 3, -1); + if (IS_DIGIT(substring(key, 3, 1))) // check only first digit + { + return sprintf(_("KP_%d"), stof(subkey)); + } + + switch(subkey) + { + case "INS": return sprintf(_("KP_%s"), _("INS")); + case "END": return sprintf(_("KP_%s"), _("END")); + case "DOWNARROW": return sprintf(_("KP_%s"), _("DOWNARROW")); + case "PGDN": return sprintf(_("KP_%s"), _("PGDN")); + case "LEFTARROW": return sprintf(_("KP_%s"), _("LEFTARROW")); + case "RIGHTARROW": return sprintf(_("KP_%s"), _("RIGHTARROW")); + case "HOME": return sprintf(_("KP_%s"), _("HOME")); + case "UPARROW": return sprintf(_("KP_%s"), _("UPARROW")); + case "PGUP": return sprintf(_("KP_%s"), _("PGUP")); + case "PERIOD": return sprintf(_("KP_%s"), _("PERIOD")); + case "DEL": return sprintf(_("KP_%s"), _("DEL")); + case "DIVIDE": return sprintf(_("KP_%s"), _("DIVIDE")); + case "SLASH": return sprintf(_("KP_%s"), _("SLASH")); + case "MULTIPLY": return sprintf(_("KP_%s"), _("MULTIPLY")); + case "MINUS": return sprintf(_("KP_%s"), _("MINUS")); + case "PLUS": return sprintf(_("KP_%s"), _("PLUS")); + case "ENTER": return sprintf(_("KP_%s"), _("ENTER")); + case "EQUALS": return sprintf(_("KP_%s"), _("EQUALS")); + default: return key; + } + } + + if (key == "PRINTSCREEN") return _("PRINTSCREEN"); + + if (substring(key, 0, 5) == "MOUSE") + return sprintf(_("MOUSE%d"), stof(substring(key, 5, -1))); + + if (key == "MWHEELUP") return _("MWHEELUP"); + if (key == "MWHEELDOWN") return _("MWHEELDOWN"); + + if (substring(key, 0,3) == "JOY") + return sprintf(_("JOY%d"), stof(substring(key, 3, -1))); + + if (substring(key, 0,3) == "AUX") + return sprintf(_("AUX%d"), stof(substring(key, 3, -1))); + + if (substring(key, 0, 4) == "X360_") + { + string subkey = substring(key, 4, -1); + switch(subkey) + { + case "DPAD_UP": return sprintf(_("X360_%s"), _("DPAD_UP")); + case "DPAD_DOWN": return sprintf(_("X360_%s"), _("DPAD_DOWN")); + case "DPAD_LEFT": return sprintf(_("X360_%s"), _("DPAD_LEFT")); + case "DPAD_RIGHT": return sprintf(_("X360_%s"), _("DPAD_RIGHT")); + case "START": return sprintf(_("X360_%s"), _("START")); + case "BACK": return sprintf(_("X360_%s"), _("BACK")); + case "LEFT_THUMB": return sprintf(_("X360_%s"), _("LEFT_THUMB")); + case "RIGHT_THUMB": return sprintf(_("X360_%s"), _("RIGHT_THUMB")); + case "LEFT_SHOULDER": return sprintf(_("X360_%s"), _("LEFT_SHOULDER")); + case "RIGHT_SHOULDER": return sprintf(_("X360_%s"), _("RIGHT_SHOULDER")); + case "LEFT_TRIGGER": return sprintf(_("X360_%s"), _("LEFT_TRIGGER")); + case "RIGHT_TRIGGER": return sprintf(_("X360_%s"), _("RIGHT_TRIGGER")); + case "LEFT_THUMB_UP": return sprintf(_("X360_%s"), _("LEFT_THUMB_UP")); + case "LEFT_THUMB_DOWN": return sprintf(_("X360_%s"), _("LEFT_THUMB_DOWN")); + case "LEFT_THUMB_LEFT": return sprintf(_("X360_%s"), _("LEFT_THUMB_LEFT")); + case "LEFT_THUMB_RIGHT": return sprintf(_("X360_%s"), _("LEFT_THUMB_RIGHT")); + case "RIGHT_THUMB_UP": return sprintf(_("X360_%s"), _("RIGHT_THUMB_UP")); + case "RIGHT_THUMB_DOWN": return sprintf(_("X360_%s"), _("RIGHT_THUMB_DOWN")); + case "RIGHT_THUMB_LEFT": return sprintf(_("X360_%s"), _("RIGHT_THUMB_LEFT")); + case "RIGHT_THUMB_RIGHT": return sprintf(_("X360_%s"), _("RIGHT_THUMB_RIGHT")); + default: return key; + } + } + + if (substring(key, 0, 4) == "JOY_") + { + string subkey = substring(key, 4, -1); + switch(subkey) + { + case "UP": return sprintf(_("JOY_%s"), _("UP")); + case "DOWN": return sprintf(_("JOY_%s"), _("DOWN")); + case "LEFT": return sprintf(_("JOY_%s"), _("LEFT")); + case "RIGHT": return sprintf(_("JOY_%s"), _("RIGHT")); + default: return key; + } + } + + if (substring(key, 0, 8) == "MIDINOTE") + return sprintf(_("MIDINOTE%d"), stof(substring(key, 8, -1))); + + return key; +} + // x-encoding (encoding as zero length invisible string) const string XENCODE_2 = "xX"; const string XENCODE_22 = "0123456789abcdefABCDEF"; @@ -1368,7 +1638,7 @@ void m_shutdown() { if(shutdown_running) { - LOG_INFO("Recursive shutdown detected! Only restoring cvars...\n"); + LOG_INFO("Recursive shutdown detected! Only restoring cvars..."); } else { @@ -1401,8 +1671,7 @@ void execute_next_frame() if(to_execute_next_frame) { localcmd("\n", to_execute_next_frame, "\n"); - strunzone(to_execute_next_frame); - to_execute_next_frame = string_null; + strfree(to_execute_next_frame); } } void queue_to_execute_next_frame(string s) @@ -1410,9 +1679,8 @@ void queue_to_execute_next_frame(string s) if(to_execute_next_frame) { s = strcat(s, "\n", to_execute_next_frame); - strunzone(to_execute_next_frame); } - to_execute_next_frame = strzone(s); + strcpy(to_execute_next_frame, s); } .float FindConnectedComponent_processing;