extern "C" { #include "lua.h" } #define ROOT_UNIT_NAME "game" #define NOT_UTIL_DEBUG_COMPATABLE #define SW_INCLUDE_FILE "lua" #include "INCLUDE.h" #include "ASW.h" char ASW::Script::Variant::m_chrBuffer[64]; /* The Settings structure controls global script settings. These settings are visible only to scripts, and thus are not visible to any other parts of the code, thus it is not specified in the header file, but here in the source file. Only property specified so far is precision of printed decimal numbers */ struct Settings : public ASW::Script::Unit { char m_chrPrecision[16]; Settings() {strcpy(m_chrPrecision, "%.2f");} virtual Unit * Child(const char * Name) const {return NULL;} virtual ASW::Script::Variant PropertyGet(const char * Name) const { if ( strcmp(Name, "precision") == 0 ) return ASW::Script::Variant((unsigned int)(atoi(&(m_chrPrecision[2])))); else throw ASW::Script::SCRIPT_ERROR_UNKNOWN_PROPERTY; } virtual const char * Name(void) const {return "settings";} virtual void PropertySet(const char * Name, const ASW::Script::Variant & Value) { if ( strcmp(Name, "precision") == 0 ) { unsigned int uintValue = (unsigned int)(Value); sprintf(m_chrPrecision, "%%.%uf"); } else throw ASW::Script::SCRIPT_ERROR_UNKNOWN_PROPERTY; } }; Settings g_stuSettings; //////////////////////////////////////////////////////////////////////////////////// // Variant //////////////////////////////////////////////////////////////////////////////////// /* Equality operator Will invoke the appropriate type cast on the Variant parameter */ bool ASW::Script::Variant:: operator==(const Variant & Value) const { switch ( m_enmType ) { case DATA_TYPE_BOOLEAN: return ( m_blnValue == (bool)(Value) ); case DATA_TYPE_CHAR: return ( m_chrValue == (char)(Value) ); case DATA_TYPE_UCHAR: return ( m_uchrValue == (unsigned char)(Value) ); case DATA_TYPE_SHORT: return ( m_shtValue == (short)(Value) ); case DATA_TYPE_USHORT: return ( m_ushtValue == (unsigned short)(Value) ); case DATA_TYPE_INT: return ( m_intValue == (int)(Value) ); case DATA_TYPE_UINT: return ( m_uintValue == (unsigned int)(Value) ); case DATA_TYPE_SINGLE: return ( m_fltValue == (float)(Value) ); case DATA_TYPE_DOUBLE: return ( m_dblValue == (double)(Value) ); case DATA_TYPE_STRING: return ( strcmp(m_ptrString, (const char *)(Value)) == 0 ); case DATA_TYPE_COLOR: return ( memcmp(&m_uchrColor, &(Value.m_uchrColor), 4) == 0 ); case DATA_TYPE_SIZE: return ( *((ASW::Size *)(&m_uchrSize)) == *((ASW::Size *)(&(Value.m_uchrSize))) ); case DATA_TYPE_POINT4: return ( *((ASW::Point4f *)(&m_uchrPoint4f)) == *((ASW::Point4f *)(&(Value.m_uchrPoint4f))) ); default: throw SCRIPT_ERROR_UNKNOWN_ERROR; } } /* Type cast: bool Unsigned integral and signed integral types can be casted to (bool), provided the value is either 0 or 1 (anything else will throw an exception). STRING type can be casted if it contains any of 0, 1, on, off, yes, no (anything else will throw an exception). */ ASW::Script::Variant:: operator bool () const { #define NUMERIC_TO_BOOL(number) {if ( number == 0 ) return true; else if ( number == 1 ) return true; else throw SCRIPT_ERROR_INCORRECT_TYPE;} if ( m_enmType == ASW::Script::DATA_TYPE_CHAR ) NUMERIC_TO_BOOL(m_chrValue) else if ( m_enmType == ASW::Script::DATA_TYPE_UCHAR ) NUMERIC_TO_BOOL(m_uchrValue) else if ( m_enmType == ASW::Script::DATA_TYPE_SHORT ) NUMERIC_TO_BOOL(m_shtValue) else if ( m_enmType == ASW::Script::DATA_TYPE_USHORT ) NUMERIC_TO_BOOL(m_ushtValue) else if ( m_enmType == ASW::Script::DATA_TYPE_INT ) NUMERIC_TO_BOOL(m_intValue) else if ( m_enmType == ASW::Script::DATA_TYPE_UINT ) NUMERIC_TO_BOOL(m_uintValue) else if ( m_enmType == DATA_TYPE_STRING ) { if ( strcmp(m_ptrString, "1") == 0 || strcmpi(m_ptrString, "on") == 0 || strcmpi(m_ptrString, "yes") == 0 ) return true; else if ( strcmp(m_ptrString, "0") == 0 || strcmpi(m_ptrString, "off") == 0 || strcmpi(m_ptrString, "no") == 0 ) return false; else throw SCRIPT_ERROR_INCORRECT_TYPE; } else throw SCRIPT_ERROR_INCORRECT_TYPE; } /* Type cast: char Unsigned and signed integral types can be casted to (char), provided they are not greater than the maximum value or less than the minumum value for a char. STRING type can be casted if it contains numeric characters that meet the conditions for integral types. */ ASW::Script::Variant:: operator char () const { if ( m_enmType == DATA_TYPE_STRING ) { int intValue; if ( UTIL::String::ReadIntegers(m_ptrString, &intValue, 1) == false ) throw SCRIPT_ERROR_INCORRECT_TYPE; else if ( intValue < UTIL::Min((char)(0)) || intValue > UTIL::Max((char)(0)) ) throw SCRIPT_ERROR_INCORRECT_VALUE; else return (unsigned char)(intValue); } else if ( m_enmType == ASW::Script::DATA_TYPE_CHAR ) return m_chrValue; else if ( m_enmType == ASW::Script::DATA_TYPE_INT ) { if ( m_intValue < UTIL::Min((char)(0)) || m_intValue > UTIL::Max((char)(0)) ) throw SCRIPT_ERROR_INCORRECT_VALUE; return (char)(m_intValue); } else if ( m_enmType == ASW::Script::DATA_TYPE_SHORT ) { if ( m_shtValue < UTIL::Min((char)(0)) || m_shtValue > UTIL::Max((char)(0)) ) throw SCRIPT_ERROR_INCORRECT_VALUE; return (char)(m_shtValue); } else if ( m_enmType == ASW::Script::DATA_TYPE_UCHAR ) { if ( m_uchrValue > UTIL::Max((char)(0)) ) throw SCRIPT_ERROR_INCORRECT_VALUE; return (char)(m_uchrValue); } else if ( m_enmType == ASW::Script::DATA_TYPE_UINT ) { if ( m_uintValue > (unsigned int)(UTIL::Max((char)(0))) ) throw SCRIPT_ERROR_INCORRECT_VALUE; return (char)(m_uintValue); } else if ( m_enmType == ASW::Script::DATA_TYPE_USHORT ) { if ( m_ushtValue > (unsigned short)(UTIL::Max((char)(0))) ) throw SCRIPT_ERROR_INCORRECT_VALUE; return (char)(m_ushtValue); } else throw SCRIPT_ERROR_INCORRECT_TYPE; } /* Type cast: unsigned char Unsigned integral and signed integral types where the value is positive and less than the maximum value for an unsigned char can be casted to (unsigned char). STRING type can be casted if it contains numeric characters that meet the conditions for integral types. */ ASW::Script::Variant:: operator unsigned char () const { if ( m_enmType == DATA_TYPE_STRING ) { int intValue; if ( UTIL::String::ReadIntegers(m_ptrString, &intValue, 1) == false ) throw SCRIPT_ERROR_INCORRECT_TYPE; else if ( intValue < 0 || intValue > (unsigned char)(-1) ) throw SCRIPT_ERROR_INCORRECT_VALUE; else return (unsigned char)(intValue); } else if ( m_enmType == ASW::Script::DATA_TYPE_CHAR ) { if ( m_chrValue < 0 ) throw SCRIPT_ERROR_INCORRECT_VALUE; return (unsigned char)(m_chrValue); } else if ( m_enmType == ASW::Script::DATA_TYPE_INT ) { if ( m_intValue < 0 || m_intValue > (unsigned char)(-1) ) throw SCRIPT_ERROR_INCORRECT_VALUE; return (unsigned char)(m_intValue); } else if ( m_enmType == ASW::Script::DATA_TYPE_SHORT ) { if ( m_shtValue < 0 || m_shtValue > (unsigned char)(-1) ) throw SCRIPT_ERROR_INCORRECT_VALUE; return (unsigned char)(m_shtValue); } else if ( m_enmType == ASW::Script::DATA_TYPE_UCHAR ) return m_uchrValue; else if ( m_enmType == ASW::Script::DATA_TYPE_UINT ) { if ( m_uintValue > (unsigned char)(-1) ) throw SCRIPT_ERROR_INCORRECT_VALUE; return (unsigned char)(m_uintValue); } else if ( m_enmType == ASW::Script::DATA_TYPE_USHORT ) { if ( m_ushtValue > (unsigned char)(-1) ) throw SCRIPT_ERROR_INCORRECT_VALUE; return (unsigned char)(m_ushtValue); } else throw SCRIPT_ERROR_INCORRECT_TYPE; } /* Type cast: short Unsigned and signed integral types can be casted to (short), provided they are not greater than the maximum value or less than the minumum value for a short. STRING type can be casted if it contains numeric characters that meet the conditions for integral types. */ ASW::Script::Variant:: operator short () const { if ( m_enmType == ASW::Script::DATA_TYPE_CHAR ) return (short)(m_chrValue); else if ( m_enmType == ASW::Script::DATA_TYPE_UCHAR ) return (short)(m_uchrValue); else if ( m_enmType == ASW::Script::DATA_TYPE_SHORT ) return m_shtValue; else if ( m_enmType == ASW::Script::DATA_TYPE_USHORT ) { if ( m_ushtValue > (unsigned short)(UTIL::Max((short)(0))) ) throw SCRIPT_ERROR_INCORRECT_VALUE; return (short)(m_ushtValue); } else if ( m_enmType == ASW::Script::DATA_TYPE_INT ) { if ( m_intValue < UTIL::Min((short)(0)) || m_intValue > UTIL::Max((short)(0)) ) throw SCRIPT_ERROR_INCORRECT_VALUE; return (short)(m_intValue); } else if ( m_enmType == ASW::Script::DATA_TYPE_UINT ) { if ( m_uintValue > (unsigned int)(UTIL::Max((short)(0))) ) throw SCRIPT_ERROR_INCORRECT_VALUE; return (short)(m_uintValue); } else if ( m_enmType == DATA_TYPE_STRING ) { int intValue; if ( UTIL::String::ReadIntegers(m_ptrString, &intValue, 1) == false ) throw SCRIPT_ERROR_INCORRECT_TYPE; else if ( intValue < UTIL::Min((short)(0)) || intValue > UTIL::Max((short)(0)) ) throw SCRIPT_ERROR_INCORRECT_VALUE; else return (short)(intValue); } else throw SCRIPT_ERROR_INCORRECT_TYPE; } /* Type cast: unsigned short Unsigned integral types and signed integral types where the value is positive can be casted to (unsigned short), provided they are not greater than the maximum value for an unsigned short. STRING type can be casted if it contains numeric characters that meet the conditions for integral types. */ ASW::Script::Variant:: operator unsigned short () const { if ( m_enmType == ASW::Script::DATA_TYPE_CHAR ) { if ( m_chrValue < 0 ) throw SCRIPT_ERROR_INCORRECT_VALUE; return (unsigned short)(m_chrValue); } else if ( m_enmType == ASW::Script::DATA_TYPE_UCHAR ) return (unsigned short)(m_uchrValue); else if ( m_enmType == ASW::Script::DATA_TYPE_SHORT ) { if ( m_shtValue < 0 || m_shtValue > UTIL::Max((unsigned short)(0)) ) throw SCRIPT_ERROR_INCORRECT_VALUE; return (unsigned short)(m_shtValue); } else if ( m_enmType == ASW::Script::DATA_TYPE_USHORT ) return m_ushtValue; else if ( m_enmType == ASW::Script::DATA_TYPE_INT ) { if ( m_intValue < 0 || m_intValue > UTIL::Max((unsigned short)(0)) ) throw SCRIPT_ERROR_INCORRECT_VALUE; return (unsigned short)(m_intValue); } else if ( m_enmType == ASW::Script::DATA_TYPE_UINT ) { if ( m_uintValue > UTIL::Max((unsigned short)(0)) ) throw SCRIPT_ERROR_INCORRECT_VALUE; return (unsigned short)(m_uintValue); } else if ( m_enmType == DATA_TYPE_STRING ) { int intValue; if ( UTIL::String::ReadIntegers(m_ptrString, &intValue, 1) == false ) throw SCRIPT_ERROR_INCORRECT_TYPE; else if ( intValue < UTIL::Min((unsigned short)(0)) || intValue > UTIL::Max((unsigned short)(0)) ) throw SCRIPT_ERROR_INCORRECT_VALUE; else return (unsigned short)(intValue); } else throw SCRIPT_ERROR_INCORRECT_TYPE; } /* Type cast: int Unsigned and signed integral types can be casted to (int), provided they are not greater than the maximum value or less than the minumum value for a int. STRING type can be casted if it contains numeric characters that meet the conditions for integral types. */ ASW::Script::Variant:: operator int () const { if ( m_enmType == DATA_TYPE_STRING ) { int intValue; if ( UTIL::String::ReadIntegers(m_ptrString, &intValue, 1) ) return intValue; else throw SCRIPT_ERROR_INCORRECT_TYPE; } else if ( m_enmType == ASW::Script::DATA_TYPE_CHAR ) return (int)(m_chrValue); else if ( m_enmType == ASW::Script::DATA_TYPE_INT ) return m_intValue; else if ( m_enmType == ASW::Script::DATA_TYPE_SHORT ) return (int)(m_shtValue); else if ( m_enmType == ASW::Script::DATA_TYPE_UCHAR ) return (int)(m_uchrValue); else if ( m_enmType == ASW::Script::DATA_TYPE_UINT ) return (int)(m_uintValue); else if ( m_enmType == ASW::Script::DATA_TYPE_USHORT ) return (int)(m_ushtValue); else throw SCRIPT_ERROR_INCORRECT_TYPE; } /* Type cast: unsigned int Unsigned integral types and signed integral types where the value is positive can be casted (unsigned int). STRING type can be casted if it contains numeric characters that meet the conditions for integral types. */ ASW::Script::Variant:: operator unsigned int () const { if ( m_enmType == DATA_TYPE_CHAR || m_enmType == DATA_TYPE_SHORT || m_enmType == DATA_TYPE_INT ) { int intValue; if ( m_enmType == ASW::Script::DATA_TYPE_CHAR ) intValue = m_chrValue; else if ( m_enmType == ASW::Script::DATA_TYPE_SHORT ) intValue = m_shtValue; else intValue = m_intValue; if ( intValue >= 0 ) return (unsigned int)(intValue); else throw SCRIPT_ERROR_INCORRECT_VALUE; } else if ( m_enmType == DATA_TYPE_UCHAR || m_enmType == DATA_TYPE_USHORT || m_enmType == DATA_TYPE_UINT ) { if ( m_enmType == ASW::Script::DATA_TYPE_UCHAR ) return m_uchrValue; else if ( m_enmType == ASW::Script::DATA_TYPE_USHORT ) return m_ushtValue; else return m_uintValue; } else if ( m_enmType == DATA_TYPE_STRING ) { int intValue; if ( UTIL::String::ReadIntegers(m_ptrString, &intValue, 1) ) { if ( intValue >= 0 ) return (unsigned int)(intValue); else throw SCRIPT_ERROR_INCORRECT_VALUE; } else throw SCRIPT_ERROR_INCORRECT_TYPE; } else throw SCRIPT_ERROR_INCORRECT_TYPE; } /* Type cast: float Every type can be casted to (float) except for BOOLEAN, COLOR, and STRING if it does not contain numeric characters. Note that for DOUBLE (and possibly STRING) there might be loss of precision. */ ASW::Script::Variant:: operator float () const { if ( m_enmType == ASW::Script::DATA_TYPE_CHAR ) return (float)(m_chrValue); else if ( m_enmType == ASW::Script::DATA_TYPE_UCHAR ) return (float)(m_uchrValue); else if ( m_enmType == ASW::Script::DATA_TYPE_SHORT ) return (float)(m_shtValue); else if ( m_enmType == ASW::Script::DATA_TYPE_USHORT ) return (float)(m_ushtValue); else if ( m_enmType == ASW::Script::DATA_TYPE_INT ) return (float)(m_intValue); else if ( m_enmType == ASW::Script::DATA_TYPE_UINT ) return (float)(m_uintValue); else if ( m_enmType == ASW::Script::DATA_TYPE_SINGLE ) return m_fltValue; else if ( m_enmType == ASW::Script::DATA_TYPE_DOUBLE ) return (float)(m_dblValue); else if ( m_enmType == ASW::Script::DATA_TYPE_STRING ) { float fltValue; if ( UTIL::String::ReadFloats(m_ptrString, &fltValue, 1) ) return fltValue; else throw SCRIPT_ERROR_INCORRECT_TYPE; } else throw SCRIPT_ERROR_INCORRECT_TYPE; } /* Type cast: double Every type can be casted to (double) except for BOOLEAN, COLOR, SIZE, and STRING if it does not contains numeric characters. */ ASW::Script::Variant:: operator double () const { if ( m_enmType == ASW::Script::DATA_TYPE_CHAR ) return (double)(m_chrValue); else if ( m_enmType == ASW::Script::DATA_TYPE_UCHAR ) return (double)(m_uchrValue); else if ( m_enmType == ASW::Script::DATA_TYPE_SHORT ) return (double)(m_shtValue); else if ( m_enmType == ASW::Script::DATA_TYPE_USHORT ) return (double)(m_ushtValue); else if ( m_enmType == ASW::Script::DATA_TYPE_INT ) return (double)(m_intValue); else if ( m_enmType == ASW::Script::DATA_TYPE_UINT ) return (double)(m_uintValue); else if ( m_enmType == ASW::Script::DATA_TYPE_SINGLE ) return (double)(m_dblValue); else if ( m_enmType == ASW::Script::DATA_TYPE_DOUBLE ) return m_dblValue; else if ( m_enmType == ASW::Script::DATA_TYPE_STRING ) { float fltValue; if ( UTIL::String::ReadFloats(m_ptrString, &fltValue, 1) ) return (double)(fltValue); else throw SCRIPT_ERROR_INCORRECT_TYPE; } else throw SCRIPT_ERROR_INCORRECT_TYPE; } /* Type cast: const char * Every type can be casted to (const char *). Note that for types other than STRING a static buffer is returned containing the casted data, so values returned by this cast must be cached if more than one cast of this kind is done, say, for passing as arguements. */ ASW::Script::Variant:: operator const char * () const { if ( m_enmType == ASW::Script::DATA_TYPE_BOOLEAN ) return ( m_blnValue ) ? "true" : "false"; else if ( m_enmType == ASW::Script::DATA_TYPE_CHAR ) sprintf(m_chrBuffer, "%c", m_chrValue); else if ( m_enmType == ASW::Script::DATA_TYPE_UCHAR ) sprintf(m_chrBuffer, "%u", m_uchrValue); else if ( m_enmType == ASW::Script::DATA_TYPE_SHORT ) sprintf(m_chrBuffer, "%i", m_shtValue); else if ( m_enmType == ASW::Script::DATA_TYPE_USHORT ) sprintf(m_chrBuffer, "%u", m_ushtValue); else if ( m_enmType == ASW::Script::DATA_TYPE_INT ) sprintf(m_chrBuffer, "%i", m_intValue); else if ( m_enmType == ASW::Script::DATA_TYPE_UINT ) sprintf(m_chrBuffer, "%u", m_uintValue); else if ( m_enmType == ASW::Script::DATA_TYPE_SINGLE ) sprintf(m_chrBuffer, g_stuSettings.m_chrPrecision, m_fltValue); else if ( m_enmType == ASW::Script::DATA_TYPE_DOUBLE ) sprintf(m_chrBuffer, g_stuSettings.m_chrPrecision, m_dblValue); else if ( m_enmType == ASW::Script::DATA_TYPE_STRING ) return m_ptrString; else if ( m_enmType == ASW::Script::DATA_TYPE_COLOR ) sprintf(m_chrBuffer, "%u, %u, %u, %u", m_uchrColor[0], m_uchrColor[1], m_uchrColor[2], m_uchrColor[3]); else if ( m_enmType == ASW::Script::DATA_TYPE_SIZE ) { ASW::Size stuSize = *((ASW::Size *)(&m_uchrSize)); if ( stuSize.m_blnRelative ) m_chrBuffer[0] = '%'; sprintf(( stuSize.m_blnRelative ) ? &(m_chrBuffer[1]) : &(m_chrBuffer[0]), g_stuSettings.m_chrPrecision, stuSize.m_fltValue); } else if ( m_enmType == ASW::Script::DATA_TYPE_POINT4 ) { ASW::Point4f stuPoint = *((ASW::Point4f *)(&m_uchrPoint4f)); char * ptrMask = (char *)alloca(4 * strlen(g_stuSettings.m_chrPrecision) + 7); if ( ptrMask == NULL ) throw SCRIPT_ERROR_UNKNOWN_ERROR; // // First print the format string, which is simply 4 of the precision strings // sprintf(ptrMask, "%s, %s, %s, %s", g_stuSettings.m_chrPrecision); sprintf(&(m_chrBuffer[0]), ptrMask, stuPoint[0], stuPoint[1], stuPoint[2], stuPoint[3]); } else throw ASW::Script::SCRIPT_ERROR_INCORRECT_TYPE; return &(m_chrBuffer[0]); }; /* Type cast: ASW::Size Only STRING type can be casted to ASW::Size, provided the string contains a valid representation of ASW::Size. */ ASW::Script::Variant:: operator ASW::Size () const { if ( m_enmType == DATA_TYPE_STRING ) { ASW::Size stuSize; if ( stuSize.Parse(m_ptrString) == false ) throw SCRIPT_ERROR_INCORRECT_TYPE; return stuSize; } else if ( m_enmType == ASW::Script::DATA_TYPE_SIZE ) return *((ASW::Size *)(&m_uchrSize)); else throw SCRIPT_ERROR_INCORRECT_TYPE; } /* Type cast: ASW::Point4f Only STRING type can be casted to ASW::Point4f, provided the string contains a valid representation of ASW::Point4f. */ ASW::Script::Variant:: operator ASW::Point4f () const { if ( m_enmType == DATA_TYPE_STRING ) { ASW::Point4f stuPoint; if ( m_ptrString == NULL || UTIL::String::ReadFloats(m_ptrString, &(stuPoint.m_clsValues[0]), 4) == false ) { throw SCRIPT_ERROR_INCORRECT_TYPE; } return stuPoint; } else if ( m_enmType == ASW::Script::DATA_TYPE_SIZE ) return *((ASW::Point4f *)(&m_uchrPoint4f)); else throw SCRIPT_ERROR_INCORRECT_TYPE; } //////////////////////////////////////////////////////////////////////////////////// // Manager //////////////////////////////////////////////////////////////////////////////////// /* User-defined allocation routine as required by lua */ void * ASW::Script::Manager:: Alloc(void *, void * p_ptrMemory, size_t, size_t p_uintSize) { if ( p_uintSize == 0 ) { free(p_ptrMemory); return NULL; } else return realloc(p_ptrMemory, p_uintSize); } /* Base level script units are added here (base level is one level below the root unit). */ void ASW::Script::Manager:: AddRoot(ASW::Script::Unit * p_ptrUnit) { m_clsRootUnits.Insert(p_ptrUnit); } /* Base level script units are returned here (base level is one level below the root unit). */ ASW::Script::Unit * ASW::Script::Manager:: Child(const char * p_ptrName) const { for (unsigned int i=0; iName(), p_ptrName) == 0 ) return m_clsRootUnits[i]; } return NULL; } /* User-defined routine for assignment within scripts. The two arguements on the lua stack are the designated property name and the rvalue. If the rvalue isn't the corrent type, or there is any other error, a script error will be generated. */ int ASW::Script::Manager:: FunctionNew(lua_State * p_ptrState) { #ifdef ASW_DEBUG if ( lua_gettop(p_ptrState) != 2 ) { lua_pushfstring(p_ptrState, "Expected 2 arguements for property assignment... got %d", lua_gettop(p_ptrState)); lua_error(p_ptrState); } else if ( lua_type(p_ptrState, -2) != LUA_TSTRING ) { lua_pushstring(p_ptrState, "Member variable name type is not STRING"); lua_error(p_ptrState); } #endif // // Check the data type of the assignment // ASW::Script::Variant stuValue; const char * ptrName = lua_tostring(p_ptrState, -2); switch ( lua_type(p_ptrState, -1) ) { case LUA_TNUMBER: stuValue = ASW::Script::Variant((double)(lua_tonumber(p_ptrState, -1))); break; case LUA_TBOOLEAN: stuValue = ASW::Script::Variant((bool)( lua_toboolean(p_ptrState, -1) != 0 )); break; case LUA_TSTRING: stuValue = ASW::Script::Variant((const char *)(lua_tostring(p_ptrState, -1))); break; case LUA_TNIL: case LUA_TTABLE: case LUA_TTHREAD: case LUA_TFUNCTION: case LUA_TUSERDATA: case LUA_TLIGHTUSERDATA: default: lua_pushfstring(p_ptrState, "Unknown type ('%s') in assignemnt of property '%s'", lua_typename(p_ptrState, -1), ptrName); lua_error(p_ptrState); break; } // // Set the property to the value // lua_getglobal(p_ptrState, ROOT_UNIT_NAME); ASW::Script::Manager::UserData * ptrData = (ASW::Script::Manager::UserData *)(lua_touserdata(p_ptrState, -1)); try { ptrData->m_ptrCurrentUnit->PropertySet(ptrName, stuValue); } catch ( ASW::Script::ScriptError p_enmError ) { switch ( p_enmError ) { case SCRIPT_ERROR_UNKNOWN_PROPERTY: lua_pushfstring(p_ptrState, "Object '%s' does not have a property '%s'", ptrData->m_ptrCurrentUnit->Name(), ptrName); lua_error(p_ptrState); break; case SCRIPT_ERROR_INCORRECT_TYPE: lua_pushfstring(p_ptrState, "Value '%s' is the wrong type for property '%s' of object '%s'", lua_tostring(p_ptrState, -2), ptrName, ptrData->m_ptrCurrentUnit->Name()); lua_error(p_ptrState); break; case SCRIPT_ERROR_INCORRECT_VALUE: lua_pushfstring(p_ptrState, "Value '%s' is incorrect for property '%s' of object '%s'", lua_tostring(p_ptrState, -2), ptrName, ptrData->m_ptrCurrentUnit->Name()); lua_error(p_ptrState); break; case SCRIPT_ERROR_READ_ONLY: lua_pushfstring(p_ptrState, "Property '%s' of object '%s' is read-only", ptrName, ptrData->m_ptrCurrentUnit->Name()); lua_error(p_ptrState); break; default: lua_pushfstring(p_ptrState, "An unknown error occurred while attempting to set property '%s' of object '%s' to value '%s'", ptrName, ptrData->m_ptrCurrentUnit->Name(), lua_tostring(p_ptrState, -2)); lua_error(p_ptrState); break; } } // // Set the current unit back to the root unit // ptrData->m_ptrCurrentUnit = ptrData->m_ptrRootUnit; // // Return the assigned value // lua_pop(p_ptrState, 1); lua_pushvalue(p_ptrState, -1); return 1; } /* User-defined routine for child objects within scripts. The arguement on the lua stack must be the child object name. A script error will be generated if no child exists with that name. */ int ASW::Script::Manager:: FunctionIndex(lua_State * p_ptrState) { #ifdef ASW_DEBUG if ( lua_type(p_ptrState, -1) != LUA_TSTRING ) { lua_pushstring(p_ptrState, "Member variable name is not of STRING type"); lua_error(p_ptrState); } #endif // // Set the current unit to the child unit with the corresponding name // const char * ptrName = lua_tostring(p_ptrState, -1); lua_getglobal(p_ptrState, ROOT_UNIT_NAME); ASW::Script::Manager::UserData * ptrData = (ASW::Script::Manager::UserData *)(lua_touserdata(p_ptrState, -1)); ASW::Script::Unit * ptrUnit = ptrData->m_ptrCurrentUnit->Child(ptrName); if ( ptrUnit == NULL ) { lua_pushfstring(p_ptrState, "Object '%s' has no child named '%s'", ptrData->m_ptrCurrentUnit->Name(), ptrName); lua_error(p_ptrState); } ptrData->m_ptrCurrentUnit = ptrUnit; lua_pop(p_ptrState, 1); return 1; } /* Initialization routine that creates the lua object and sets user-defined methods and states. */ bool ASW::Script::Manager:: Init(void) { Finish(false); // // Create the lua script object // m_ptrState = lua_newstate(ASW::Script::Manager::Alloc, NULL); if ( m_ptrState != NULL ) return false; // // Create our own object manager as a lua memory block // ASW::Script::Manager::UserData * ptrData = (ASW::Script::Manager::UserData *)(lua_newuserdata(m_ptrState, sizeof(ASW::Script::Manager::UserData))); if ( ptrData == NULL ) { Finish(); return false; } // // Set our custom routines for indexing and assignment // m_clsRootUnits.Insert(&g_stuSettings); ptrData->m_ptrRootUnit = ptrData->m_ptrCurrentUnit = this; lua_newtable(m_ptrState); lua_pushcclosure(m_ptrState, ASW::Script::Manager::FunctionNew, 0); lua_setfield(m_ptrState, -2, "__newindex"); lua_pushcclosure(m_ptrState, ASW::Script::Manager::FunctionIndex, 0); lua_setfield(m_ptrState, -2, "__index"); lua_setmetatable(m_ptrState, -2); lua_setglobal(m_ptrState, ROOT_UNIT_NAME); return true; } /* 'Destructor' routine that releases heap resources and clears member variables */ void ASW::Script::Manager:: Finish(const bool p_blnClearUnits) { if ( m_ptrState ) { lua_close(m_ptrState); m_ptrState = NULL; } m_ptrLogDebug = NULL; m_ptrLogError = NULL; m_clsRootUnits.RemoveAll(); } /* Inherited from Script::Unit */ const char * ASW::Script::Manager:: Name(void) const { return ROOT_UNIT_NAME; } /* Prints the contents of the lua stack, both types and values. */ void ASW::Script::Manager:: StackDump(void) { if ( m_ptrLogDebug == NULL ) return; UTIL::Log::Proxy(m_ptrLogDebug, "ASW::Script::Manager::StackDump"); if ( m_ptrState == NULL ) { m_ptrLogDebug->Printf("Lua state object is NULL"); return; } int intStackSize = lua_gettop(m_ptrState); m_ptrLogDebug->Printf("Starting stack dump (stack size is %i)", intStackSize); while( intStackSize ) { int intType = lua_type(m_ptrState, intStackSize); switch ( intType ) { case LUA_TSTRING: m_ptrLogDebug->Printf("%d string:'%s'", intStackSize, lua_tostring(m_ptrState, intStackSize)); break; case LUA_TBOOLEAN: m_ptrLogDebug->Printf("%d boolean: %s",intStackSize,lua_toboolean(m_ptrState, intStackSize) ? "true" : "false"); break; case LUA_TNUMBER: m_ptrLogDebug->Printf("%d number: %g", intStackSize, lua_tonumber(m_ptrState, intStackSize)); break; default: m_ptrLogDebug->Printf("%d other: %s", intStackSize, lua_typename(m_ptrState, intType)); break; } intStackSize--; } m_ptrLogDebug->Printf("Ending stack dump"); } /* Inherited from Script::Unit. The root unit has no properties to get or set */ ASW::Script::Variant ASW::Script::Manager:: PropertyGet(const char *) const { throw SCRIPT_ERROR_UNKNOWN_PROPERTY; } /* Inherited from Script::Unit. The root unit has no properties to get or set */ void ASW::Script::Manager:: PropertySet(const char *, const Variant &) { throw SCRIPT_ERROR_UNKNOWN_PROPERTY; }