From 2754b3f9f7869e1731bf0a070c4b2fcfc921f437 Mon Sep 17 00:00:00 2001 From: Markus Mittendrein Date: Thu, 1 Apr 2021 17:22:30 +0200 Subject: Add CrewSelection rule --- System.c4g/DTArrays.c | 52 +++ System.c4g/DTCallback.c | 397 +++++++++++++++++++++ System.c4g/DTCrewSelection.c | 12 + System.c4g/DTScopedVars.c | 108 ++++++ System.c4g/DTUtility.c | 817 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 1386 insertions(+) create mode 100644 System.c4g/DTArrays.c create mode 100644 System.c4g/DTCallback.c create mode 100644 System.c4g/DTCrewSelection.c create mode 100644 System.c4g/DTScopedVars.c create mode 100644 System.c4g/DTUtility.c (limited to 'System.c4g') diff --git a/System.c4g/DTArrays.c b/System.c4g/DTArrays.c new file mode 100644 index 0000000..0b78ef4 --- /dev/null +++ b/System.c4g/DTArrays.c @@ -0,0 +1,52 @@ +#strict 2 + +global func ArrayErase(array& arr, int index) +{ + if(index < GetLength(arr)) + { + for(var i = index; i < GetLength(arr) - 1; ++i) + { + arr[i] = arr[i + 1]; + } + SetLength(arr, GetLength(arr) - 1); + } +} + +global func ArrayEraseItem(array& arr, item, bool multiple) +{ + var index, count = 0; + while((index = GetIndexOf2(item, arr)) != -1) + { + ArrayErase(arr, index); + if(!multiple) + { + return index; + } + ++count; + } + return (!multiple && -1) || count; +} + +global func ArrayInsert(array& arr, int index, value) +{ + for(var i = GetLength(arr); i > index; --i) + { + arr[i] = arr[i - 1]; + } + arr[index] = value; +} + +global func ArrayAppend(array& arr, value) +{ + arr[GetLength(arr)] = value; +} + +global func ArrayAppendArray(array& arr, array append) +{ + var i = GetLength(arr); + SetLength(arr, GetLength(arr) + GetLength(append)); + for(var val in append) + { + arr[i++] = val; + } +} diff --git a/System.c4g/DTCallback.c b/System.c4g/DTCallback.c new file mode 100644 index 0000000..91730d2 --- /dev/null +++ b/System.c4g/DTCallback.c @@ -0,0 +1,397 @@ +/*-- Extensible callback system --*/ +#strict 2 + +static const CallbackTarget_Bind = -1; +static const CallbackTarget_Global = -2; +static const CallbackTarget_Scenario = -3; + +// NOTE: fast callbacks (fast = true for ObjectCallback or DefinitionCallback) use ObjectCall/DefinitionCall directly for greater performance if possible (refs == 0 and GetLength(args) <= 8 for CallA()) and thus must be real functions of the desired object/definition. safe mode is ignored for fast callbacks + +global func GlobalCallback(string name) { return [CallbackTarget_Global, name]; } +global func ScenarioCallback(string name) { return [CallbackTarget_Scenario, name]; } +global func ObjectCallback(string name, bool fast, object target) { return [target || this || FatalError("ObjectCallback without target object"), name, fast]; } +global func DefinitionCallback(string name, bool fast, id target) { return [target || GetID() || FatalError("DefinitionCallback without target definition"), name, fast]; } +global func Callback(string name, target) { return [target || this || GetID() || CallbackTarget_Global, name]; } +global func BindCallback(callback, array binding) { return [CallbackTarget_Bind, callback, binding]; } + +static const BindCallback_Bind_Value = -1; +static const BindCallback_Bind_Context = -2; +static const BindCallback_Bind_ContextDef = -3; +static const BindCallback_Bind_CallbackResult = -4; +static const BindCallback_Bind_ArgumentArrayPart = -5; +static const BindCallback_Bind_Reference = -6; +global func Bind(value) { return [BindCallback_Bind_Value, value]; } +global func Bind_Context() { return [BindCallback_Bind_Context]; } +global func Bind_ContextDef() { return [BindCallback_Bind_ContextDef]; } +global func Bind_CallbackResult(callback) { return [BindCallback_Bind_CallbackResult, callback]; } +global func Bind_ArgumentArrayPart(int argument, part) +{ + if(GetType(part) != C4V_Array) + { + part = [part]; + } + return [BindCallback_Bind_ArgumentArrayPart, argument, part]; +} +global func Bind_Reference(array scopedVar) { return [BindCallback_Bind_Reference, scopedVar]; } + +global func Call(callback) +{ + if(GetType(callback) == C4V_String) + { + return _inherited(callback, ...); + } + else + { + return CallA(callback, CreateFilledArray(...)); + } +} + +global func CallA(callback, args, bool safe, array refs) +{ + if(GetType(callback) == C4V_String) + { + callback = [this, callback, true]; + } + + if(GetType(callback) != C4V_Array) + { + return _inherited(callback, args, ...); + } + + var target = callback[0], function = callback[1]; + + if((GetType(target) == C4V_C4Object || GetType(target) == C4V_C4ID) && GetLength(callback) == 3 && callback[2] && (!refs || refs == []) && GetLength(args) <= 8) // fast callback + { + if(GetType(target) == C4V_C4Object) + { + return ObjectCall(target, function, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]); + } + else if(GetType(target) == C4V_C4ID) + { + return DefinitionCall(target, function, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]); + } + } + + refs = refs || []; + + if(target == CallbackTarget_Scenario) + { + return GameCall(function, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]); + } + else if(target == CallbackTarget_Bind) + { + return CallA(function, BindArgs(callback[2], args, safe, refs), safe, refs); + } + + if(GetType(target) == C4V_C4Object || GetType(target) == C4V_C4ID || target == CallbackTarget_Global) + { + var safeModifier = ""; + if(safe) + { + safeModifier = "~"; + } + var argsStr = "", pos = 0; + for(var arg in args) + { + if(pos > 0) + { + argsStr = Format("%s, ", argsStr); + } + if(refs[pos]) + { + argsStr = Format("%sScopedVar(%s)", argsStr, Serialize(arg)); + } + else + { + argsStr = Format("%s%s", argsStr, Serialize(arg)); + } + ++pos; + } + + if(target == CallbackTarget_Global) + { + return GlobalEval(Format("%s(%s)", function, argsStr)); + } + else if(GetType(target) == C4V_C4Object || GetType(target) == C4V_C4ID) + { + return eval(Format("%s->%s%s(%s)", Serialize(target), safeModifier, function, argsStr)); + } + } + else + { + if(this) + { + return this->~CallCustom(callback, args, ...); + } + else if(GetID()) + { + return GetID()->~CallCustom(callback, args, ...); + } + else + { + return CallCustom(callback, args, ...); + } + } +} + +global func CallCustom() { return _inherited(...); } + +global func BindArgs_ArgumentArrayPart(array binding, array args, bool safe) +{ + var ret = args[binding[0]]; + for(var i = 1; i < GetLength(binding); ++i) + { + if(!safe || GetType(ret) == C4V_Array) + { + ret = ret[binding[i]]; + } + else + { + return 0; + } + } + return ret; +} + +global func BindCustomArgs() { return _inherited(...); } // this allows "overloading" this function even if the "overloading" function is loaded before + +global func BindArgs(array binding, array args, bool safe, array& refs) +{ + refs = []; + var ret = CreateArray(GetLength(binding)), pos = 0; + for(var bind in binding) + { + if(GetType(bind) == C4V_Int || GetType(bind) == C4V_Any && bind >= 0) + { + ret[pos] = args[bind]; + } + else if(GetType(bind) == C4V_Array && GetLength(bind)) + { + if(bind[0] == BindCallback_Bind_Value) + { + ret[pos] = bind[1]; + } + else if(bind[0] == BindCallback_Bind_Context) + { + ret[pos] = this; + } + else if(bind[0] == BindCallback_Bind_ContextDef) + { + ret[pos] = GetID(); + } + else if(bind[0] == BindCallback_Bind_CallbackResult) + { + ret[pos] = CallA(bind[1], args, safe); + } + else if(bind[0] == BindCallback_Bind_ArgumentArrayPart) + { + ret[pos] = BindArgs_ArgumentArrayPart(bind[2], args[bind[1]], safe); + } + else if(bind[0] == BindCallback_Bind_Reference) + { + refs[pos] = true; + ret[pos] = bind[1]; + } + else if(GetType(bind[0]) == C4V_Int && bind[0] < 0) + { + if(this) + { + ret[pos] = this->~BindCustomArgs(bind, args, safe); + } + else if(GetID()) + { + ret[pos] = GetID()->~BindCustomArgs(bind, args, safe); + } + else + { + ret[pos] = BindCustomArgs(bind, args, safe); + } + } + else + { + ret[pos] = BindArgs(bind, args, safe); + } + } + else + { + FatalError(Format("BindArgs: incorrect binding %v", bind)); + } + ++pos; + } + return ret; +} + +global func GlobalEval(string code) +{ + var effect = AddEffect("IntGlobalEval", 0, 1); + var ret = EffectCall(0, effect, "Eval", code); + RemoveEffect(0, 0, effect); + return ret; +} + +global func FxIntGlobalEvalEval(object target, int effectNumber, string code) +{ + return eval(code); +} + +global func foreach(array arr, callback) +{ + var i = 0; + for(var val in arr) + { + CallA(callback, [val, i++]); + } +} + +global func CheckCallback(callback) +{ + if(GetType(callback) == C4V_String) + { + return true; + } + + if(GetType(callback) == C4V_Array) + { + if(GetType(callback[0]) == C4V_Int) + { + if(callback[0] == CallbackTarget_Bind && GetLength(callback) == 3) + { + if(CheckCallback(callback[1]) && CheckBindCallbackBinding(callback[2])) + { + return true; + } + } + else if(callback[0] == CallbackTarget_Global || callback[0] == CallbackTarget_Scenario) + { + if(GetLength(callback) == 2 && GetType(callback[1]) == C4V_String && callback[1] != "") + { + return true; + } + } + } + else if(GetType(callback[0]) == C4V_C4ID || GetType(callback[0]) == C4V_C4Object) + { + if(GetLength(callback) == 2 || (GetLength(callback) == 3 && (!callback[2] || GetType(callback[2]) == C4V_Bool))) // length 2 for callbacks created by Callback() or Object/DefinitionCallback() before fast was introduced + { + if(GetType(callback[1]) == C4V_String && callback[1] != "") + { + return true; + } + } + } + } + + if(this) + { + return this->~CheckCustomCallback(callback, ...); + } + else if(GetID()) + { + return GetID()->~CheckCustomCallback(callback, ...); + } + else + { + return CheckCustomCallback(callback, ...); + } +} + +// to silence the error if no ScopedVars are included +global func CheckScopedVar() { return _inherited(...); } + +global func CheckCustomCallback() { return _inherited(...); } + +global func CheckBindCallbackBinding(array binding) +{ + for(var b in binding) + { + if(b && GetType(b) != C4V_Int) + { + if(GetType(b) == C4V_Array) + { + if(b[0] == BindCallback_Bind_Value) + { + if(GetLength(b) != 2) + { + return false; + } + } + else if(b[0] == BindCallback_Bind_Context || b[0] == BindCallback_Bind_ContextDef) + { + continue; + } + else if(b[0] == BindCallback_Bind_CallbackResult) + { + if(GetLength(b) != 2 || !CheckCallback(b[1])) + { + return false; + } + } + else if(b[0] == BindCallback_Bind_ArgumentArrayPart) + { + if(GetLength(b) != 3) + { + return false; + } + + if(b[1] && (GetType(b[1]) != C4V_Int || b[1] < 0)) + { + return false; + } + + for(var part in b[2]) + { + if(part && (GetType(part) != C4V_Int || part < 0)) + { + return false; + } + } + } + else if(b[0] == BindCallback_Bind_Reference) + { + if(GetLength(b) != 2 || !CheckScopedVar(b[1])) + { + return false; + } + } + else if(GetType(b[0]) == C4V_Int && b[0] < 0) + { + var ret; + if(this) + { + ret = this->~CheckBindCallbackCustomBinding(b); + } + else if(GetID()) + { + ret = GetID()->~CheckBindCallbackCustomBinding(b); + } + else + { + ret = CheckBindCallbackCustomBinding(b); + } + if(!ret) + { + return false; + } + } + else + { + if(!CheckBindCallbackBinding(b)) + { + return false; + } + } + } + else + { + return false; + } + } + else if(b < 0) + { + return false; + } + } + return true; +} + +global func CheckBindCallbackCustomBinding() { return _inherited(...); } \ No newline at end of file diff --git a/System.c4g/DTCrewSelection.c b/System.c4g/DTCrewSelection.c new file mode 100644 index 0000000..4e12db1 --- /dev/null +++ b/System.c4g/DTCrewSelection.c @@ -0,0 +1,12 @@ +#strict 2 +#appendto CLNK + +func Initialize() +{ + if(!FindObject(CS7I)) + { + CreateObject(CS7I, 0, 0, NO_OWNER); + } + + return _inherited(...); +} \ No newline at end of file diff --git a/System.c4g/DTScopedVars.c b/System.c4g/DTScopedVars.c new file mode 100644 index 0000000..0cde670 --- /dev/null +++ b/System.c4g/DTScopedVars.c @@ -0,0 +1,108 @@ +#strict 2 +// TODO: ScopedVars with temporary target (like a reference to a function local var) + +static const ScopedVar_Global = 1; +static const ScopedVar_Local = 2; +static const ScopedVar_ArrayIndex = 3; + +global func GlobalVar(name) { return [ScopedVar_Global, name]; } +global func LocalVar(name, object target) { return [ScopedVar_Local, name, target || this]; } +global func ArrayVar(index, array scopedVar) { return [ScopedVar_ArrayIndex, scopedVar, index]; } + +global func &ScopedVar(array variable) +{ + if(!variable) + { + return 0; + } + if(variable[0] == ScopedVar_Global) + { + if(GetType(variable[1]) == C4V_String) + { + return GlobalN(variable[1]); + } + else + { + return Global(variable[1]); + } + } + else if(variable[0] == ScopedVar_Local) + { + if(GetType(variable[1]) == C4V_String) + { + return LocalN(variable[1], variable[2]); + } + else + { + return Local(variable[1], variable[2]); + } + } + else if(variable[0] == ScopedVar_ArrayIndex) + { + var index = variable[2]; + if(GetType(index) != C4V_Int && GetType(index) != C4V_Any) + { + index = ScopedVar(index); + } + return ScopedVar(variable[1])[index]; + } + else + { + if(this) + { + return ScopedVar(this->~CustomScopedVar(variable)); + } + else if(GetID()) + { + return ScopedVar(GetID()->~CustomScopedVar(variable)); + } + else + { + return ScopedVar(CustomScopedVar(variable)); + } + } +} + +global func CustomScopedVar() { return _inherited(...); } // this allows "overloading" this function even if the "overloading" function is loaded before + +global func CheckScopedVar(array variable) +{ + if(!variable) + { + return false; + } + + if(GetType(variable[0]) == C4V_Int) + { + if(variable[0] == ScopedVar_Global || variable[0] == ScopedVar_Local) + { + if(!variable[1] || GetType(variable[1]) == C4V_Int || (GetType(variable[1]) == C4V_String && variable[1] != "")) + { + return true; + } + } + + if(variable[0] == ScopedVar_ArrayIndex) + { + if(CheckScopedVar(variable[1]) && !variable[2] || (GetType(variable[2]) == C4V_Int && variable[2] >= 0)) + { + return true; + } + } + } + + if(this) + { + return this->~CheckCustomScopedVar(variable); + } + else if(GetID()) + { + return GetID()->~CheckCustomScopedVar(variable); + } + else + { + return CheckCustomScopedVar(variable); + } +} + +global func CheckCustomScopedVar() { return _inherited(...); } \ No newline at end of file diff --git a/System.c4g/DTUtility.c b/System.c4g/DTUtility.c new file mode 100644 index 0000000..d491567 --- /dev/null +++ b/System.c4g/DTUtility.c @@ -0,0 +1,817 @@ +#strict 2 + +global func Isolate(object obj) // Puts the object in its own layer to prevent interaction +{ + obj || obj = this; + return obj->SetObjectLayer(obj); +} + +global func GetIndexOf2(val, array arr) // Because GetIndexOf doesn't find Format("%c", GetChar("a", 0)) in ["a"] +{ + var i = 0; + for(var value in arr) + { + if(val == value) return i; + ++i; + } + return -1; +} + +global func Serialize(value) +{ + if(GetType(value) == C4V_Array) + { + var first = true; + var ret = "["; + for(var val in value) + { + if(first) + { + first = false; + } + else + { + ret = Format("%s,", ret); + } + ret = Format("%s%s", ret, Serialize(val)); + } + return Format("%s]", ret); + } + else if(GetType(value) == C4V_Bool) if(value) return "true"; else return "false"; + else if(GetType(value) == C4V_C4ID) return Format("%i", value); + else if(GetType(value) == C4V_C4Object) return Format("Object(%d)", ObjectNumber(value)); + else if(GetType(value) == C4V_Int || GetType(value) == C4V_Any) return Format("%d", value); + else if(GetType(value) == C4V_String) return Format("\"%s\"", EscapeString(value)); +} + +global func EscapeString(string value) +{ + var ret = ""; + for(var i = 0; i < GetLength(value); ++i) + { + var c = GetChar(value, i); + if(c == 34) // " + { + ret = Format("%s\\\"", ret); + } + else if(c == 92) // \ + { + ret = Format("%s\\\\", ret); + } + else + { + ret = Format("%s%c", ret, c); + } + } + return ret; +} + +global func CreateEnum(string prefix, array enum) +{ + var log = Format("%c// This enum was created with CreateEnum(%s, %s);%c", 10, Serialize(prefix), Serialize(enum), 10); + var switch = ""; + + for(var i = 0; i < GetLength(enum); ++i) + { + log = Format("%s%cstatic const %s%s = %d;", log, 10, prefix, enum[i], i); + + if(switch == "") + { + switch = Format("if(switchval == %s%s)%c{%c%c}%c", prefix, enum[i], 10, 10, 10, 10); + } + else + { + switch = Format("%selse if(switchval == %s%s)%c{%c%c}%c", switch, prefix, enum[i], 10, 10, 10, 10); + } + } + + Log("%s%c%c// Template if-structure - replace switchval with the value to compare.%c%c%s", log, 10, 10, 10, 10, switch); +} + +global func CreateBitField(string prefix, array flags) +{ + if(GetLength(flags) > 32) + { + FatalError("CreateBitField: A bitfield can only have a maximum of up to 32 flags."); + return; + } + + var log = Format("%c// This bitfield was created with CreateBitField(%s, %s);%c", 10, Serialize(prefix), Serialize(flags), 10); + + for(var i = 0, j = 1; i < GetLength(flags); ++i) + { + log = Format("%s%cstatic const %s%s = %d;", log, 10, prefix, flags[i], j); + j = j << 1; + } + + Log("%s%c%c", log, 10, 10); +} + +// pos >= 0 => begin at pos | pos < 0 => begin at GetLength(string) - pos +// count = 0 => replace all | count > 0 replace a maximum of count occurences from starting from pos + +global func Lowercase(int c) +{ + if((c >= 65 && c <= 90) || (c >= 192 && c <= 214) || (c >= 216 && c <= 221)) return c + 32; + else return c; +} + +global func StringLowercase(string string) +{ + var ret = ""; + for(var i = 0; i < GetLength(string); ++i) + { + ret = Format("%s%c", ret, Lowercase(GetChar(string, i))); + } + return ret; +} + +global func MultiStringLowercase(array strings) +{ + var ret = []; + for(var string in strings) + { + ret[GetLength(ret)] = StringLowercase(string); + } + return ret; +} + +global func CaseInsensitive(int c, bool caseSensitive) // TODO +{ + if(caseSensitive) return c; + else return Lowercase(c); +} + +global func StringConcatenate(array strings) +{ + var ret = strings[0]; + + for(var i = 1; i < GetLength(strings); ++i) + { + ret = Format("%s%s", ret, strings[i]); + } + + return ret; +} + +global func MultiStringReplace(find, strings, replace, bool caseInsensitive, int count, int pos, int maxpos) +{ + var returnString = false; + if(GetType(strings) == C4V_String) + { + strings = [strings]; + returnString = true; + } + else if(GetType(strings) != C4V_Array) return strings; + if(GetType(find) == C4V_String) find = [find]; + else if(GetType(find) != C4V_Array) return strings; + if(GetType(replace) == C4V_String) replace = [find]; + else if(GetType(replace) != C4V_Array) return strings; + + var ret = []; + + for(var i = 0; i < GetLength(strings); ++i) + { + ret[i] = strings[i]; + for(var j = 0; j < GetLength(find); ++j) + { + ret[i] = StringReplace(find[j], ret[i], replace[j % GetLength(replace)], caseInsensitive, count, pos, maxpos); + } + } + + if(returnString) return ret[0]; + else return ret; +} + +global func StringReplace(string find, string string, string replace, bool caseInsensitive, int count, int pos, int maxpos) +{ + if(GetLength(find) == 0 || GetLength(string) == 0) return string; + var ret = ""; + if(pos < 0) pos = GetLength() - pos; + if(maxpos < 0) maxpos = GetLength(string) - pos; + if(maxpos == 0) maxpos = GetLength(string); + if(pos < 0 || pos > GetLength(string) || maxpos < 0 || maxpos > GetLength(string) || count < 0) return string; + if(count == 0) count = -1; + + for(var i = 0; i < pos; ++i) + { + ret = Format("%s%c", ret, GetChar(string, i)); + } + + var match = 0; + + var i; + + for(i = pos; i + GetLength(find) - match - 1 < maxpos && count != 0; ++i) + { + var c = GetChar(string, i); + if(CaseInsensitive(c, !caseInsensitive) == CaseInsensitive(GetChar(find, match), !caseInsensitive)) + { + if(++match == GetLength(find)) + { + ret = StringConcatenate([ret, replace]); + match = 0; + --count; + } + } + else + { + if(match != 0) + { + for(var j = i - match; j < i; ++j) + { + ret = Format("%s%c", ret, GetChar(string, j)); + } + } + match = 0; + ret = Format("%s%c", ret, GetChar(string, i)); + } + } + + for(i -= match; i < GetLength(string); ++i) + { + ret = Format("%s%c", ret, GetChar(string, i)); + } + + return ret; +} + +global func StringReplaceMulti(string find, string string, array replace) +{ + var ret = []; + for(var rep in replace) + { + ret[GetLength(ret)] = StringReplace(find, string, rep); + } + return ret; +} + +global func MultiStringReplaceMulti(string string, array findReplace) +{ + var ret = []; + + for(var j = 0; j < GetLength(findReplace[0][1]); ++j) + { + var part = string; + for(var i = 0; i < GetLength(findReplace); ++i) + { + part = StringReplace(findReplace[i][0], part, findReplace[i][1][j]); + } + ret[j] = part; + } + + return ret; +} + +global func GetMapValue(key, array map, default) +{ + for(var val in map) + { + if(val[0] == key) return val; + } + return default; +} + +global func GetIDByName(string name, int category) // WARNING: desyncs between clients with different languages +{ + var i, id; + while(id = GetDefinition(i++, category)) + { + if(GetName(0, id) == name) return id; + } + return 0; +} + +global func GetIDsByName(string name, int category) // WARNING: desyncs between clients with different languages +{ + var i, id, ret = []; + while(id = GetDefinition(i++, category)) + { + if(GetName(0, id) == name) + { + ret[GetLength(ret)] = id; + } + } + return ret; +} + +global func ArrayConcatenate(array arrays) +{ + var ret = []; + for(var arr in arrays) + { + for(var val in arr) + { + ret[GetLength(ret)] = val; + } + } + return ret; +} + +global func SetPlrExtraDataString(int plr, string name, string data) +{ + var part = 0; + var i; + for(i = 0; i < GetLength(data); ++i) + { + var c = GetChar(data, i); + + if((i % 4) == 0 && i != 0) + { + SetPlrExtraData(plr, Format("%s%d", name, i/4 - 1), part); + part = 0; + } + + part |= (c << ((i % 4) * 8)); + } + + if(part != 0) + { + SetPlrExtraData(plr, Format("%s%d", name, i/4), part); + } + + i = i/4 + 1; + while(GetPlrExtraData(plr, Format("%s%d", name, i))) + { + SetPlrExtraData(plr, Format("%s%d", name, i++), 0); + } +} + +global func GetPlrExtraDataString(int plr, string name) +{ + var ret = ""; + var part = true; + for(var i = 0; part != 0; ++i) + { + part = CastInt(GetPlrExtraData(plr, Format("%s%d", name, i))); + for(var j = 0; j < 4; ++j) + { + var c = (part >> (j * 8)) & 0xFF; + if(c == 0) + { + part = 0; + break; + } + else + { + ret = Format("%s%c", ret, c); + } + } + } + return ret; +} + +global func SetPlrExtraDataArray(int plr, string name, array arr) +{ + return SetPlrExtraDataString(plr, name, Serialize(arr)); +} + +global func GetPlrExtraDataArray(int plr, string name) +{ + var function = GetPlrExtraDataString(plr, name); + if(function != "") + { + return eval(function); + } +} + +global func SetPlrExtraDataIntArray(int plr, string name, array arr) +{ + var lengthName = Format("%sL", name); + + var oldLength = CastInt(GetPlrExtraData(plr, lengthName)); + + var length = GetLength(arr); + + for(var i = 0; i < length; ++i) + { + var partName = Format("%s%d", name, i); + if(arr[i] != 0) + { + SetPlrExtraData(plr, partName, arr[i]); + } + else if(GetPlrExtraData(plr, partName) != 0) + { + SetPlrExtraData(plr, partName, 0); + } + } + + SetPlrExtraData(plr, lengthName, length); + + for(var i = length; i < oldLength; ++i) + { + var partName = Format("%s%d", name, i); + if(GetPlrExtraData(plr, partName) != 0) + { + SetPlrExtraData(plr, partName, 0); + } + } +} + +global func GetPlrExtraDataIntArray(int plr, string name) +{ + var length = CastInt(GetPlrExtraData(plr, Format("%sL", name))); + + var ret = CreateArray(length); + + for(var i = 0; i < length; ++i) + { + ret[i] = CastInt(GetPlrExtraData(plr, Format("%s%d", name, i))); + } + + return ret; +} + +global func EnableScripting() +{ + AddMsgBoardCmd("s", "ScriptingFunc(\"%s\", %player%)", C4MSGCMDR_Escaped); +} + +global func ScriptingFunc(string script, int player) +{ + Log("-> %s", script); + Log("= %v (by %s)", eval(script), GetTaggedPlayerName(player)); +} + +global func ParseInt(string int, bool hex) +{ + if(GetLength(int) == 0) + { + return ""; + } + var ret = 0, neg = false; + for(var i = 0; i < GetLength(int); ++i) + { + var c = GetChar(int, i); + if(i == 0) + { + if(c == 45) // "-" + { + neg = true; + continue; + } + else if(c == 43) // "+" + { + continue; + } + } + c -= 48; // "0" == 48 + if(c < 0 || ((!hex && c > 9) || (hex && c > 54))) // "f" - "0" == 54 + { + return ""; + } + if(hex) + { + ret = ret << 4; + } + else + { + ret *= 10; + } + if(c > 9) + { + c -= 39; + } + ret += c; + } + return ret * (1 - (2 * neg)); +} + +global func ParseFloat(string float, int precision) // precision = number of digits after decimal point and multiplier of 10^precision +{ + precision = precision || 3; + if(GetLength(float) == 0) + { + return ""; + } + var ret = 0, neg = false, decimalPoint = -1; + for(var i = 0; i < GetLength(float); ++i) + { + if(decimalPoint != -1 && decimalPoint + precision < i) + { + // out of precision + break; + } + + var c = GetChar(float, i); + if(i == 0) + { + if(c == 45) // "-" + { + neg = true; + continue; + } + else if(c == 43) // "+" + { + continue; + } + } + c -= 48; // "0" == 48 + if(c < 0 || c > 9) + { + if((c == -2 || c == -4) && decimalPoint == -1) // "." || "," + { + decimalPoint = i; + continue; + } + else + { + return ""; + } + } + ret *= 10; + ret += c; + } + if(decimalPoint == -1) + { + decimalPoint = i - 1; + } + + for(; i <= decimalPoint + precision; ++i) + { + ret *= 10; + } + + return ret * (1 - (2 * neg)); +} + +global func CreateFilledArray() +{ + var ret = []; + for(var i = 9; i >= 0; --i) + { + if(Par(i)) + { + ret[i] = Par(i); + } + } + return ret; +} + +global func Find_Procedure(string proc) +{ + return [C4FO_Func, "Find_ProcedureCheck", proc]; +} + +global func Find_ProcedureCheck(string proc) +{ + return proc == GetProcedure(); +} + +global func GetSolidMask(object obj) +{ + obj = obj || this; + return + [ + GetObjectVal("SolidMask", 0, obj, 0), GetObjectVal("SolidMask", 0, obj, 1), + GetObjectVal("SolidMask", 0, obj, 2), GetObjectVal("SolidMask", 0, obj, 3), + GetObjectVal("SolidMask", 0, obj, 4), GetObjectVal("SolidMask", 0, obj, 5) + ]; +} + +// getValue: +// 0 - offset index (the preferred way is to always get the offset index first and to pass the result to following calls for performance reasons) +// 1 - overlay ID +// 2 - overlay mode +// 3 - graphics definition ID +// 4 - graphics name +// 5 - action name +// 6 - blit mode +// 7 - index of Transformation-matrix +// 8 - enumerated overlay object (i.e. object number of the overlay object); WARNING: this is only valid and true directly after saving or loading a savegame + +global func GetOverlayValueByIndex(int index, int startIndex, int getValue, object obj) // startIndex can be given as a valid index (retrieved with this function beforehand) and the asked index is used as offset (better performance for iterating over all indices) +{ + if(getValue < 0 || getValue > 8) + { + // invalid getValues could cause infinite loops + return -2; + } + obj = obj || this; + var found = false; + if(index == 0) + { + if(getValue == 0) + { + if(GetObjectVal("GfxOverlay", 0, obj, startIndex) == 0) + { + // there is no such overlay + return -1; + } + else + { + return startIndex; + } + } + else if(getValue == 1) + { + return GetObjectVal("GfxOverlay", 0, obj, startIndex); + } + found = true; + } + for(var i = startIndex + 1, foundIndex = 0; ;) // skip overlay ID + { + var val = GetObjectVal("GfxOverlay", 0, obj, i); + if(val == 0) + { + // there is no overlay left + return -1; + } + if(val == GFXOV_MODE_Object) + { + // this is the overlay mode GFXOV_MODE_Object. Graphics-Definition and -Name are left out + if(found && (getValue == 3 || getValue == 4)) + { + return 0; + } + else if(found && getValue == 2) + { + return GFXOV_MODE_Object; + } + } + else if(GetType(val) == C4V_C4ID) + { + if(found) + { + if(getValue == 3) + { + return val; + } + else if(getValue == 4) + { + return GetObjectVal("GfxOverlay", 0, obj, i + 1); + } + } + i += 2; // skip Graphics-Definition and -Name, so i points to OverlayMode here too + if(found && getValue == 2) + { + return GetObjectVal("GfxOverlay", 0, obj, i); + } + } + else + { + //something went wrong already + return -3; + } + + if(found) + { + if(getValue == 5) + { + return GetObjectVal("GfxOverlay", 0, obj, i + 1); + } + else if(getValue == 6) + { + return GetObjectVal("GfxOverlay", 0, obj, i + 2); + } + else if(getValue == 7) + { + return i + 4; + } + } + + i += 10; // this is either the last row of the Transformation matrix or the Color-Modulation + val = GetObjectVal("GfxOverlay", 0, obj, i); + + if(GetType(val) == C4V_String) + { + // part of the matrix, skip it + i += 3; + } + + if(found && getValue == 8) + { + return GetObjectVal("GfxOverlay", 0, obj, i + 2); + } + + i += 3; // and the rest + + if(++foundIndex == index) + { + if(GetObjectVal("GfxOverlay", 0, obj, i) == 0) + { + // there is no overlay left + return -1; + } + else + { + found = true; + if(getValue == 0) + { + return i; + } + else if(getValue == 1) + { + return GetObjectVal("GfxOverlay", 0, obj, i); + } + } + } + + ++i; // skip the next overlay ID + } +} + +global func GetOverlayValueOffsetByID(int overlay, object obj) +{ + obj = obj || this; + + if(overlay != 0) + { + var offset = 0, diffIndex = 0; + while((offset = obj->GetOverlayValueByIndex(diffIndex, offset)) >= 0) + { + if(GetOverlayValueByIndex(0, offset, 1) == overlay) + { + return offset; + } + diffIndex = 1; + } + } + + return -1; +} + +global func GetObjDrawTransform(int overlay, int overlayOffset, object obj) +{ + obj = obj || this; + if(overlay == 0) + { + var first = GetObjectVal("DrawTransform", 0, obj, 0); + if(first == 0) + { + return [1000, 0, 0, 0, 1000, 0]; + } + var ret = [ParseFloat(first, 3), ParseFloat(GetObjectVal("DrawTransform", 0, obj, 1), 3), ParseFloat(GetObjectVal("DrawTransform", 0, obj, 2), 3), ParseFloat(GetObjectVal("DrawTransform", 0, obj, 3), 3), ParseFloat(GetObjectVal("DrawTransform", 0, obj, 4), 3), ParseFloat(GetObjectVal("DrawTransform", 0, obj, 5), 3)]; + + var rest = GetObjectVal("DrawTransform", 0, obj, 7); // 6 is left out intentionally, because its only FlipDir (used internally for Actions with FlipDir) + if(GetType(rest) == C4V_String) // the last 3 matrix-values are only decompiled if they are not the default of [0, 0, 1.0] + { + SetLength(ret, 9); + ret[6] = ParseFloat(rest, 3); + ret[7] = ParseFloat(GetObjectVal("DrawTransform", 0, obj, 8), 3); + ret[8] = ParseFloat(GetObjectVal("DrawTransform", 0, obj, 9), 3); + } + + return ret; + } + else + { + var index = 0; + if(overlay == -1) + { + index = overlayOffset; + } + else + { + index = obj->GetOverlayValueOffsetByID(overlay); + } + if(index < 0) + { + return index; + } + index = obj->GetOverlayValueByIndex(0, index, 7); + if(index < 0) + { + return index; + } + + var ret = [ParseFloat(GetObjectVal("GfxOverlay", 0, obj, index), 3), ParseFloat(GetObjectVal("GfxOverlay", 0, obj, index + 1), 3), ParseFloat(GetObjectVal("GfxOverlay", 0, obj, index + 2), 3), ParseFloat(GetObjectVal("GfxOverlay", 0, obj, index + 3), 3), ParseFloat(GetObjectVal("GfxOverlay", 0, obj, index + 4), 3), ParseFloat(GetObjectVal("GfxOverlay", 0, obj, index + 5), 3)]; + + var rest = GetObjectVal("GfxOverlay", 0, obj, index + 7); // 6 is left out intentionally, because its only FlipDir (used internally for Actions with FlipDir) + if(GetType(rest) == C4V_String) // the last 3 matrix-values are only decompiled if they are not the default of [0, 0, 1.0] + { + SetLength(ret, 9); + ret[6] = ParseFloat(rest, 3); + ret[7] = ParseFloat(GetObjectVal("GfxOverlay", 0, obj, index + 8), 3); + ret[8] = ParseFloat(GetObjectVal("GfxOverlay", 0, obj, index + 9), 3); + } + + return ret; + } +} + +global func GetShape(object obj) +{ + obj = obj || this; + return [GetObjectVal("Offset", 0, obj, 0), GetObjectVal("Offset", 0, obj, 1), GetObjectVal("Width", 0, obj), GetObjectVal("Height", 0, obj)]; +} + +global func InRect(array point, array rect) +{ + var x = point[0], y = point[1]; + return rect[0] < x && x < rect[0] + rect[2] && rect[1] < y && y < rect[1] + rect[3]; +} + +global func GetPlayerByID(int id) +{ + for(var i = 0; i < GetPlayerCount(); ++i) + { + var plr = GetPlayerByIndex(i); + if(GetPlayerID(plr) == id) + { + return plr; + } + } + + return NO_OWNER; +} -- cgit v1.2.3-54-g00ecf