// Ryzom - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #include "stdpch.h" #include "nel/gui/interface_expr.h" #include "nel/gui/interface_link.h" #include "nel/gui/interface_element.h" #include "nel/gui/db_manager.h" #include "nel/misc/i18n.h" using namespace std; using namespace NLMISC; namespace NLGUI { void ifexprufct_forcelink() { } // alias to CInterfaceExprValue typedef CInterfaceExprValue CIEV; /** takes arguments of a binary operator, and promote them to the best type. * string are not supported * \return true */ bool promoteToNumericalBestType(CInterfaceExpr::TArgList &_list) { uint i; bool bIsNumerical = true; for (i = 0 ; i < _list.size(); ++i) if (!_list[i].isNumerical()) bIsNumerical = false; if (bIsNumerical) { bool bDouble = false; for (i = 0 ; i < _list.size(); ++i) if (_list[i].getType() == CIEV::Double) bDouble = true; if (bDouble) { for (i = 0 ; i < _list.size(); ++i) _list[i].toDouble(); } else { for (i = 0 ; i < _list.size(); ++i) _list[i].toInteger(); } return true; } return false; } ///////////////////// // ADD 2 numbers // ///////////////////// static DECLARE_INTERFACE_USER_FCT(userFctAdd) { if (!promoteToNumericalBestType(args)) { nlwarning("add : invalid entry"); return false; } switch(args[0].getType()) { case CIEV::Integer: result.setInteger(args[0].getInteger() + args[1].getInteger()); return true; case CIEV::Double: result.setDouble(args[0].getDouble() + args[1].getDouble()); return true; default: break; } return false; } REGISTER_INTERFACE_USER_FCT("add", userFctAdd) ///////////////////// // SUB 2 numbers // ///////////////////// static DECLARE_INTERFACE_USER_FCT(userFctSub) { if (!promoteToNumericalBestType(args)) { nlwarning("sub : invalid entry"); return false; } switch(args[0].getType()) { case CIEV::Integer: result.setInteger(args[0].getInteger() - args[1].getInteger()); return true; case CIEV::Double: result.setDouble(args[0].getDouble() - args[1].getDouble()); return true; default: break; } return false; } REGISTER_INTERFACE_USER_FCT("sub", userFctSub) /////////////////// // MUL 2 numbers // /////////////////// static DECLARE_INTERFACE_USER_FCT(userFctMul) { if (!promoteToNumericalBestType(args)) { nlwarning("mul : invalid entry"); return false; } switch(args[0].getType()) { case CIEV::Integer: result.setInteger(args[0].getInteger() * args[1].getInteger()); return true; case CIEV::Double: result.setDouble(args[0].getDouble() * args[1].getDouble()); return true; default: break; } return false; } REGISTER_INTERFACE_USER_FCT("mul", userFctMul) /////////////////// // DIV 2 numbers // /////////////////// static DECLARE_INTERFACE_USER_FCT(userFctDiv) { if (args.size() != 2 || !args[0].isNumerical() || !args[1].isNumerical()) { nlwarning("div: bad arguments"); return false; } args[0].toDouble(); args[1].toDouble(); if (args[1].getDouble() == 0) { nlwarning("div: zero divide"); return false; } result.setDouble(args[0].getDouble() / args[1].getDouble()); return true; } REGISTER_INTERFACE_USER_FCT("div", userFctDiv) /////////////////// // MOD 2 numbers // /////////////////// static DECLARE_INTERFACE_USER_FCT(userFctMod) { if (args.size() != 2 || !args[0].isNumerical() || !args[1].isNumerical()) { nlwarning("mod: bad arguments"); return false; } args[0].toDouble(); args[1].toDouble(); if (args[1].getDouble() == 0) { nlwarning("mod: zero divide"); return false; } result.setDouble(fmod(args[0].getDouble(), args[1].getDouble())); return true; } REGISTER_INTERFACE_USER_FCT("mod", userFctMod) /////////////////// // abs 1 number // /////////////////// static DECLARE_INTERFACE_USER_FCT(userFctAbs) { if (args.size() != 1 || !args[0].isNumerical()) { nlwarning("abs: bad arguments"); return false; } args[0].toDouble(); result.setDouble(fabs(args[0].getDouble())); return true; } REGISTER_INTERFACE_USER_FCT("abs", userFctAbs) //////////////////////////////////// // Identity (copy its first arg) // //////////////////////////////////// static DECLARE_INTERFACE_USER_FCT(userFctIdentity) { if (args.size() > 0) { result = args[0]; return true; } else { return false; } } REGISTER_INTERFACE_USER_FCT("identity", userFctIdentity) ////////////////////////////////////////////////////////////////////////////////////////////////////// // Evaluate all of the args, and return 0, so may be used to create dependances on database entries // ////////////////////////////////////////////////////////////////////////////////////////////////////// static DECLARE_INTERFACE_USER_FCT(userFctDepends) { result.setInteger(0); return true; } REGISTER_INTERFACE_USER_FCT("depends", userFctDepends) ////////////////////////// // comparison operators // ////////////////////////// /** ugly macro to declare comparison operator in a 'compact' way * this can compare number vs number & string vs string */ #define CREATE_CMP_OPERATOR(op, name) \ static DECLARE_INTERFACE_USER_FCT(userFct##name) \ { \ \ if (args.size() != 2) \ { \ nlwarning("comparison : bad number of arguments"); \ return false; \ } \ if (args[0].getType() == CIEV::String && args[1].getType() == CIEV::String) \ { \ result.setBool(strcmp(args[0].getString().c_str(), \ args[1].getString().c_str()) op 0); \ return true; \ } \ if (args.size() != 2 || !args[0].isNumerical() || !args[1].isNumerical()) \ { \ nlwarning("comparison : arguments are not numerical"); \ return false; \ } \ args[0].toDouble(); \ args[1].toDouble(); \ result.setBool(args[0].getDouble() op args[1].getDouble()); \ return true; \ } \ REGISTER_INTERFACE_USER_FCT(#name, userFct##name) // declare all comparison operators //CREATE_CMP_OPERATOR(==, eq) CREATE_CMP_OPERATOR(!=, ne) CREATE_CMP_OPERATOR(==, eq) CREATE_CMP_OPERATOR(< , lt) CREATE_CMP_OPERATOR(<=, le) CREATE_CMP_OPERATOR(> , gt) CREATE_CMP_OPERATOR(>=, ge) ////////////////// // Logical OR // ////////////////// static DECLARE_INTERFACE_USER_FCT(userFctOr) { for(uint k = 0; k < args.size(); ++k) { if (!args[k].toBool()) { nlwarning("Argument is not boolean"); return false; } if (args[k].getBool()) { result.setBool(true); return true; } } result.setBool(false); return true; } REGISTER_INTERFACE_USER_FCT("or", userFctOr) ////////////////// // Logical AND // ////////////////// static DECLARE_INTERFACE_USER_FCT(userFctAnd) { for(uint k = 0; k < args.size(); ++k) { if (!args[k].toBool()) { nlwarning("Argument is not boolean"); return false; } if (!args[k].getBool()) { result.setBool(false); return true; } } result.setBool(true); return true; } REGISTER_INTERFACE_USER_FCT("and", userFctAnd) ////////////////// // Logical NOT // ////////////////// static DECLARE_INTERFACE_USER_FCT(userFctNot) { if (args.size() != 1) { nlwarning("not : bad number of arguments"); return false; } if (!args[0].toBool()) { nlwarning("Argument is not boolean"); return false; } result.setBool(!args[0].getBool()); return true; } REGISTER_INTERFACE_USER_FCT("not", userFctNot) //////////////////////////////////// // String Add Operation // //////////////////////////////////// static DECLARE_INTERFACE_USER_FCT(userFctStr) { if (args.size() > 0) { ucstring res(""); for (uint32 i = 0; i < args.size(); ++i) { args[i].toString(); res += args[i].getUCString(); } result.setUCString (res); return true; } else { return false; } } REGISTER_INTERFACE_USER_FCT("str", userFctStr) //////////////////////////////////// // Integer Operation // //////////////////////////////////// static DECLARE_INTERFACE_USER_FCT(userFctInt) { if (args.size() != 1) { return false; } args[0].toInteger(); result.setInteger(args[0].getInteger()); return true; } REGISTER_INTERFACE_USER_FCT("int", userFctInt) //////////////////////////////////// // Branching Operation ifthenelse // //////////////////////////////////// static DECLARE_INTERFACE_USER_FCT(userFctIfThenElse) { if ((args.size() < 1) || (args.size() > 3)) return false; if (!args[0].toBool()) return false; if (args[0].getBool()) { result = args[1]; } else { if (args.size() == 3) result = args[2]; else result.setBool (false); } return true; } REGISTER_INTERFACE_USER_FCT("ifthenelse", userFctIfThenElse) //////////////////////////////// // Branching Operation switch // //////////////////////////////// static DECLARE_INTERFACE_USER_FCT(userFctSwitch) { if (args.size() < 2) return false; if (!args[0].toInteger()) return false; sint64 n = args[0].getInteger(); if ((n > ((sint64)args.size()-2)) || (n < 0)) return false; result = args[(uint)n+1]; return true; } REGISTER_INTERFACE_USER_FCT("switch", userFctSwitch) ///////////////////////////////// // Takes maximum of any numbers // ///////////////////////////////// static DECLARE_INTERFACE_USER_FCT(userFctMax) { // compute type of output if (!promoteToNumericalBestType(args)) { nlwarning("max : invalid entry"); return false; } uint i; if (args[0].getType() == CIEV::Integer) { sint64 m; m = args[0].getInteger(); for (i = 1; i < args.size(); ++i) m = std::max(m,args[i].getInteger()); result.setInteger(m); } else { double m; m = args[0].getDouble(); for (i = 1; i < args.size(); ++i) m = std::max(m,args[i].getDouble()); result.setDouble(m); } return true; } REGISTER_INTERFACE_USER_FCT("max", userFctMax) ///////////////////////////////// // Takes minimum of 2 numbers // ///////////////////////////////// static DECLARE_INTERFACE_USER_FCT(userFctMin) { // compute type of output if (!promoteToNumericalBestType(args)) { nlwarning("max : invalid entry"); return false; } uint i; if (args[0].getType() == CIEV::Integer) { sint64 m; m = args[0].getInteger(); for (i = 1; i < args.size(); ++i) m = std::min(m,args[i].getInteger()); result.setInteger(m); } else { double m; m = args[0].getDouble(); for (i = 1; i < args.size(); ++i) m = std::min(m,args[i].getDouble()); result.setDouble(m); } return true; } REGISTER_INTERFACE_USER_FCT("min", userFctMin) ////////////////////////////// // Get Reflected Property // ////////////////////////////// static DECLARE_INTERFACE_USER_FCT(userFctGetProp) { if (args.size() != 1) return false; if (args[0].getType() != CIEV::String) return false; string sTmp = args[0].getString(); std::vector targetsVector; CInterfaceLink::splitLinkTargets(sTmp, NULL, targetsVector); if (targetsVector.empty()) { nlwarning("no target found"); return false; } CInterfaceLink::CTargetInfo &rTI = targetsVector[0]; CInterfaceElement *elem = rTI.Elem; if (!elem) { nlwarning(" : Element is NULL"); return false; } const CReflectedProperty *pRP = elem->getReflectedProperty(rTI.PropertyName); if (!pRP) return false; switch(pRP->Type) { case CReflectedProperty::Boolean: result.setBool ((elem->*(pRP->GetMethod.GetBool))()); break; case CReflectedProperty::SInt32: result.setInteger ((elem->*(pRP->GetMethod.GetSInt32))()); break; case CReflectedProperty::Float: result.setDouble ((elem->*(pRP->GetMethod.GetFloat))()); break; case CReflectedProperty::String: result.setString ((elem->*(pRP->GetMethod.GetString))()); break; case CReflectedProperty::UCString: result.setUCString ((elem->*(pRP->GetMethod.GetUCString))()); break; case CReflectedProperty::RGBA: result.setRGBA ((elem->*(pRP->GetMethod.GetRGBA))()); break; default: nlstop; return false; } return true; } REGISTER_INTERFACE_USER_FCT("getprop", userFctGetProp) /////////////////////////////// // Convert an int to a color // /////////////////////////////// static DECLARE_INTERFACE_USER_FCT(userIntToColor) { if (args.size() != 1) { nlwarning("Bad number of args"); return false; } if (!args[0].toInteger()) { nlwarning("Bad type for arg 0 : should be an integer"); return false; } CRGBA col; uint32 intCol = (uint32) args[0].getInteger(); col.R = uint8(intCol & 0xff); col.G = uint8((intCol >> 8) & 0xff); col.B = uint8((intCol >> 16) & 0xff); col.A = uint8((intCol >> 24) & 0xff); result.setRGBA(col); return true; } REGISTER_INTERFACE_USER_FCT("intToColor", userIntToColor) /////////////////////////////// // Get components of a color // /////////////////////////////// static DECLARE_INTERFACE_USER_FCT(userGetRed) { if (args.size() != 1) { nlwarning("Bad number of args"); return false; } if (!args[0].toRGBA()) { nlwarning("Bad type for arg 0 : should be a color"); return false; } result.setInteger((sint64) args[0].getRGBA().R); return true; } REGISTER_INTERFACE_USER_FCT("getRed", userGetRed) // static DECLARE_INTERFACE_USER_FCT(userGetGreen) { if (args.size() != 1) { nlwarning("Bad number of args"); return false; } if (!args[0].toRGBA()) { nlwarning("Bad type for arg 0 : should be a color"); return false; } result.setInteger((sint64) args[0].getRGBA().G); return true; } REGISTER_INTERFACE_USER_FCT("getGreen", userGetGreen) // static DECLARE_INTERFACE_USER_FCT(userGetBlue) { if (args.size() != 1) { nlwarning("Bad number of args"); return false; } if (!args[0].toRGBA()) { nlwarning("Bad type for arg 0 : should be a color"); return false; } result.setInteger((sint64) args[0].getRGBA().B); return true; } REGISTER_INTERFACE_USER_FCT("getBlue", userGetBlue) // static DECLARE_INTERFACE_USER_FCT(userGetAlpha) { if (args.size() != 1) { nlwarning("Bad number of args"); return false; } if (!args[0].toRGBA()) { nlwarning("Bad type for arg 0 : should be a color"); return false; } result.setInteger((sint64) args[0].getRGBA().A); return true; } REGISTER_INTERFACE_USER_FCT("getAlpha", userGetAlpha) //////////////////////////////////////////////// // make a rgb color from 3 components R, G, B // //////////////////////////////////////////////// static DECLARE_INTERFACE_USER_FCT(userMakeRGB) { if ((args.size() != 3) && (args.size() != 4)) { nlwarning("Bad number of args : 3 or 4 args required : R, G, B, [A]"); return false; } if (!args[0].toInteger() || !args[1].toInteger() || !args[2].toInteger()) { nlwarning("Not all args converting to integer"); return false; } uint8 nAlpha = 255; if (args.size() == 4 ) nAlpha = (uint8)args[3].getInteger(); NLMISC::CRGBA col((uint8) args[0].getInteger(), (uint8) args[1].getInteger(), (uint8) args[2].getInteger(),nAlpha); result.setRGBA(col); return true; } REGISTER_INTERFACE_USER_FCT("makeRGB", userMakeRGB) ////////////////////////////// // Get number of DB entries // ////////////////////////////// static DECLARE_INTERFACE_USER_FCT(userDBCount) { if (args.size() != 1) return false; if (args[0].getType() != CIEV::String) return false; string sTmp = args[0].getString(); if (sTmp.find('$') == string::npos) return false; string sFirstPart = sTmp.substr(0,sTmp.find('$')); string sSecondPart = sTmp.substr(sTmp.find('$')+1,sTmp.size()); sint i = 0; bool bExit = false; while (!bExit) { sTmp = sFirstPart + NLMISC::toString(i) + sSecondPart; CCDBNodeLeaf *pNL = NLGUI::CDBManager::getInstance()->getDbProp(sTmp,false); CCDBNodeBranch *pNB = NLGUI::CDBManager::getInstance()->getDbBranch(sTmp); if (pNL != NULL) { if (pNL->getValue64() == 0) bExit = true; else ++i; } else if (pNB != NULL) { ++i; } else { bExit = true; } } result.setInteger(i); return true; } REGISTER_INTERFACE_USER_FCT("dbcount", userDBCount) //////////////////////// // Get a random value // //////////////////////// static DECLARE_INTERFACE_USER_FCT(userFctRand) { if ((args.size() != 2) && (args.size() != 0)) return false; if (args.size() == 2) { if (!args[0].toDouble()) return false; if (!args[1].toDouble()) return false; double s = args[0].getDouble(); double e = 0.999+args[1].getDouble(); result.setDouble ( s + (e-s)*NLMISC::frand(1.0)); } else { result.setDouble (NLMISC::frand(1.0)); } return true; } REGISTER_INTERFACE_USER_FCT("rand", userFctRand) static DECLARE_INTERFACE_USER_FCT(userFctGetBit) { if (args.size() != 2) return false; if (!args[0].toInteger()) return false; if (!args[1].toInteger()) return false; sint64 i = args[0].getInteger(); sint64 s = args[1].getInteger(); result.setInteger (0); if ((i & (SINT64_CONSTANT(1)<> args[1].getInteger()); return true; } REGISTER_INTERFACE_USER_FCT("shr", userFctSHR) ////////////////////////// // Unsigned left shift // ////////////////////////// static DECLARE_INTERFACE_USER_FCT(userFctSHL) { if (args.size() != 2) { nlwarning("shl : bad number of arguments"); return false; } if (!args[0].toInteger() || !args[1].toInteger()) { nlwarning("Argument is not integer"); return false; } result.setInteger(((uint64)args[0].getInteger()) << args[1].getInteger()); return true; } REGISTER_INTERFACE_USER_FCT("shl", userFctSHL) ///////////////////////// // Signed right shift // ///////////////////////// static DECLARE_INTERFACE_USER_FCT(userFctSAR) { if (args.size() != 2) { nlwarning("sar : bad number of arguments"); return false; } if (!args[0].toInteger() || !args[1].toInteger()) { nlwarning("Argument is not integer"); return false; } result.setInteger(args[0].getInteger() >> args[1].getInteger()); return true; } REGISTER_INTERFACE_USER_FCT("sar", userFctSAR) //////////////////////// // Signed left shift // //////////////////////// static DECLARE_INTERFACE_USER_FCT(userFctSAL) { if (args.size() != 2) { nlwarning("sal : bad number of arguments"); return false; } if (!args[0].toInteger() || !args[1].toInteger()) { nlwarning("Argument is not integer"); return false; } result.setInteger(args[0].getInteger() << args[1].getInteger()); return true; } REGISTER_INTERFACE_USER_FCT("sal", userFctSAL) ///////////////////////////////////////////////////////////////////////////// // Extend the sign of the argument considered over 8 bits to a 64 bits int // ///////////////////////////////////////////////////////////////////////////// static DECLARE_INTERFACE_USER_FCT(extSign8To64) { if (args.size() != 1) { nlwarning("extSign8To64 : bad number of arguments"); return false; } if (!args[0].toInteger()) { nlwarning("Argument is not integer"); return false; } sint8 i = (sint8)args[0].getInteger(); result.setInteger((sint64)i); return true; } REGISTER_INTERFACE_USER_FCT("extSign8To64", extSign8To64) ////////////////////////////////////////////////////////////////////////////// // Extend the sign of the argument considered over 11 bits to a 64 bits int // ////////////////////////////////////////////////////////////////////////////// static DECLARE_INTERFACE_USER_FCT(extSign11To64) { if (args.size() != 1) { nlwarning("extSign12To64 : bad number of arguments"); return false; } if (!args[0].toInteger()) { nlwarning("Argument is not integer"); return false; } sint32 i = (sint16)args[0].getInteger() & 0x7ff; if( i > 1023 ) i |= 0xfffff800; result.setInteger((sint64)i); return true; } REGISTER_INTERFACE_USER_FCT("extSign11To64", extSign11To64) //////////////////////// // Ryzom version info // //////////////////////// static DECLARE_INTERFACE_USER_FCT(isFinalVersion) { if (!args.empty()) { nlwarning("isFinalVersion : no args required"); return false; } #if FINAL_VERSION result.setBool(true); #else result.setBool(false); #endif return true; } REGISTER_INTERFACE_USER_FCT("isFinalVersion", isFinalVersion) //////////////////////// //////////////////////// static DECLARE_INTERFACE_USER_FCT(secondsToTimeString) { if (args.size() != 1) { nlwarning("intToTimeString : 1 args required"); return false; } if (!args[0].toInteger()) { nlwarning("intToTimeString : args 0 required to be an int"); return false; } sint64 nVal = args[0].getInteger(); ucstring sTmp; if (nVal < 0) nVal = 0; sTmp = toString(nVal % 60) + " " + CI18N::get("uiMissionTimerSecond"); nVal = nVal / 60; if( nVal > 0 ) { sTmp = toString(nVal % 60) + " " + CI18N::get("uiMissionTimerMinute") + " " + sTmp; nVal = nVal / 60; if( nVal > 0 ) { sTmp = toString(nVal % 24) + " " + CI18N::get("uiMissionTimerHour") + " " + sTmp; nVal = nVal / 24; if( nVal > 0 ) { sTmp = toString(nVal) + " " + CI18N::get("uiMissionTimerDay") + " " + sTmp; } } } result.setUCString(sTmp); return true; } REGISTER_INTERFACE_USER_FCT("secondsToTimeString", secondsToTimeString) //////////////////////// //////////////////////// static DECLARE_INTERFACE_USER_FCT(secondsToTimeStringShort) { if (args.size() != 1) { nlwarning("intToTimeString : 1 args required"); return false; } if (!args[0].toInteger()) { nlwarning("intToTimeString : args 0 required to be an int"); return false; } sint64 nVal = args[0].getInteger(); ucstring sTmp; if (nVal < 0) nVal = 0; sTmp = toString("%02d", nVal % 60); nVal = nVal / 60; if( nVal > 0 ) { sTmp = toString(nVal % 60) + "'" + sTmp; nVal = nVal / 60; // if at least one hour, just display number of hour if( nVal > 0 ) { sTmp = toString(nVal % 24) + "h"; nVal = nVal / 24; // if at least one hour, just display number of days if( nVal > 0 ) { sTmp = toString(nVal) + "d"; } } } result.setUCString(sTmp); return true; } REGISTER_INTERFACE_USER_FCT("secondsToTimeStringShort", secondsToTimeStringShort) //////////////////////// //////////////////////// static DECLARE_INTERFACE_USER_FCT(oldvalue) { if (args.size() != 1) { nlwarning("oldvalue : 1 arg required"); return false; } CCDBNodeLeaf *nl = NLGUI::CDBManager::getInstance()->getDbProp(args[0].getString()); if (!nl) { nlwarning("oldvalue : arg 0 required to be an interface leaf"); return false; } result.setInteger (nl->getOldValue64()); return true; } REGISTER_INTERFACE_USER_FCT("oldvalue", oldvalue) //////////////////////// //////////////////////// static DECLARE_INTERFACE_USER_FCT(localize) { if (args.size() != 1) { nlwarning("localize : 1 arg required"); return false; } result.setUCString(CI18N::get(args[0].getString())); return true; } REGISTER_INTERFACE_USER_FCT("localize", localize); }