// Reki (May 28 2024): // Extended map scripting capabilities // essentially a mini asm language meant for semi-visual scripting // by mappers inside of the .map file, using placed entities to create // the logic chains and call entrypoints inside their MapScript files #ifdef SSQC #define LOGIC_IF_SPAWNFIELDS(v) \ SPAWNFIELD_PARSESTRING(targetname, v) \ SPAWNFIELD_PARSESTRING(value1, v) \ SPAWNFIELD_PARSESTRING(value2, v) \ SPAWNFIELD_PARSESTRING(targetThen, v) \ SPAWNFIELD_PARSESTRING(targetElse, v) #define LOGIC_STORE_SPAWNFIELDS(v) \ SPAWNFIELD_PARSEINT(datatype, v) \ SPAWNFIELD_PARSESTRING(value, v) #define LOGIC_SET_SPAWNFIELDS(v) \ SPAWNFIELD_PARSESTRING(register, v) \ SPAWNFIELD_PARSESTRING(value, v) class logic_store; // prototype, icky class script_base_c : map_entity_c { //string targetname; <- inherited //string target; <- inherited string target2; string target3; string target4; nonvirtual void(string msg) ErrorOut = { error(sprintf("^xF00ERROR IN SCRIPT ENTITY %s\n^xF00 %s\n", this.targetname, msg)); }; nonvirtual logic_store(string str) isRegister; nonvirtual logic_store(string str) resolveRegister; }; // data registers class logic_store : script_base_c { int datatype; __variant value; logic_store(); virtual void ParseSpawnField(string key, string value); // fetcher for virtual __variant(int type=0) get = { __variant val = this.value; int val_type = this.datatype; if (val_type == EV_STRING) // this could potentially be a ""pointer""" to another register { logic_store aliasTo = resolveRegister((string)val); if (aliasTo) { val = aliasTo.value; val_type = aliasTo.datatype; } } __variant retval = val; if (type > 0) { if (val_type != type) { switch(type) // switch for what type we were requested to return { case EV_INTEGER: // we need to convert to a integer switch (val_type) { case EV_FLOAT: retval = (int)(val); break; case EV_VECTOR: retval = (int)vlen((vector)val); break; case EV_STRING: retval = (int)stoi((string)val); break; default: ErrorOut(sprintf("impossible conversion from %i to %i", val_type, type)); } break; case EV_FLOAT: // we need to convert to a float switch (val_type) { case EV_INTEGER: retval = (float)((int)val); break; case EV_VECTOR: retval = (float)vlen((vector)val); break; case EV_STRING: retval = (float)stof((string)val); break; default: ErrorOut(sprintf("impossible conversion from %i to %i", val_type, type)); } break; case EV_VECTOR: // we need to convert to a vector switch (val_type) { case EV_INTEGER: retval = (vector)([(int)val, (int)val, (int)val]); break; case EV_FLOAT: retval = (vector)([(float)val, (float)val, (float)val]); break; case EV_STRING: retval = (vector)stov((string)val); break; default: ErrorOut(sprintf("impossible conversion from %i to %i", val_type, type)); } break; case EV_STRING: // we need to convert to a string switch (val_type) { case EV_INTEGER: retval = (string)itos((float)val); break; case EV_FLOAT: retval = (string)ftos((float)val); break; case EV_VECTOR: retval = (string)vtos((vector)val); break; default: ErrorOut(sprintf("impossible conversion from %i to %i", val_type, type)); } break; } } } return retval; }; // setter virtual void(string val) set = { switch(this.datatype) { case EV_INTEGER: this.value = (int)stoi(val); break; case EV_FLOAT: this.value = (float)stof(val); break; case EV_VECTOR: this.value = (vector)stov(val); break; case EV_STRING: this.value = val; break; } }; }; class logic_set : script_base_c { string register; string value; logic_set(); virtual void ParseSpawnField(string key, string value); nonvirtual void() set_value = { if (!isRegister(this.register)) { ErrorOut(sprintf("invalid register \"%s\" in logic_set entity", this.register)); return; } logic_store regRef = resolveRegister(this.register); string old_val = regRef.get(EV_STRING); regRef.set(this.value); // trigger targets if the value changed if (old_val != this.value) { use_targets_ex(this, this.target); use_targets_ex(this, this.target2); use_targets_ex(this, this.target3); use_targets_ex(this, this.target4); } }; }; class logic_ifeq : script_base_c { string value1; string value2; string targetThen; string targetElse; logic_ifeq(); virtual void ParseSpawnField(string key, string value); nonvirtual void() evaluateTrue = { if (this.targetThen == __NULL__) return; use_targets_ex(this, this.targetThen); }; nonvirtual void() evaluateFalse = { if (this.targetElse == __NULL__) return; use_targets_ex(this, this.targetElse); }; virtual void(__variant val1, __variant val2) evaluate = { if ((float)val1 == (float)val2) { evaluateTrue(); print("evaluated true\n"); } else { evaluateFalse(); print("evaluated false\n"); } }; virtual void() resolve = { float val1, val2; void(__out float val, __in string str) getVal = { if (isRegister(str)) { logic_store aliasTo = resolveRegister(str); val = aliasTo.get(EV_FLOAT); } else { val = stof(str); } } getVal(val1, value1); getVal(val2, value2); print(sprintf("%g(%s) == %g(%s)\n", val1, value1, val2, value2)); evaluate(val1, val2); }; }; class logic_ifgt : logic_ifeq { virtual void(__variant val1, __variant val2) evaluate = { if (val1 > val2) evaluateTrue(); else evaluateFalse(); }; }; class logic_ifge : logic_ifeq { virtual void(__variant val1, __variant val2) evaluate = { if (val1 >= val2) evaluateTrue(); else evaluateFalse(); }; }; class logic_ifstrcmp : logic_ifeq { virtual void(__variant val1, __variant val2) evaluate = { if (strcmp(val1, val2)) evaluateTrue(); else evaluateFalse(); }; virtual void() resolve = { string val1, val2; void(__out string val, __in string str) getVal = { if (isRegister(str)) { logic_store aliasTo = resolveRegister(str); val = aliasTo.get(EV_STRING); } else { val = str; } } getVal(val1, value1); getVal(val2, value2); evaluate(val1, val2); }; }; class logic_ifstricmp : logic_ifstrcmp { virtual void(__variant val1, __variant val2) evaluate = { if (strcasecmp(val1, val2)) evaluateTrue(); else evaluateFalse(); }; }; #endif