From 9b5d0a3ddf41e686439dcda1edfe11eee51c3b07 Mon Sep 17 00:00:00 2001 From: Markus Mittendrein Date: Thu, 5 Jan 2017 16:19:56 +0100 Subject: Initial --- DTArrays.c | 52 ++++ DTCallback.c | 324 +++++++++++++++++++++ DTCallbackScopedVars.c | 55 ++++ DTColorStack.c | 86 ++++++ DTCompatibility.c | 105 +++++++ DTContents.c | 16 ++ DTFindObject.c | 338 ++++++++++++++++++++++ DTFormatN.c | 87 ++++++ DTMenuCompatibility.c | 20 ++ DTObjectSerializing.c | 406 +++++++++++++++++++++++++++ DTParticles.c | 15 + DTPhysicalStack.c | 72 +++++ DTPlayers.c | 82 ++++++ DTQuickSort.c | 66 +++++ DTRemoveNotification.c | 43 +++ DTScenUtils.c | 91 ++++++ DTScopedVars.c | 87 ++++++ DTTemplateFunctions.c | 307 ++++++++++++++++++++ DTTimer.c | 26 ++ DTTransform.c | 240 ++++++++++++++++ DTUtility.c | 744 +++++++++++++++++++++++++++++++++++++++++++++++++ 21 files changed, 3262 insertions(+) create mode 100644 DTArrays.c create mode 100644 DTCallback.c create mode 100644 DTCallbackScopedVars.c create mode 100644 DTColorStack.c create mode 100644 DTCompatibility.c create mode 100644 DTContents.c create mode 100644 DTFindObject.c create mode 100644 DTFormatN.c create mode 100644 DTMenuCompatibility.c create mode 100644 DTObjectSerializing.c create mode 100644 DTParticles.c create mode 100644 DTPhysicalStack.c create mode 100644 DTPlayers.c create mode 100644 DTQuickSort.c create mode 100644 DTRemoveNotification.c create mode 100644 DTScenUtils.c create mode 100644 DTScopedVars.c create mode 100644 DTTemplateFunctions.c create mode 100644 DTTimer.c create mode 100644 DTTransform.c create mode 100644 DTUtility.c diff --git a/DTArrays.c b/DTArrays.c new file mode 100644 index 0000000..0b78ef4 --- /dev/null +++ b/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/DTCallback.c b/DTCallback.c new file mode 100644 index 0000000..6e026b7 --- /dev/null +++ b/DTCallback.c @@ -0,0 +1,324 @@ +/*-- Extensible callback system --*/ +#strict 2 + +static const CallbackTarget_Bind = -1; +static const CallbackTarget_Global = -2; +static const CallbackTarget_Scenario = -3; + +global func GlobalCallback(string name) { return [CallbackTarget_Global, name]; } +global func ScenarioCallback(string name) { return [CallbackTarget_Scenario, name]; } +global func ObjectCallback(string name, object target) { return [target || this || FatalError("ObjectCallback without target object"), name]; } +global func DefinitionCallback(string name, id target) { return [target || GetID() || FatalError("DefinitionCallback without target definition"), name]; } +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]; + } + if(GetType(callback) != C4V_Array) + { + return _inherited(callback, args, ...); + } + else + { + refs = refs || []; + var safeModifier = ""; + if(safe) + { + safeModifier = "~"; + } + var target = callback[0], function = callback[1]; + 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(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(callback[1], BindArgs(callback[2], args, safe, refs), safe, refs); + } + else + { + if(GetType(target) == C4V_C4Object || GetType(target) == C4V_C4ID) + { + return eval(Format("%s->%s%s(%s)", Serialize(target), safeModifier, function, argsStr)); + } + else + { + return (this && this->~CallCustom(callback, args, ...)) || ROCK->~CallCustom(callback, args, ...); + } + } + } +} + +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) + { + 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 && GetType(callback[1]) == C4V_String && callback[1] != "") + { + return true; + } + } + } + + return (this && this->~CheckCustomCallback(callback, ...)) || ROCK->~CheckCustomCallback(callback, ...); +} + +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) + { + if(!CheckBindCallbackCustomBinding(b)) + { + return false; + } + } + else + { + if(!CheckBindCallbackBinding(b)) + { + return false; + } + } + } + else + { + return false; + } + } + else if(b < 0) + { + return false; + } + } + return true; +} + +global func CheckBindCallbackCustomBinding() { return _inherited(...); } diff --git a/DTCallbackScopedVars.c b/DTCallbackScopedVars.c new file mode 100644 index 0000000..75eb5e2 --- /dev/null +++ b/DTCallbackScopedVars.c @@ -0,0 +1,55 @@ +#strict 2 + +static const ScopedVar_Callback = 4; + +global func CallbackVar(callback) { return [ScopedVar_Callback, callback]; } + +global func &CustomScopedVar(array variable) +{ + if(variable[0] == ScopedVar_Callback) + { + return CallA(variable[1], []); + } + else + { + return _inherited(variable, ...); + } +} + +static const BindCallback_Bind_ScopedVar = -6; + +global func Bind_Var(array scopedVar) { return [BindCallback_Bind_ScopedVar, scopedVar]; } + +global func BindCustomArgs(array bind, array args, bool safe) +{ + if(bind[0] == BindCallback_Bind_ScopedVar) + { + return ScopedVar(bind[1]); + } + else + { + return _inherited(bind, args, safe, ...); + } +} + +global func CheckCustomScopedVar(array variable) +{ + if(GetType(variable) == C4V_Array && variable[0] == ScopedVar_Callback && GetLength(variable) == 2) + { + if(CheckCallback(variable[1])) + { + return true; + } + } + + return _inherited(variable, ...); +} + +global func CheckBindCallbackCustomBinding(binding) +{ + if(GetType(binding) == C4V_Array && GetLength(binding) == 2 && binding[0] == BindCallback_Bind_ScopedVar && CheckScopedVar(binding[1])) + { + return true; + } + return _inherited(binding, ...); +} diff --git a/DTColorStack.c b/DTColorStack.c new file mode 100644 index 0000000..9f9535f --- /dev/null +++ b/DTColorStack.c @@ -0,0 +1,86 @@ +#strict 2 + +global func GetClrModulationStack(object target) +{ + target || FatalError("GetClrModulationStack: no target object given"); + return GetEffect("ClrModulationStack", target) || AddEffect("ClrModulationStack", target, 200); +} + +global func AddClrModulation(int color, int baseColor, int factor, int precision, object target) +{ + baseColor = baseColor || RGB(127, 127, 127); + target = target || this || FatalError("AddClrModulation: no target object given"); + factor = factor || 1; + precision = precision || 1; + + return EffectCall(target, GetClrModulationStack(target), "AddModulation", color, baseColor, factor, precision); +} + +global func RemoveClrModulation(int id, object target) +{ + target = target || this || FatalError("RemoveClrModulation: no target object given"); + + return EffectCall(target, GetClrModulationStack(target), "RemoveModulation", id); +} + +global func FxClrModulationStackStart(object target, int effectNumber, int temp) +{ + if(!temp) + { + EffectVar(1, target, effectNumber) = []; + } +} + +global func FxClrModulationStackAddModulation(object target, int effectNumber, int color, int baseColor, int factor, int precision) +{ + ArrayAppend(EffectVar(1, target, effectNumber), [++EffectVar(0, target, effectNumber), color, baseColor, factor, precision]); + EffectCall(target, effectNumber, "ApplyModulation"); + return EffectVar(0, target, effectNumber); +} + +global func FxClrModulationStackRemoveModulation(object target, int effectNumber, int id) +{ + for(var i = 0; i < GetLength(EffectVar(1, target, effectNumber)); ++i) + { + if(EffectVar(1, target, effectNumber)[i][0] == id) + { + ArrayErase(EffectVar(1, target, effectNumber), i); + EffectCall(target, effectNumber, "ApplyModulation"); + return true; + } + } + return 0; +} + +global func FxClrModulationStackApplyModulation(object target, int effectNumber) +{ + if(GetLength(EffectVar(1, target, effectNumber)) == 0) + { + SetClrModulation(0, target); + return 0; + } + var r, g, b, a; + SplitRGBaValue(EffectVar(1, target, effectNumber)[0][1], r, g, b, a); + a = 255 - a; + for(var i = 1; i < GetLength(EffectVar(1, target, effectNumber)); ++i) + { + var clrPart = EffectVar(1, target, effectNumber)[i]; + var mr, mg, mb, ma, br, bg, bb, ba; + SplitRGBaValue(clrPart[1], mr, mg, mb, ma); + SplitRGBaValue(clrPart[2], br, bg, bb, ba); + ma = 255 - ma; + a *= ma; + a /= 0xFF; + r += mr - br; + r *= clrPart[3]; + r /= clrPart[4]; + g += mg - bg; + g *= clrPart[3]; + g /= clrPart[4]; + b += mb - bb; + b *= clrPart[3]; + b /= clrPart[4]; + } + SetClrModulation(RGBa(BoundBy(r, 0, 255), BoundBy(g, 0, 255), BoundBy(b, 0, 255), 255 - a), target); + return true; +} diff --git a/DTCompatibility.c b/DTCompatibility.c new file mode 100644 index 0000000..d3ae922 --- /dev/null +++ b/DTCompatibility.c @@ -0,0 +1,105 @@ +/*-- Avoid errors from non-existing Engine-Functions --*/ + +#strict 2 + +static hostFeatures; +static hostTime; + +global func SetGameComment() { return _inherited(...); } +global func IsHost() { return _inherited(...); } +global func RequestHostFeature(string feature) { if(!HaveHostFeature(feature) || feature == "HostTime") return _inherited(feature, ...); } + +global func AnnounceHostFeature(string feature) +{ + hostFeatures || (hostFeatures = []); + hostFeatures[GetLength(hostFeatures)] = feature; +} + +global func HaveHostFeature(string feature) +{ + hostFeatures || (hostFeatures = []); + return GetIndexOf(feature, hostFeatures) != -1; +} + +global func ReRequestHostFeatures() +{ + if(IsNetwork()) + { + var features = hostFeatures; + hostFeatures = []; + + if(features) + { + for(var feature in features) + { + RequestHostFeature(feature); + } + } + } +} + +global func AnnounceHostTime(int time) +{ + hostTime = time; +} + +global func GetSystemTime(int what) +{ + if(HaveHostFeature("HostTime")) + { + if(what == 10) // is leap year + { + var year = GetSystemTime(0); + return !!((!(year % 4) && year % 100) || !(year % 400)); + } + if(what == 9) return hostTime; // timestamp + if(what == 8) // day of year + { + return (hostTime - (GetSystemTime(0) - 1970) * 31556926)/(3600*24) + 1; + } + if(what == 7) return 0; + if(what == 6) return hostTime % 60; + if(what == 5) return (hostTime/60) % 60; + if(what == 4) return (hostTime/3600) % 24; + if(what == 3) + { + var dayofyear = GetSystemTime(8); + var leapyear = GetSystemTime(10); + if(dayofyear < 32) return dayofyear; + else if(dayofyear < 60 + leapyear) return dayofyear - 31; + else if(dayofyear < 91 + leapyear) return dayofyear - 59; + else if(dayofyear < 121 + leapyear) return dayofyear - (90 + leapyear); + else if(dayofyear < 152 + leapyear) return dayofyear - (120 + leapyear); + else if(dayofyear < 182 + leapyear) return dayofyear - (151 + leapyear); + else if(dayofyear < 213 + leapyear) return dayofyear - (181 + leapyear); + else if(dayofyear < 244 + leapyear) return dayofyear - (212 + leapyear); + else if(dayofyear < 274 + leapyear) return dayofyear - (243 + leapyear); + else if(dayofyear < 305 + leapyear) return dayofyear - (273 + leapyear); + else if(dayofyear < 335 + leapyear) return dayofyear - (204 + leapyear); + else return dayofyear - (334 + leapyear); + } + if(what == 2) + { + return ((hostTime/86400) + 4) % 7; + } + if(what == 1) + { + var dayofyear = GetSystemTime(8); + var leapyear = GetSystemTime(10); + if(dayofyear < 32) return 1; + else if(dayofyear < 60 + leapyear) return 2; + else if(dayofyear < 91 + leapyear) return 3; + else if(dayofyear < 121 + leapyear) return 4; + else if(dayofyear < 152 + leapyear) return 5; + else if(dayofyear < 182 + leapyear) return 6; + else if(dayofyear < 213 + leapyear) return 7; + else if(dayofyear < 244 + leapyear) return 8; + else if(dayofyear < 274 + leapyear) return 9; + else if(dayofyear < 305 + leapyear) return 10; + else if(dayofyear < 335 + leapyear) return 11; + else return 12; + } + if(what == 0) return 1970 + ((hostTime + 31556926 * 2)/(31556926)) - 2; + } + else return _inherited(what, ...); +} diff --git a/DTContents.c b/DTContents.c new file mode 100644 index 0000000..cb49691 --- /dev/null +++ b/DTContents.c @@ -0,0 +1,16 @@ +#strict 2 + +global func GetContents(bool recursive, object obj) +{ + obj = obj || this; + var ret = []; + for(var i = 0; i < obj->ContentsCount(); ++i) + { + ret[GetLength(ret)] = obj->Contents(i); + if(recursive) + { + ArrayAppendArray(ret, obj->Contents(i)->GetContents(true)); + } + } + return ret; +} diff --git a/DTFindObject.c b/DTFindObject.c new file mode 100644 index 0000000..b7205e6 --- /dev/null +++ b/DTFindObject.c @@ -0,0 +1,338 @@ +/*-- + * Overloads Find_-functions available in System.c4g so Find_Or and Find_And can be used inside other criterions like so: + * Find_ID(Find_Or(ROCK, FLNT)) + * Find_Func("IsBlock", ["CompareLayer", LAYER_FG]) + * --*/ +#strict 2 + +global func ProxySimpleFind_AndOr(int type, criteria) +{ + if(GetType(criteria) != C4V_Array) + { + return [type, criteria]; + } + else + { + var ret = [criteria[0]]; + for(var i = 1; i < GetLength(criteria); ++i) + { + ret[i] = [type, criteria[i]]; + } + return ret; + } +} + +global func ProxyFind_AndOr(criteria, &type, &parts) +{ + type = criteria[0]; + parts = CreateArray(GetLength(criteria) - 1); + for(var i = 1; i < GetLength(criteria); ++i) + { + if(GetType(criteria[i]) == C4V_Array) + { + parts[i - 1] = criteria[i]; + } + else + { + parts[i - 1] = [criteria[i]]; + } + } +} + +global func Find_Action(what) { return ProxySimpleFind_AndOr(C4FO_Action, what); } +global func Find_Category(what) { return ProxySimpleFind_AndOr(C4FO_Category, what); } +global func Find_Container(what) { return ProxySimpleFind_AndOr(C4FO_Container, what); } +global func Find_Controller(what) { return ProxySimpleFind_AndOr(C4FO_Controller, what); } +global func Find_ID(what) { return ProxySimpleFind_AndOr(C4FO_ID, what); } +global func Find_Layer(what) { return ProxySimpleFind_AndOr(C4FO_Layer, what); } +global func Find_OCF(what) { return ProxySimpleFind_AndOr(C4FO_OCF, what); } +global func Find_Owner(what) { return ProxySimpleFind_AndOr(C4FO_Owner, what); } + +global func Find_Exclude(what) +{ + if(GetType(what) != C4V_Array) + { + return _inherited(what); + } + + var ret = [], parts, i = 0; + ProxyFind_AndOr(what, ret[0], parts); + for(var part in parts) + { + ret[++i] = _inherited(part[0], part[1], part[2], part[3], part[4], part[5], part[6], part[7], part[8], part[9]); + } + return ret; +} + +global func Find_InRect(what) +{ + if(GetType(what) != C4V_Array) + { + return _inherited(what); + } + + var ret = [], parts, i = 0; + ProxyFind_AndOr(what, ret[0], parts); + for(var part in parts) + { + ret[++i] = _inherited(part[0], part[1], part[2], part[3], part[4], part[5], part[6], part[7], part[8], part[9]); + } + return ret; +} + +global func Find_AtRect(what) +{ + if(GetType(what) != C4V_Array) + { + return _inherited(what); + } + + var ret = [], parts, i = 0; + ProxyFind_AndOr(what, ret[0], parts); + for(var part in parts) + { + ret[++i] = _inherited(part[0], part[1], part[2], part[3], part[4], part[5], part[6], part[7], part[8], part[9]); + } + return ret; +} + +global func Find_OnLine(what) +{ + if(GetType(what) != C4V_Array) + { + return _inherited(what); + } + + var ret = [], parts, i = 0; + ProxyFind_AndOr(what, ret[0], parts); + for(var part in parts) + { + ret[++i] = _inherited(part[0], part[1], part[2], part[3], part[4], part[5], part[6], part[7], part[8], part[9]); + } + return ret; +} + +global func Find_Distance(what) +{ + if(GetType(what) != C4V_Array) + { + return _inherited(what); + } + + var ret = [], parts, i = 0; + ProxyFind_AndOr(what, ret[0], parts); + for(var part in parts) + { + ret[++i] = _inherited(part[0], part[1], part[2], part[3], part[4], part[5], part[6], part[7], part[8], part[9]); + } + return ret; +} + +global func Find_ActionTarget(what) +{ + if(GetType(what) != C4V_Array) + { + return _inherited(what); + } + + var ret = [], parts, i = 0; + ProxyFind_AndOr(what, ret[0], parts); + for(var part in parts) + { + ret[++i] = _inherited(part[0], part[1], part[2], part[3], part[4], part[5], part[6], part[7], part[8], part[9]); + } + return ret; +} + +global func Find_Hostile(what) +{ + if(GetType(what) != C4V_Array) + { + return _inherited(what); + } + + var ret = [], parts, i = 0; + ProxyFind_AndOr(what, ret[0], parts); + for(var part in parts) + { + ret[++i] = _inherited(part[0], part[1], part[2], part[3], part[4], part[5], part[6], part[7], part[8], part[9]); + } + return ret; +} + +global func Find_Allied(what) +{ + if(GetType(what) != C4V_Array) + { + return _inherited(what); + } + + var ret = [], parts, i = 0; + ProxyFind_AndOr(what, ret[0], parts); + for(var part in parts) + { + ret[++i] = _inherited(part[0], part[1], part[2], part[3], part[4], part[5], part[6], part[7], part[8], part[9]); + } + return ret; +} + +global func Find_Func(what) +{ + if(GetType(what) != C4V_Array) + { + return _inherited(what); + } + + var ret = [], parts, i = 0; + ProxyFind_AndOr(what, ret[0], parts); + for(var part in parts) + { + ret[++i] = _inherited(part[0], part[1], part[2], part[3], part[4], part[5], part[6], part[7], part[8], part[9]); + } + return ret; +} + +global func Find_PathFree(what) +{ + if(GetType(what) != C4V_Array) + { + return _inherited(what); + } + + var ret = [], parts, i = 0; + ProxyFind_AndOr(what, ret[0], parts); + for(var part in parts) + { + ret[++i] = _inherited(part[0], part[1], part[2], part[3], part[4], part[5], part[6], part[7], part[8], part[9]); + } + return ret; +} + +global func Find_Command(what) +{ + if(GetType(what) != C4V_Array) + { + return _inherited(what); + } + + var ret = [], parts, i = 0; + ProxyFind_AndOr(what, ret[0], parts); + for(var part in parts) + { + ret[++i] = _inherited(part[0], part[1], part[2], part[3], part[4], part[5], part[6], part[7], part[8], part[9]); + } + return ret; +} + +global func Find_ColorDw(what) +{ + if(GetType(what) != C4V_Array) + { + return _inherited(what); + } + + var ret = [], parts, i = 0; + ProxyFind_AndOr(what, ret[0], parts); + for(var part in parts) + { + ret[++i] = _inherited(part[0], part[1], part[2], part[3], part[4], part[5], part[6], part[7], part[8], part[9]); + } + return ret; +} + +global func Find_Effect(what) +{ + if(GetType(what) != C4V_Array) + { + return _inherited(what); + } + + var ret = [], parts, i = 0; + ProxyFind_AndOr(what, ret[0], parts); + for(var part in parts) + { + ret[++i] = _inherited(part[0], part[1], part[2], part[3], part[4], part[5], part[6], part[7], part[8], part[9]); + } + return ret; +} + +global func Find_Local(what) +{ + if(GetType(what) != C4V_Array) + { + return _inherited(what); + } + + var ret = [], parts, i = 0; + ProxyFind_AndOr(what, ret[0], parts); + for(var part in parts) + { + ret[++i] = _inherited(part[0], part[1], part[2], part[3], part[4], part[5], part[6], part[7], part[8], part[9]); + } + return ret; +} + +global func Find_Team(what) +{ + if(GetType(what) != C4V_Array) + { + return _inherited(what); + } + + var ret = [], parts, i = 0; + ProxyFind_AndOr(what, ret[0], parts); + for(var part in parts) + { + ret[++i] = _inherited(part[0], part[1], part[2], part[3], part[4], part[5], part[6], part[7], part[8], part[9]); + } + return ret; +} + +global func Find_FuncEqual(what) +{ + if(GetType(what) != C4V_Array) + { + return _inherited(what); + } + + var ret = [], parts, i = 0; + ProxyFind_AndOr(what, ret[0], parts); + for(var part in parts) + { + ret[++i] = _inherited(part[0], part[1], part[2], part[3], part[4], part[5], part[6], part[7], part[8], part[9]); + } + return ret; +} + +global func Find_FuncInside(what) +{ + if(GetType(what) != C4V_Array) + { + return _inherited(what); + } + + var ret = [], parts, i = 0; + ProxyFind_AndOr(what, ret[0], parts); + for(var part in parts) + { + ret[++i] = _inherited(part[0], part[1], part[2], part[3], part[4], part[5], part[6], part[7], part[8], part[9]); + } + return ret; +} + +global func Find_ID(what) +{ + if(GetType(what) != C4V_Array) + { + return _inherited(what); + } + + var ret = [], parts, i = 0; + ProxyFind_AndOr(what, ret[0], parts); + for(var part in parts) + { + ret[++i] = _inherited(part[0], part[1], part[2], part[3], part[4], part[5], part[6], part[7], part[8], part[9]); + } + return ret; +} + diff --git a/DTFormatN.c b/DTFormatN.c new file mode 100644 index 0000000..0f9481b --- /dev/null +++ b/DTFormatN.c @@ -0,0 +1,87 @@ +#strict 2 + +global func FormatN(string format, array placeholders, array items) +{ + if(!items && GetType(placeholders[0]) == C4V_Array) + { + items = CreateArray(GetLength(placeholders)); + for(var i = 0; i < GetLength(placeholders); ++i) + { + items[i] = placeholders[i][1]; + placeholders[i] = placeholders[i][0]; + } + } + + var ret = ""; + + var inPlaceholder = 0; + var placeholderType = ""; + var placeholderPart = ""; + + for(var i = 0; i < GetLength(format); ++i) + { + var c = GetChar(format, i); + if(c == 37) // % + { + if(inPlaceholder == 0) + { + inPlaceholder = 1; + } + else if(inPlaceholder == 1) + { + if(c == 37 && GetLength(placeholderType) == 0) // % + { + ret = Format("%s%%", ret); + inPlaceholder = 0; + } + else + { + inPlaceholder = 2; + } + } + else if(inPlaceholder == 2) + { + var index = GetIndexOf2(placeholderPart, placeholders); + if(index == -1) + { + FatalError(Format("FormatN: Unkown placeholder \"%s\"", placeholderPart)); + return 0; + } + + ret = Format(Format("%%s%%%s", placeholderType), ret, items[index]); + + inPlaceholder = 0; + placeholderType = ""; + placeholderPart = ""; + } + } + else + { + if(inPlaceholder == 0) + { + ret = Format("%s%c", ret, c); + } + else if(inPlaceholder == 1) + { + placeholderType = Format("%s%c", placeholderType, c); + } + else if(inPlaceholder == 2) + { + placeholderPart = Format("%s%c", placeholderPart, c); + } + } + } + + if(inPlaceholder == 1) + { + FatalError(Format("FormatN: Placeholder not finished at end of format-string: \"%%%s\"", placeholderType)); + return 0; + } + else if(inPlaceholder == 2) + { + FatalError(Format("FormatN: Placeholder not finished at end of format-string: \"%%%s%%%s\"", placeholderType, placeholderPart)); + return 0; + } + + return ret; +} diff --git a/DTMenuCompatibility.c b/DTMenuCompatibility.c new file mode 100644 index 0000000..0401b95 --- /dev/null +++ b/DTMenuCompatibility.c @@ -0,0 +1,20 @@ +#strict 2 +#appendto MN7I + +static const Menu_Enum_Symbol = Menu_Layout_Symbol; +static const Menu_Enum_InfoCaption = Menu_Layout_InfoCaption; + +static const Menu_Enum_Caption = Menu_Layout_Caption; +static const Menu_Enum_Value = Menu_Layout_Value; + +global func Menu_SubMenu(caption, symbol, string infoCaption, array menuEntries_Settings, int count, int extra, XPar1, XPar2) +{ + if(GetType(caption) == C4V_Array) // caption contains all entry settings for the current menu and symbol contains all submenu entries and settings + { + return inherited(caption, symbol, infoCaption, menuEntries_Settings, count, extra, XPar1, XPar2, ...); + } + else + { + return inherited([Menu_Entry_Caption(caption), Menu_Entry_Symbol(symbol), Menu_Entry_Count(count), Menu_Entry_InfoCaption(infoCaption), Menu_Entry_Extra(extra), Menu_Entry_XPar1(XPar1), Menu_Entry_XPar2(XPar2)], menuEntries_Settings); + } +} diff --git a/DTObjectSerializing.c b/DTObjectSerializing.c new file mode 100644 index 0000000..bd68ddc --- /dev/null +++ b/DTObjectSerializing.c @@ -0,0 +1,406 @@ +#strict 2 + +static const Object_Status = 0; +static const Object_Name = 1; +static const Object_Owner = 2; +static const Object_Controller = 3; +static const Object_Killer = 4; +static const Object_Category = 5; +static const Object_Position = 6; +static const Object_Speed = 7; +static const Object_Con = 8; +static const Object_OwnMass = 9; +static const Object_Damage = 10; +static const Object_Energy = 11; +static const Object_MagicEnergy = 12; +static const Object_Alive = 13; +static const Object_Breath = 14; +static const Object_ColorDw = 15; +static const Object_Shape = 16; +static const Object_Vertices = 17; +static const Object_SolidMask = 18; +static const Object_Picture = 19; +static const Object_Entrance = 20; +static const Object_Physicals = 21; +static const Object_Action = 22; +static const Object_Components = 23; +static const Object_Contents = 24; +static const Object_PlrViewRange = 25; +static const Object_Visibility = 26; +static const Object_BlitMode = 27; +static const Object_CrewEnabled = 28; +static const Object_ObjectLayer = 29; +static const Object_Locals = 30; +static const Object_Graphics = 31; +static const Object_Effects = 32; +static const Object_ID = 33; +static const Object_ContactDensity = 34; +static const Object_Dir = 35; +static const Object_ComDir = 36; +static const Object_Origin = 37; +static const Object_Custom = 38; +static const Object_Count = 39; +//_enum(Object_, Status, Name, Owner, Controller, Killer, Category, Position, Speed, Con, OwnMass, Damage, Energy, MagicEnergy, Alive, Breath, ColorDw, Shape, Vertices, SolidMask, Picture, Entrance, Physicals, Action, Components, Contents, PlrViewRange, Visibility, BlitMode, CrewEnabled, ObjectLayer, Locals, Graphics, Effects, ID, ContactDensity, Dir, ComDir, Origin, Custom, Count) +// DONT KNOW: OnFire, Commands + +global func& LocalX(name, object obj) +{ + obj = obj || this; + if(GetType(name) == C4V_String) + { + return LocalN(name, obj); + } + else + { + return Local(name, obj); + } +} + +global func GetEffectVarCount(object target, int effectNumber) // WARNING: this could eventually be wrong (with a very very small probability) when some EffectVars are set right coincidentally +{ // based on and inspired by C4Effect::CompileFunc + var name = GetEffect(0, target, effectNumber, 1); + var prio = GetEffect(0, target, effectNumber, 2); + var timer = GetEffect(0, target, effectNumber, 3); + var lifeTime = GetEffect(0, target, effectNumber, 6); + + if(!name) + { + return -1; + } + + // determine offset for this effect within GetObjectVal + for(var i = 0; ; ++i) + { + if(GetObjectVal("Effects", 0, target, i) == name && GetObjectVal("Effects", 0, target, i + 1) == effectNumber && GetObjectVal("Effects", 0, target, i + 2) == prio && GetObjectVal("Effects", 0, target, i + 3) == lifeTime && GetObjectVal("Effects", 0, target, i + 4) == timer) + { + var count = GetObjectVal("Effects", 0, target, i + 7); + if(count == 1) + { + var nextEffectName = GetObjectVal("Effects", 0, target, i + 8); + if(GetType(nextEffectName) == C4V_String) + { + var nextNumber = GetObjectVal("Effects", 0, target, i + 9); + if(GetType(nextNumber) == C4V_Int && GetEffect(0, target, nextNumber, 1) == nextEffectName) + { + return 0; + } + } + + } + return GetType(count) == C4V_Int && count; + } + } +} + +global func GetObjectSaveData(object obj) +{ + obj = obj || this; + var id = GetID(obj); + var ret = CreateArray(Object_Count); + ret[Object_ID] = id; + ret[Object_Origin] = obj; + ret[Object_Status] = GetObjectStatus(obj); + if(GetName(obj) != GetName(0, id)) + { + ret[Object_Name] = GetName(obj); + } + ret[Object_Owner] = GetOwner(obj); + ret[Object_Controller] = GetController(obj); + ret[Object_Killer] = GetKiller(obj); + ret[Object_Category] = GetCategory(obj); + ret[Object_Position] = [GetX(obj), GetY(obj), GetR(obj)]; + ret[Object_Speed] = [GetXDir(obj, 65536), GetYDir(obj, 65536), GetRDir(obj, 65536)]; + ret[Object_Con] = GetCon(obj); + ret[Object_OwnMass] = GetMass(obj) - GetMass(0, id); // maybe save complete Mass instead? + ret[Object_Damage] = GetDamage(obj); + ret[Object_Energy] = GetObjectVal("Energy", 0, obj); + ret[Object_MagicEnergy] = GetMagicEnergy(obj); + ret[Object_Alive] = GetAlive(obj); + ret[Object_Breath] = GetBreath(obj); + ret[Object_ColorDw] = GetColorDw(obj); + ret[Object_Shape] = [GetObjectVal("Offset", 0, obj, 0), GetObjectVal("Offset", 0, obj, 1), GetObjectVal("Width", 0, obj), GetObjectVal("Height", 0, obj)]; + + if(GetObjectVal("OwnVertices", 0, obj)) + { + var vertexNum = GetVertexNum(obj); + var vertices = CreateArray(vertexNum); + for(var i = 0; i < vertexNum; ++i) + { + vertices[i] = [GetVertex(i, VTX_X, obj), GetVertex(i, VTX_Y, obj), GetVertex(i, VTX_CNAT, obj), GetVertex(i, VTX_Friction, obj)]; + } + ret[Object_Vertices] = vertices; + } + + ret[Object_SolidMask] = GetSolidMask(obj); + ret[Object_Picture] = [GetObjectVal("Picture", 0, obj, 0), GetObjectVal("Picture", 0, obj, 1), GetObjectVal("Picture", 0, obj, 2), GetObjectVal("Picture", 0, obj, 3)]; + ret[Object_Entrance] = GetEntrance(obj); + ret[Object_Action] = [GetAction(obj), GetPhase(obj), GetActionTarget(0, obj), GetActionTarget(1, obj), GetObjectVal("ActionData", 0, obj)]; + + var defComponents = [], objComponents = []; + for(var i = 0, componentID; componentID = GetComponent(0, i, 0, id); ++i) + { + var cnt = GetComponent(componentID, 0, 0, id); + if(cnt != 0) + { + defComponents[GetLength(defComponents)] = [componentID, cnt]; + } + } + for(var i = 0, componentID; componentID = GetComponent(0, i, obj); ++i) + { + var cnt = GetComponent(componentID, 0, obj); + if(cnt != 0) + { + objComponents[GetLength(objComponents)] = [componentID, cnt]; + } + } + + var diffComponents = []; + for(var i = 0; i < GetLength(defComponents); ++i) + { + var defID = defComponents[i][0], defCnt = defComponents[i][1]; + var cnt = 0; + for(var j = 0; j < GetLength(objComponents); ++j) + { + if(objComponents[j][0] == defID) + { + cnt = objComponents[j][1]; + ArrayErase(objComponents, j); + break; + } + } + + if(cnt != defCnt) + { + diffComponents[GetLength(diffComponents)] = [defID, cnt]; + } + } + ArrayAppendArray(diffComponents, objComponents); + + if(GetLength(diffComponents) != 0) + { + ret[Object_Components] = diffComponents; + } + + var contents = []; + for(var content in obj->GetContents()) + { + contents[GetLength(contents)] = GetObjectSaveData(content); + } + ret[Object_Contents] = contents; + ret[Object_PlrViewRange] = GetObjectVal("PlrViewRange", 0, obj); + ret[Object_Visibility] = GetVisibility(obj); + ret[Object_BlitMode] = GetObjectBlitMode(obj); + ret[Object_CrewEnabled] = GetCrewEnabled(obj); + ret[Object_ObjectLayer] = GetObjectLayer(obj); + ret[Object_Dir] = GetDir(obj); + ret[Object_ComDir] = GetComDir(obj); + ret[Object_ContactDensity] = GetObjectVal("ContactDensity", 0, obj); + + var locals = []; + for(var f in [0, 1]) + { + var cnt = GetLocalCount(obj, f); + for(var i = 0; i < cnt; ++i) + { + var name = GetLocalByIndex(i, obj, f); + locals[GetLength(locals)] = [name, LocalX(name, obj)]; + } + } + + ret[Object_Locals] = locals; + + var overlays = [[GetGraphics(1, obj, 0), GetGraphics(0, obj, 0), 0, GetGraphics(2, obj, 0), GetGraphics(3, obj, 0), GetGraphics(4, obj, 0), 0, obj->GetObjDrawTransform(0), GetClrModulation(obj, 0)]]; + var offset = 0, diffIndex = 0; + while((offset = obj->GetOverlayValueByIndex(diffIndex, offset)) >= 0) + { + var overlayID = obj->GetOverlayValueByIndex(0, offset, 1); + overlays[GetLength(overlays)] = [obj->GetOverlayValueByIndex(0, offset, 4), obj->GetOverlayValueByIndex(0, offset, 3), overlayID, obj->GetOverlayValueByIndex(0, offset, 2), obj->GetOverlayValueByIndex(0, offset, 5), obj->GetOverlayValueByIndex(0, offset, 6), Object(obj->GetOverlayValueByIndex(0, offset, 8)), obj->GetObjDrawTransform(-1, offset), GetClrModulation(obj, overlayID)]; + diffIndex = 1; + } + ret[Object_Graphics] = overlays; + + var physicals = []; // TODO: Think about StackTemporary? What about Effects? Maybe pop the whole stack while saving and restore afterwards + for(var physical in ["Energy", "Breath", "Walk", "Jump", "Scale", "Hangle", "Dig", "Swim", "Throw", "Push", "Fight", "Magic", "Float", "CanScale", "CanHangle", "CanDig", "CanConstruct", "CanChop", "CanSwimDig", "CanFly", "CorrosionResist", "BreatheWater"]) + { + var value = GetPhysical(physical, PHYS_Current, obj); + if(value != GetPhysical(physical, 0, 0, id)) + { + physicals[GetLength(physicals)] = [physical, value]; + } + } + if(GetLength(physicals) != 0) + { + ret[Object_Physicals] = physicals; + } + + var effects = []; + for(var i = 0, index; index = GetEffect("*", obj, i, 0); ++i) + { + var varCnt = GetEffectVarCount(obj, index); + var effectVars = CreateArray(varCnt); + for(var j = 0; j < varCnt; ++j) + { + effectVars[j] = EffectVar(j, obj, index); + } + effects[i] = [GetEffect(0, obj, index, 1), GetEffect(0, obj, index, 2), GetEffect(0, obj, index, 3), GetEffect(0, obj, index, 4), GetEffect(0, obj, index, 5), GetEffect(0, obj, index, 6), effectVars, index]; + } + if(GetLength(effects) != 0) + { + ret[Object_Effects] = effects; + } + + // TODO: Custom + + return ret; +} + + +global func ApplyObjectSaveData(array data, object obj) +{ + obj = obj || this; + // set values which can trigger callbacks before changing def + obj->SetObjectStatus(data[Object_Status]); + obj->SetCon(data[Object_Con]); + obj->SetOwner(data[Object_Owner]); + obj->DoDamage(data[Object_Damage] - obj->GetDamage()); + if(data[Object_Energy]) + { + if(GetPhysical("Energy", PHYS_Current, obj) < data[Object_Energy]) + { + SetPhysical("Energy", data[Object_Energy], PHYS_Temporary, obj); + } + obj->DoEnergy(data[Object_Energy] - GetObjectVal("Energy", 0, obj), obj, true); + } + + for(var content in data[Object_Contents]) + { + var temp = obj->CreateContents(ROCK); + temp->ApplyObjectSaveData(content); + } + + obj->ChangeDef(data[Object_ID]); + + // the following changes should not call Callbacks anymore + obj->SetName(data[Object_Name]); + obj->SetController(data[Object_Controller]); + obj->SetKiller(data[Object_Killer]); + obj->SetCategory(data[Object_Category]); + obj->SetPosition(data[Object_Position][0], data[Object_Position][1]); + obj->SetR(data[Object_Position][2]); + SetXDir(data[Object_Speed][0], obj, 65536); + SetYDir(data[Object_Speed][1], obj, 65536); + SetRDir(data[Object_Speed][2], obj, 65536); + obj->SetMass(data[Object_OwnMass] - obj->GetMass()); + obj->SetColorDw(data[Object_ColorDw]); + obj->SetShape(data[Object_Shape][0], data[Object_Shape][1], data[Object_Shape][2], data[Object_Shape][3]); + obj->SetSolidMask(data[Object_SolidMask][0], data[Object_SolidMask][1], data[Object_SolidMask][2], data[Object_SolidMask][3], data[Object_SolidMask][4], data[Object_SolidMask][5]); + obj->SetPicture(data[Object_Picture][0], data[Object_Picture][1], data[Object_Picture][2], data[Object_Picture][3]); + obj->SetAlive(data[Object_Alive]); + obj->DoMagicEnergy(data[Object_MagicEnergy] - obj->GetMagicEnergy()); + obj->DoBreath(data[Object_Breath] - obj->GetBreath()); + obj->SetEntrance(data[Object_Entrance]); + + if(data[Object_Vertices]) + { + var cnt = GetLength(data[Object_Vertices]); + while(obj->GetVertexNum() < cnt) + { + obj->AddVertex(); + } + + var i = 0; + for(var vertex in data[Object_Vertices]) + { + obj->SetVertex(i, VTX_X, vertex[0], VTX_SetPermanent); + obj->SetVertex(i, VTX_Y, vertex[1], VTX_SetPermanent); + obj->SetVertex(i, VTX_CNAT, vertex[2], VTX_SetPermanent); + obj->SetVertex(i, VTX_Friction, vertex[3], (i == cnt - 1 && VTX_SetPermanentUpd) || VTX_SetPermanent); + ++i; + } + } + + var id = data[Object_ID]; + for(var physical in ["Energy", "Breath", "Walk", "Jump", "Scale", "Hangle", "Dig", "Swim", "Throw", "Push", "Fight", "Magic", "Float", "CanScale", "CanHangle", "CanDig", "CanConstruct", "CanChop", "CanSwimDig", "CanFly", "CorrosionResist", "BreatheWater"]) + { + obj->SetPhysical(physical, GetPhysical(physical, 0, 0, id), PHYS_Temporary); + } + + if(data[Object_Physicals]) // TODO: Update for StackTemporary and try to represent right mode + { + for(var physical in data[Object_Physicals]) + { + obj->SetPhysical(physical[0], physical[1], PHYS_Temporary); + } + } + + for(var localVar in data[Object_Locals]) + { + LocalX(localVar[0]) = localVar[1]; + } + + if(data[Object_Components]) + { + for(var component in data[Object_Components]) + { + obj->SetComponent(component[0], component[1]); + } + } + SetPlrViewRange(data[Object_PlrViewRange], obj, true); + obj->SetVisibility(data[Object_Visibility]); + obj->SetObjectBlitMode(data[Object_BlitMode]); + obj->SetCrewEnabled(data[Object_CrewEnabled]); + obj->SetObjectLayer(data[Object_ObjectLayer]); + obj->SetContactDensity(data[Object_ContactDensity]); + obj->SetComDir(data[Object_ComDir]); + + // unfortunately there is no SetAction without triggering CallCallbacks + // SetAction at last, so the important stuff is setup already + obj->SetAction(data[Object_Action][0], data[Object_Action][2], data[Object_Action][3], true); + obj->SetPhase(data[Object_Action][1]); + obj->SetActionData(data[Object_Action][4]); + + obj->SetDir(data[Object_Dir]); // Set Dir after Action because Dirs are enabled per action + + for(var graphic in data[Object_Graphics]) + { + SetGraphics(graphic[0], obj, graphic[1], graphic[2], graphic[3], graphic[4], graphic[5], graphic[6]); + + var transform = graphic[7]; + if(GetLength(transform) == 6) + { + SetObjDrawTransform(transform[0], transform[1], transform[2], transform[3], transform[4], transform[5], obj, graphic[2]); + } + else + { + SetObjDrawTransform(1000, 0, 0, 0, 1000, 0, obj, graphic[2]); + obj->SetObjDrawTransform2(transform[0], transform[1], transform[2], transform[3], transform[4], transform[5], transform[6], transform[7], transform[8], graphic[2]); + } + + SetClrModulation(graphic[8], obj, graphic[2]); + } + + if(data[Object_Effects]) + { + // WARNING: Can't restore lifetime + for(var effect in data[Object_Effects]) + { + var temp = AddEffect("ApplyEffectDummy", obj, effect[1], effect[2], effect[3], effect[4]); + + for(var i = 0; i < GetLength(effect[6]); ++i) + { + EffectVar(i, obj, temp) = effect[6][i]; + } + + ChangeEffect(0, obj, temp, effect[0], -1); + } + } + + // TODO: Custom +} + +global func InstantiateObjectSaveData(array data) +{ + var ret = CreateObject(ROCK); + ret->ApplyObjectSaveData(data); + return ret; +} diff --git a/DTParticles.c b/DTParticles.c new file mode 100644 index 0000000..5373134 --- /dev/null +++ b/DTParticles.c @@ -0,0 +1,15 @@ +#strict 2 + +global func DrawParticleRect(string name, array rect, int dist, int a, b, int yDir) +{ + var ret = 0; + if(GetType(b) != C4V_Array) + { + b = [b, b, b, b]; + } + ret = DrawParticleLine(name, rect[0], rect[1], rect[0] + rect[2], rect[1], dist, a, b[0], b[1], yDir); + ret += DrawParticleLine(name, rect[0] + rect[2], rect[1], rect[0] + rect[2], rect[1] + rect[3], dist, a, b[1], b[2], yDir); + ret += DrawParticleLine(name, rect[0] + rect[2], rect[1] + rect[3], rect[0], rect[1] + rect[3], dist, a, b[2], b[3], yDir); + ret += DrawParticleLine(name, rect[0], rect[1] + rect[3], rect[0], rect[1], dist, a, b[3], b[0], yDir); + return ret; +} diff --git a/DTPhysicalStack.c b/DTPhysicalStack.c new file mode 100644 index 0000000..c0aa7ad --- /dev/null +++ b/DTPhysicalStack.c @@ -0,0 +1,72 @@ +#strict 2 + +global func GetPhysicalFactorStack(object target) +{ + target || FatalError("GetPhysicalFactorStack: no target object given"); + return GetEffect("PhysicalFactorStack", target) || AddEffect("PhysicalFactorStack", target, 200); +} + +global func AddPhysicalFactor(string physical, int factor, int precision, object target) +{ + target = target || this || FatalError("AddPhysicalFactor: no target object given"); + precision = precision || 100; + + return EffectCall(target, GetPhysicalFactorStack(target), "AddFactor", physical, factor, precision); +} + +global func RemovePhysicalFactor(int id, object target) +{ + target = target || this || FatalError("AddPhysicalFactor: no target object given"); + + return EffectCall(target, GetPhysicalFactorStack(target), "RemoveFactor", id); +} + +global func FxPhysicalFactorStackStart(object target, int effectNumber, int temp) +{ + if(!temp) + { + EffectVar(1, target, effectNumber) = []; + } +} + +global func FxPhysicalFactorStackAddFactor(object target, int effectNumber, string physical, int factor, int precision) +{ + ArrayAppend(EffectVar(1, target, effectNumber), [++EffectVar(0, target, effectNumber), physical, factor, precision]); + EffectCall(target, effectNumber, "ApplyPhysical", physical); + return EffectVar(0, target, effectNumber); +} + +global func FxPhysicalFactorStackRemoveFactor(object target, int effectNumber, int id) +{ + for(var i = 0; i < GetLength(EffectVar(1, target, effectNumber)); ++i) + { + if(EffectVar(1, target, effectNumber)[i][0] == id) + { + var physical = EffectVar(1, target, effectNumber)[i][1]; + ArrayErase(EffectVar(1, target, effectNumber), i); + EffectCall(target, effectNumber, "ApplyPhysical", physical); + return true; + } + } + return 0; +} + +global func FxPhysicalFactorStackApplyPhysical(object target, int effectNumber, string physical) +{ + var phys = GetPhysical(physical, PHYS_Temporary, target); + if(phys) + { + ResetPhysical(target, physical); + } + phys = GetPhysical(physical, PHYS_Current, target); + for(var factor in EffectVar(1, target, effectNumber)) + { + if(factor[1] == physical) + { + phys *= factor[2]; + phys /= factor[3]; + } + } + SetPhysical(physical, phys, PHYS_StackTemporary, target); + return phys; +} diff --git a/DTPlayers.c b/DTPlayers.c new file mode 100644 index 0000000..ab75aef --- /dev/null +++ b/DTPlayers.c @@ -0,0 +1,82 @@ +/*-- Helper functions for iterating through all players and teams --*/ +#strict 2 + +static const Player_Number = 0; +static const Player_ID = 0 + 1; +static const Player_Name = 0 + 1 + 1; +static const Player_TaggedName = 0 + 1 + 1 + 1; +static const Player_Color = 0 + 1 + 1 + 1 + 1; +static const Player_Team = 0 + 1 + 1 + 1 + 1 + 1; +static const Player_Type = 0 + 1 + 1 + 1 + 1 + 1 + 1; + +global func GetPlayers(int team, bool exclude) +{ + var ret = []; + for(var plr, plrTeam, i = 0; (i < GetPlayerCount()) && ((plrTeam = GetPlayerTeam(plr = GetPlayerByIndex(i))) || true); ++i) + { + if(!team || (team == plrTeam) != exclude) + { + var plrInfo = []; + plrInfo[Player_Number] = plr; + plrInfo[Player_ID] = GetPlayerID(plr); + plrInfo[Player_Name] = GetPlayerName(plr); + plrInfo[Player_TaggedName] = GetTaggedPlayerName(plr); + plrInfo[Player_Color] = GetPlrColorDw(plr); + plrInfo[Player_Team] = GetPlayerTeam(plr); + plrInfo[Player_Type] = GetPlayerType(plr); + ret[GetLength(ret)] = plrInfo; + } + } + + return ret; +} + +global func GetPlayerNumbers(int team, bool exclude) +{ + var ret = []; + for(var plr, i = 0; (i < GetPlayerCount()) && ((plr = GetPlayerByIndex(i)) || true); ++i) + { + if(!team || (team == GetPlayerTeam(plr)) != exclude) + { + ret[GetLength(ret)] = plr; + } + } + return ret; +} + +global func GetTaggedTeamName(int team) +{ + return Format("%s", GetTeamColor(team), GetTeamName(team)); +} + +static const Team_ID = 0; +static const Team_Name = 0 + 1; +static const Team_TaggedName = 0 + 1 + 1; +static const Team_Color = 0 + 1 + 1 + 1; +static const Team_Players = 0 + 1 + 1 + 1 + 1; + +global func GetTeams() +{ + var ret = []; + for(var team, i = 0; (i < GetTeamCount()) && ((team = GetTeamByIndex(i)) || true); ++i) + { + var teamInfo = []; + teamInfo[Team_ID] = team; + teamInfo[Team_Name] = GetTeamName(team); + teamInfo[Team_TaggedName] = GetTaggedTeamName(); + teamInfo[Team_Color] = GetTeamColor(team); + teamInfo[Team_Players] = GetPlayers(team); + ret[GetLength(ret)] = teamInfo; + } + return ret; +} + +global func GetTeamIDs() +{ + var ret = []; + for(var team, i = 0; (i < GetTeamCount()) && ((team = GetTeamByIndex(i)) || true); ++i) + { + ret[GetLength(ret)] = team;; + } + return ret; +} diff --git a/DTQuickSort.c b/DTQuickSort.c new file mode 100644 index 0000000..7434263 --- /dev/null +++ b/DTQuickSort.c @@ -0,0 +1,66 @@ +#strict 2 + +global func SortNumeric(int a, int b) +{ + if(a < b) + { + return -1; + } + else if(a > b) + { + return 1; + } +} + +global func SortNumericInverse(int a, int b) +{ + return -SortNumeric(a, b); +} + +global func QSort(array& data, callback) // WARNING: Can cause stack-overflow with too much data +{ + if(callback == true) + { + callback = GlobalCallback("SortNumericInverse"); + } + QSort_Part(data, callback || GlobalCallback("SortNumeric"), 0, GetLength(data) - 1); + return data; +} + +global func QSort_Part(array& data, callback, int left, int right) +{ + if(left < right) + { + // Partitioning + var pPos = RandomX(left, right); + var p = data[pPos]; + var tmp; + + tmp = data[pPos]; + data[pPos] = data[right]; + data[right] = tmp; + pPos = right; + + var i = left - 1; + for(var j = left; j <= right; ++j) + { + if(Call(callback, data[j], p) < 0) + { + ++i; + tmp = data[i]; + data[i] = data[j]; + data[j] = tmp; + } + } + + ++i; + + tmp = data[i]; + data[i] = data[pPos]; + data[pPos] = tmp; + // ----- + + QSort_Part(data, callback, left, i - 1); + QSort_Part(data, callback, i + 1, right); + } +} diff --git a/DTRemoveNotification.c b/DTRemoveNotification.c new file mode 100644 index 0000000..eb4a47c --- /dev/null +++ b/DTRemoveNotification.c @@ -0,0 +1,43 @@ +#strict 2 + +global func AddRemoveNotification(callback, object target, object callbackTarget, int prio) +{ + if(!target || !callback) + { + return; + } + callbackTarget = callbackTarget || this; + return AddEffect("IntRemoveNotifier", target, prio || 1, 0, callbackTarget, 0, callback); +} + +global func RemoveRemoveNotification(int id, object target) +{ + if(!target) + { + return; + } + return RemoveEffect(0, target, id); +} + +global func FxIntRemoveNotifierStart(object target, int effectNumber, int temp, callback) +{ + if(!temp) + { + EffectVar(0, target, effectNumber) = callback; + } +} + +global func FxIntRemoveNotifierStop(object target, int effectNumber, int reason, bool temp) +{ + if(!temp) + { + if(reason == FX_Call_RemoveClear) + { + Call(EffectVar(0, target, effectNumber), target); + } + else if(reason == FX_Call_RemoveDeath) + { + return FX_Stop_Deny; + } + } +} diff --git a/DTScenUtils.c b/DTScenUtils.c new file mode 100644 index 0000000..be55cfe --- /dev/null +++ b/DTScenUtils.c @@ -0,0 +1,91 @@ +#strict 2 + +static const ObjStr_Skip = -1; +static const ObjStr_Defaults = 0; +static const ObjStr_NoDefault = 1; +static const ObjStr_NoLocals = 2; +static const ObjStr_NoContents = 4; +static const ObjStr_ModeParts = 1; // NoDefault + +global func LogObjects(array criteria, bool inline, bool& first) +{ + for(var obj in FindObjects(criteria)) + { + var str = GetObjectString(obj); + if(str) Log((inline && ((first && " %s") || ", %s")) || " %s;", str); + first = false; + } +} + +global func GetObjects(bool inline) +{ + var first = true, exp = Find_And(Find_Not(Find_Func("IsHUD")), Find_Not(Find_Func("IsLight")), Find_NoContainer()); + if(inline) Log("["); + LogObjects(Find_And(Find_Category(C4D_Rule | C4D_Goal | C4D_Environment), exp), inline, first); // goals, rules and environment first + LogObjects(Find_And(Find_Not(Find_Category(C4D_Rule | C4D_Goal | C4D_Environment)), exp), inline, first); // and the rest + if(inline) Log("]"); +} + +global func GetObjectString(obj) +{ + var extra, extray, custom, customStr = ""; + extra = ""; + extray = 0; + custom = obj->~CustomObjectString(customStr); + if(custom == ObjStr_Skip) + { + return; + } + else if((custom & ObjStr_ModeParts) != ObjStr_NoDefault) + { + if(obj->GetR() != 0) extra = Format("%s->SetRX(%d)", extra, obj->GetR()); + if(obj->GetCon() != 100) + { + extra = Format("%s->SetConX(%d)", extra, obj->GetCon()); + extray = -GetDefCoreVal("Offset", "DefCore", GetID(obj), 1) * (100-obj->GetCon()) / 100; + } + if(obj->GetDir()) + { + extra = Format("%s->SetDirX(%d)", extra, obj->GetDir()); + } + if(!(custom & ObjStr_NoLocals)) for(var iFunc = 0; iFunc < 2; ++iFunc) + { + for(var i = 0; i < GetLocalCount(obj, iFunc); ++i) + { + var key = GetLocalByIndex(i, obj, iFunc); + var val; + if(GetType(key) == C4V_Int || GetType(key) == C4V_Any) val = Local(key, obj); + else if(GetType(key) == C4V_String) val = LocalN(key, obj); + if(val == 0) continue; + extra = Format("%s->SetLocalX(%s, %s)", extra, Serialize(key), Serialize(val)); + } + } + if(!(custom & ObjStr_NoContents)) for(var content in FindObjects(Find_Container(obj))) + { + extra = Format("%s->EnterX(%s)", extra, GetObjectString(content)); + } + } + if(GetCategory(obj) & C4D_StaticBack) + { + extray -= GetDefOffset(GetID(obj), 1) * 2 + GetDefHeight(GetID(obj)); + } + return Format("CreateObjectX(%i, %d, %d, %d)%s%s", + GetID(obj), + GetX(obj), + GetY(obj)/* - GetDefCoreVal("Offset", "DefCore", GetID(obj), 1) - extray*/, + GetOwner(obj), + extra, customStr); +} + +global func CreateObjectX(id id, int x, int y, int owner) { return CreateObject(id, x, y, owner)->SetPositionX(x, y); } +global func SetPositionX(int x, int y) { this->SetPosition(x, y); return this; } +global func SetDirX(int dir) { this->SetDir(dir); return this; } +global func SetRX(int r) { this->SetR(r); return this; } +global func SetConX(int con) { this->SetCon(con); return this; } +global func EnterX(object obj) { Enter(this, obj); return this; } +global func SetLocalX(key, val) +{ + if(GetType(key) == C4V_Int || GetType(key) == C4V_Any) Local(key, this) = val; + else LocalN(key) = val; + return this; +} diff --git a/DTScopedVars.c b/DTScopedVars.c new file mode 100644 index 0000000..f64ccdc --- /dev/null +++ b/DTScopedVars.c @@ -0,0 +1,87 @@ +#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 + { + 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; + } + } + } + + return CheckCustomScopedVar(variable); +} + +global func CheckCustomScopedVar() { return _inherited(...); } diff --git a/DTTemplateFunctions.c b/DTTemplateFunctions.c new file mode 100644 index 0000000..860c9e1 --- /dev/null +++ b/DTTemplateFunctions.c @@ -0,0 +1,307 @@ +/*-- Template Functions --*/ + +#strict 2 + +static v; +static TMPL_Funcs; +static const TMPL_FuncArguments = 0; +static const TMPL_FuncContents = 1; +static const TMPL_FuncName = 2; +static const TMPL_FuncCommands = 3; + +global func InitializeTemplateFunctions() +{ + if(GetType(v) != C4V_Array) v = []; + if(GetType(TMPL_Funcs) != C4V_Array) TMPL_Funcs = []; +} + +global func DefineFunction(string name, arguments, commands) +{ + InitializeTemplateFunctions(); + + var anonymousFunction = Function(arguments, commands); + + var function = [anonymousFunction[0], anonymousFunction[1], name, commands]; + + SetFunction(name, function); +} + +global func SetFunction(string name, array function) +{ + var index = FindTemplateFunction(name); + if(index != -1) + { + TMPL_Funcs[index] = function; + } + else + { + TMPL_Funcs[GetLength(TMPL_Funcs)] = function; + } +} + +global func RemoveFunction(string name) +{ + var index = FindTemplateFunction(name); + if(index != -1) + { + var i; + for(i = index; i < GetLength(TMPL_Funcs) - 1; ++i) + { + TMPL_Funcs[i] = TMPL_Funcs[i + 1]; + } + TMPL_Funcs[GetLength(TMPL_Funcs) - 1] = 0; + } +} + +global func Function(arguments, commands) +{ + if(!commands) + { + commands = arguments; + arguments = []; + } + + if(GetType(arguments) == C4V_String) arguments = [arguments]; + else if(arguments == 0) arguments = []; + + if(GetType(commands) == C4V_String) commands = [commands]; + + var funcContents = []; + for(var command in commands) + { + var isArg = false; + var argument = ""; + var funcContent = []; + var contentPart = ""; + var escapeCount = 0; + for(var i = 0; i < GetLength(command); ++i) + { + var c = GetChar(command, i); + if(isArg) + { + if(c == 37) // % + { + if(argument == "") + { + contentPart = Format("%s%%", contentPart); + } + else + { + var index = GetIndexOf2(argument, arguments); + if(index == -1) + { + FatalError(Format("Function: Unknown argument-name %s", argument)); + return; + } + else + { + funcContent[GetLength(funcContent)] = [index, escapeCount]; + argument = ""; + escapeCount = 0; + } + } + isArg = false; + } + else if(argument == "" && c == 47) // / + { + ++escapeCount; + } + else + { + if(contentPart != "") + { + funcContent[GetLength(funcContent)] = contentPart; + contentPart = ""; + } + + argument = Format("%s%c", argument, c); + } + } + else + { + if(c == 37) // % + { + isArg = true; + } + else if(c == 39) // ' + { + contentPart = Format("%s\"", contentPart); + } + else + { + contentPart = Format("%s%c", contentPart, c); + } + } + } + if(isArg) FatalError(Format("Function: argument-reference \"%s\" not closed.", argument)); + else if(contentPart) funcContent[GetLength(funcContent)] = contentPart; + funcContents[GetLength(funcContents)] = funcContent; + } + + return [arguments, funcContents]; +} + +global func FindTemplateFunction(string name) +{ + var i = 0; + for(var function in TMPL_Funcs) + { + if(GetType(function) == C4V_Array && function[TMPL_FuncName] == name) return i; + ++i; + } + return -1; +} + +global func F(string name, array args) +{ + return f(Func(name), args); +} + +global func f(array function, array args) +{ + var ret; + for(var content in function[TMPL_FuncContents]) + { + var command = ""; + for(var contentPart in content) + { + if(GetType(contentPart) == C4V_Array) + { + var part = StringReplace("'", Serialize(args[contentPart[0]]), "\\\""); + for(var i = 0; i < contentPart[1]; ++i) + { + part = EscapeString(part); + } + command = Format("%s%s", command, part); + } + else command = Format("%s%s", command, contentPart); + } + ret = eval(command); + } + return ret; +} + +global func DebugF(string function, array args) +{ + return DebugFunc(Func(function), args); +} + +global func DebugFunc(array function, array args) +{ + var ret; + for(var content in function[TMPL_FuncContents]) + { + var command = ""; + for(var contentPart in content) + { + if(GetType(contentPart) == C4V_Array) + { + var part = StringReplace("'", Serialize(args[contentPart[0]]), "\\\""); + for(var i = 0; i < contentPart[1]; ++i) + { + part = EscapeString(part); + } + command = Format("%s%s", command, part); + } + else command = Format("%s%s", command, contentPart); + } + Log(command); + } + return ret; +} + +global func Func(string name) +{ + var index = FindTemplateFunction(name); + if(index == -1) + { + FatalError(Format("Func: Unknown function %s.", name)); + return; + } + return TMPL_Funcs[index]; +} + +global func SaveFunction(int plr, string name, array function) +{ + return SetPlrExtraDataArray(plr, Format("TemplateFunction_%s", name), function); +} + +global func LoadFunction(int plr, string name, string loadAs) +{ + var function = GetPlrExtraDataArray(plr, Format("TemplateFunction_%s", name)); + if(function == 0) + { + FatalError(Format("LoadFunction: Unknown function: \"%s\"", name)); + return; + } + if(loadAs != 0) + { + SetFunction(loadAs, function); + } + return function; +} + +global func DeleteFunction(int plr, string name) +{ + return SetPlrExtraDataString(plr, Format("TemplateFunction_%s", name), ""); +} + +global func CallCustom(callback, args) +{ + if(GetType(callback) == C4V_Array && GetLength(callback) >= 2 && GetType(callback[0]) == C4V_Array && GetType(callback[1]) == C4V_Array) + { + return f(callback, args); + } + else + { + return _inherited(callback, args, ...); + } +} + +global func CheckCustomCallback(callback) +{ + if(GetType(callback) == C4V_Array && (GetLength(callback) == 2 || (GetLength(callback) == 4 && GetType(callback[2]) == C4V_String && GetType(callback[3]) == C4V_Array)) && GetType(callback[0]) == C4V_Array && GetType(callback[1]) == C4V_Array) + { + var stringOnlyChecks = [callback[0]]; + + if(GetLength(callback) == 4) + { + stringOnlyChecks[1] = callback[3]; + } + + for(var check in stringOnlyChecks) + { + for(var val in check) + { + if(GetType(val) != C4V_String) + { + return _inherited(callback, ...); + } + } + } + + for(var contentParts in callback[1]) + { + if(GetType(contentParts) != C4V_Array) + { + return _inherited(callback, ...); + } + + for(var content in contentParts) + { + if(GetType(content) == C4V_String) + { + continue; + } + + if(GetType(content) != C4V_Array || GetLength(content) != 2 || (content[0] && GetType(content[0]) == C4V_Int && content[0] < 0) || (content[1] && GetType(content[1]) == C4V_Int && content[1] < 0)) + { + return _inherited(callback, ...); + } + } + } + + return true; + } + return _inherited(callback, ...); +} diff --git a/DTTimer.c b/DTTimer.c new file mode 100644 index 0000000..ecc5885 --- /dev/null +++ b/DTTimer.c @@ -0,0 +1,26 @@ +#strict 2 + +global func AddTimer(callback, int timer, object target, int prio) +{ + target = target || this; + return AddEffect("IntTimer", target, prio || 1, timer, target, 0, callback); +} + +global func RemoveTimer(int id, object target) +{ + target = target || this; + return RemoveEffect(0, target, id); +} + +global func FxIntTimerStart(object target, int effectNumber, int temp, callback) +{ + if(!temp) + { + EffectVar(0, target, effectNumber) = callback; + } +} + +global func FxIntTimerTimer(object target, int effectNumber, int effectTime) +{ + return Call(EffectVar(0, target, effectNumber)); +} diff --git a/DTTransform.c b/DTTransform.c new file mode 100644 index 0000000..07206c2 --- /dev/null +++ b/DTTransform.c @@ -0,0 +1,240 @@ +#strict 2 + +global func ResetTransform(overlays) +{ + for(var overlay in TransformOverlays(overlays)) + { + if(!overlay) SetObjDrawTransform(0, 0, 0, 0, 0, 0, this, overlay); + else SetObjDrawTransform(1000, 0, 0, 0, 1000, 0, this, overlay); + } +} + +global func SetTransform(array transforms, overlays) +{ + for(var overlay in TransformOverlays(overlays)) + { + ResetTransform(overlay); + AddTransform(transforms, overlay); + } +} + +global func AddTransform(array transforms, overlays) +{ + for(var overlay in TransformOverlays(overlays)) + { + for(var transform in transforms) + { + SetObjDrawTransform2(transform[0][0], transform[0][1], transform[0][2], transform[1][0], transform[1][1], transform[1][2], transform[2][0], transform[2][1], transform[2][2], overlay); + } + } +} + +global func TransformOverlays(overlays) +{ + if(!overlays || GetType(overlays) == C4V_Int) + { + if(overlays >= 0) return [overlays]; + else + { + var ret = []; + overlays = Abs(overlays); + for(var i = 0; i <= overlays; ++i) + { + ret[GetLength(ret)] = i; + } + return ret; + } + } + else if(GetType(overlays) == C4V_Array) + { + var ret = [], last; + last = overlays[0]; + var i = 1; + if(last < 0) + { + i = 0; + last = 0; + } + else + { + ret[0] = last; + } + for(; i < GetLength(overlays); ++i) + { + var overlay = overlays[i]; + if(overlay < 0) + { + overlay = Abs(overlay); + for(var j = last + 1; j <= overlay; ++j) + { + ret[GetLength(ret)] = j; + } + } + else + { + ret[GetLength(ret)] = overlay; + } + last = overlay; + } + + return ret; + } + else + { + FatalError("TransformOverlays: overlays must be a single integer or an array."); + } +} + +global func Rotate() { return RotateZ(...); } + +global func RotateX(int phi, int prec) +{ + prec = prec || 1; + + var cos = Cos(phi, 1000, prec); + var sin = Sin(phi, 1000, prec); + + return + [ + [1000, 0, 0], + [ 0, cos, -sin], + [ 0, sin, cos] + ]; +} + +global func RotateY(int phi, int prec) +{ + prec = prec || 1; + + var cos = Cos(phi, 1000, prec); + var sin = Sin(phi, 1000, prec); + + return + [ + [ cos, 0, sin], + [ 0, 1000, 0], + [-sin, 0, cos] + ]; +} + +global func RotateZ(int phi, int prec) +{ + prec = prec || 1; + + var cos = Cos(phi, 1000, prec); + var sin = Sin(phi, 1000, prec); + + return + [ + [cos, -sin, 0], + [sin, cos, 0], + [ 0, 0, 1000] + ]; +} + +global func Scale3D(int x, int y, int z) +{ + return + [ + [x, 0, 0], + [0, y, 0], + [0, 0, z] + ]; +} + +global func Scale2D(int x, int y) { return Scale3D(x, y, 1000); } + +global func ScaleX(int f) { return Scale3D(f, 1000, 1000); } +global func ScaleY(int f) { return Scale3D(1000, f, 1000); } +global func ScaleZ(int f) { return Scale3D(1000, 1000, f); } + +global func Translate2D(int x, int y, int prec) +{ + prec = prec || 1; + return + [ + [1000, 0, x * 1000 / prec], + [ 0, 1000, y * 1000 / prec], + [ 0, 0, 1000] + ]; +} + +global func TranslateX(int x, int prec) { return Translate2D(x, 0, prec); } +global func TranslateY(int y, int prec) { return Translate2D(0, y, prec); } + +global func MirrorX() +{ + return + [ + [-1000, 0, 0], + [ 0, 1000, 0], + [ 0, 0, 1000] + ]; +} + +global func MirrorY() +{ + return + [ + [1000, 0, 0], + [ 0, -1000, 0], + [ 0, 0, 1000] + ]; +} + +global func MirrorZ() // useless? +{ + return + [ + [1000, 0, 0], + [ 0, 1000, 0], + [ 0, 0, -1000] + ]; +} + +global func Skew2D(int x, int y) +{ + return + [ + [1000, x, 0], + [ y, 1000, 0], + [ 0, 0, 1000] + ]; +} + +global func SkewX(int x) { return Skew2D(x, 0); } +global func SkewY(int y) { return Skew2D(0, y); } + +global func Matrix3x3Multiply(array a, array b, int precision) +{ + return + [ + [(a[0][2] * b[2][0] + a[0][1] * b[1][0] + a[0][0] * b[0][0]) / precision, (a[0][2] * b[2][1] + a[0][1] * b[1][1] + a[0][0] * b[0][1]) / precision, (a[0][2] * b[2][2] + a[0][1] * b[1][2] + a[0][0] * b[0][2]) / precision], + [(a[1][2] * b[2][0] + a[1][1] * b[1][0] + a[1][0] * b[0][0]) / precision, (a[1][2] * b[2][1] + a[1][1] * b[1][1] + a[1][0] * b[0][1]) / precision, (a[1][2] * b[2][2] + a[1][1] * b[1][2] + a[1][0] * b[0][2]) / precision], + [(a[2][2] * b[2][0] + a[2][1] * b[1][0] + a[2][0] * b[0][0]) / precision, (a[2][2] * b[2][1] + a[2][1] * b[1][1] + a[2][0] * b[0][1]) / precision, (a[2][2] * b[2][2] + a[2][1] * b[1][2] + a[2][0] * b[0][2]) / precision] + ]; +} + +global func PreTransform(array transforms) // funzt nit +{ + if(GetLength(transforms) == 0) + { + FatalError("PreTransform called without transforms."); + } + else + { + var ret = transforms[0]; + for(var i = 1; i < GetLength(transforms); ++i) + { + ret = Matrix3x3Multiply(ret, transforms[i], 1000); + } + return ret; + } +} + +// Riesenschädl +// GetCursor(0)->SetTransform([TranslateY(8), RotateX(4), ScaleZ(400), TranslateY(-10)]) + +// Ähnlich Chipakyus Demo +// Schedule("FindObject(HUT2)->SetTransform([TranslateY(-20), RotateZ(++Global(0)), TranslateY(0), RotateX(-1), TranslateY(20)])", 1, 10000) +// Schedule("GetCursor(0)->SetTransform([TranslateY(-8), RotateZ(++Global(0)), TranslateY(0), RotateX(-2), TranslateY(8)])", 1, 10000) diff --git a/DTUtility.c b/DTUtility.c new file mode 100644 index 0000000..a747d33 --- /dev/null +++ b/DTUtility.c @@ -0,0 +1,744 @@ +#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 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; + } +} -- cgit v1.2.3-54-g00ecf