void qspCallSaveGame(QSP_CHAR *file) { /* Здесь позволяем пользователю выбрать файл */ /* для сохранения состояния игры и сохраняем */ /* в нем текущее состояние */ QSPCallState state; AS3_Val args; char *strUTF8; if (qspCallBacks[QSP_CALL_SAVEGAMESTATUS].IsSet) { qspSaveCallState(&state, QSP_FALSE, QSP_TRUE); if (file) { strUTF8 = qspW2C(file); args = AS3_Array("StrType", strUTF8); free(strUTF8); } else args = AS3_Array("StrType", 0); AS3_Call(qspCallBacks[QSP_CALL_SAVEGAMESTATUS].FuncVal, qspCallBacks[QSP_CALL_SAVEGAMESTATUS].ThisVal, args); AS3_Release(args); flyield(); qspRestoreCallState(&state); } }
QSP_CHAR *qspCallInputBox(QSP_CHAR *text) { /* Здесь вводим текст */ QSPCallState state; QSP_CHAR *buffer; AS3_Val args; char *strUTF8; char *resText; int maxLen = 511; if (qspCallBacks[QSP_CALL_INPUTBOX].IsSet) { qspSaveCallState(&state, QSP_TRUE, QSP_FALSE); if (text) { strUTF8 = qspW2C(text); args = AS3_Array("StrType", strUTF8); free(strUTF8); } else args = AS3_Array("StrType", 0); AS3_Call(qspCallBacks[QSP_CALL_INPUTBOX].FuncVal, qspCallBacks[QSP_CALL_INPUTBOX].ThisVal, args); AS3_Release(args); flyield(); resText = AS3_StringValue(result); AS3_Release(result); buffer = qspC2W(resText); free(resText); qspRestoreCallState(&state); } else buffer = qspGetNewText(QSP_FMT(""), 0); return buffer; }
QSP_BOOL qspCallIsPlayingFile(QSP_CHAR *file) { /* Здесь проверяем, проигрывается ли файл */ QSPCallState state; QSP_BOOL isPlaying; AS3_Val args; char *strUTF8; if (qspCallBacks[QSP_CALL_ISPLAYINGFILE].IsSet) { qspSaveCallState(&state, QSP_TRUE, QSP_FALSE); if (file) { strUTF8 = qspW2C(file); args = AS3_Array("StrType", strUTF8); free(strUTF8); } else args = AS3_Array("StrType", 0); AS3_Call(qspCallBacks[QSP_CALL_ISPLAYINGFILE].FuncVal, qspCallBacks[QSP_CALL_ISPLAYINGFILE].ThisVal, args); AS3_Release(args); flyield(); isPlaying = (QSP_BOOL)AS3_IntValue(result); AS3_Release(result); qspRestoreCallState(&state); return isPlaying; } return QSP_FALSE; }
/* * Create an ActionScript value from the lua stack starting * at index start and ending at index end. If collapse_array == 1, * an empty return will be transformed into AS3_Undefined() and a * return of length 1 will just return the specific value. * Otherwise an array is returned. */ AS3_Val create_as3_value_from_lua_stack( lua_State * L, int start, int end, BOOL collapse_array ) { /* WARNING: Panic alert! Use L*_FN checkers here! */ LCALL(L, stack); AS3_Val ret; SPAM(("create_as3_value_from_lua_stack(): begin")); if (collapse_array == TRUE && start > end) { ret = AS3_Null(); } else if (collapse_array == TRUE && start == end) { ret = get_as3_value_from_lua_stack(L, start); } else { int i; ret = AS3_Array(""); for (i = start; i <= end; ++i) { AS3_Val value; AS3_Val r; /*SPAM(("create_as3_value_from_lua_stack() + 1 begin"));*/ value = get_as3_value_from_lua_stack(L, i); r = AS3_CallTS("push", ret, "AS3ValType", value); SAFE_RELEASE(r); /* Ignoring result */ SAFE_RELEASE(value); /*SPAM(("create_as3_value_from_lua_stack() + 1 end"));*/ } } #ifdef DO_SPAM SPAM(("create_as3_value_from_lua_stack(): end")); AS3_Trace( AS3_Call( getQualifiedClassName_method, NULL, AS3_Array("AS3ValType", ret) ) ); #endif /* DO_SPAM */ LCHECK_FN(L, stack, 0, fatal_error); return ret; }
/* * Given an ActionScript object, push it onto the Lua stack as a Lua native * type if a primitive class (String, Number, Boolean, int, null). * If object is not convertible to native Lua value, do not push anything * (and return 0). * * WARNING: It important that this function does not touch * non-primitive values (like Arrays). If this will be changed, * optional primitive autoconversion logic will break. */ int push_as3_to_lua_stack_if_convertible(lua_State * L, AS3_Val val) { LCALL(L, stack); #ifdef DO_SPAM SPAM(("push_as3_to_lua_stack_if_convertible(): begin: value, type")); AS3_Trace(val); AS3_Trace( AS3_Call( getQualifiedClassName_method, NULL, AS3_Array("AS3ValType", val) ) ); #endif /* DO_SPAM */ if (AS3_InstanceOf(val, Number_class)) { lua_pushnumber(L, AS3_NumberValue(val)); } else if (AS3_InstanceOf(val, int_class)) { lua_pushinteger(L, AS3_IntValue(val)); } else if (AS3_InstanceOf(val, String_class)) { size_t length = 0; AS3_Malloced_Str str = get_string_bytes(val, &length); lua_pushlstring(L, str, length); free(str); } else if (AS3_InstanceOf(val, Boolean_class)) { lua_pushboolean(L, AS3_IntValue(val)); } else if (val == AS3_Undefined()) { lua_pushnil(L); } else if (is_null(val)) { lua_pushnil(L); } else { SPAM(("push_as3_to_lua_stack_if_convertible(): not convertible")); LRETURN(L, stack, 0); } SPAM(("push_as3_to_lua_stack_if_convertible(): end")); LRETURN(L, stack, 1); }
void qspCallSleep(int msecs) { /* Здесь ожидаем заданное количество миллисекунд */ QSPCallState state; AS3_Val args; if (qspCallBacks[QSP_CALL_SLEEP].IsSet) { qspSaveCallState(&state, QSP_TRUE, QSP_FALSE); args = AS3_Array("IntType", msecs); AS3_Call(qspCallBacks[QSP_CALL_SLEEP].FuncVal, qspCallBacks[QSP_CALL_SLEEP].ThisVal, args); AS3_Release(args); flyield(); qspRestoreCallState(&state); } }
void qspCallDeleteMenu() { /* Здесь удаляем текущее меню */ QSPCallState state; AS3_Val args; if (qspCallBacks[QSP_CALL_DELETEMENU].IsSet) { qspSaveCallState(&state, QSP_TRUE, QSP_FALSE); args = AS3_Array(""); AS3_Call(qspCallBacks[QSP_CALL_DELETEMENU].FuncVal, qspCallBacks[QSP_CALL_DELETEMENU].ThisVal, args); AS3_Release(args); flyield(); qspRestoreCallState(&state); } }
void qspCallRefreshInt(QSP_BOOL isRedraw) { /* Здесь выполняем обновление интерфейса */ QSPCallState state; AS3_Val args; if (qspCallBacks[QSP_CALL_REFRESHINT].IsSet) { qspSaveCallState(&state, QSP_TRUE, QSP_FALSE); args = AS3_Array("IntType", isRedraw); AS3_Call(qspCallBacks[QSP_CALL_REFRESHINT].FuncVal, qspCallBacks[QSP_CALL_REFRESHINT].ThisVal, args); AS3_Release(args); flyield(); qspRestoreCallState(&state); } }
void qspCallSetTimer(int msecs) { /* Здесь устанавливаем интервал таймера */ QSPCallState state; AS3_Val args; if (qspCallBacks[QSP_CALL_SETTIMER].IsSet) { qspSaveCallState(&state, QSP_TRUE, QSP_FALSE); args = AS3_Array("IntType", msecs); AS3_Call(qspCallBacks[QSP_CALL_SETTIMER].FuncVal, qspCallBacks[QSP_CALL_SETTIMER].ThisVal, args); AS3_Release(args); flyield(); qspRestoreCallState(&state); } }
/* TODO: Ugly workaround. Remove. See http://tinyurl.com/a9djb2 */ BOOL is_null(AS3_Val val) { BOOL result = FALSE; AS3_Val argsVal = AS3_Array("AS3ValType", val); AS3_Val classNameVal = AS3_Call(getQualifiedClassName_method, NULL, argsVal); AS3_Malloced_Str className = AS3_StringValue(classNameVal); AS3_Release(argsVal); AS3_Release(classNameVal); result = (strncmp(className, "null", 4) == 0); free(className); return result; }
void qspCallShowWindow(int type, QSP_BOOL isShow) { /* Здесь показываем или скрываем окно */ QSPCallState state; AS3_Val args; if (qspCallBacks[QSP_CALL_SHOWWINDOW].IsSet) { qspSaveCallState(&state, QSP_TRUE, QSP_FALSE); args = AS3_Array("IntType, IntType", type, isShow); AS3_Call(qspCallBacks[QSP_CALL_SHOWWINDOW].FuncVal, qspCallBacks[QSP_CALL_SHOWWINDOW].ThisVal, args); AS3_Release(args); flyield(); qspRestoreCallState(&state); } }
void qspCallShowMenu() { /* Здесь показываем меню */ QSPCallState state; AS3_Val args; if (qspCallBacks[QSP_CALL_SHOWMENU].IsSet) { qspSaveCallState(&state, QSP_FALSE, QSP_TRUE); args = AS3_Array(""); AS3_Call(qspCallBacks[QSP_CALL_SHOWMENU].FuncVal, qspCallBacks[QSP_CALL_SHOWMENU].ThisVal, args); AS3_Release(args); flyield(); qspRestoreCallState(&state); } }
int qspCallShowMenu() { /* «десь показываем меню */ QSPCallState state; int index; AS3_Val args; if (qspCallBacks[QSP_CALL_SHOWMENU].IsSet) { qspSaveCallState(&state, QSP_FALSE, QSP_TRUE); args = AS3_Array(""); AS3_Call(qspCallBacks[QSP_CALL_SHOWMENU].FuncVal, qspCallBacks[QSP_CALL_SHOWMENU].ThisVal, args); AS3_Release(args); flyield(); index = AS3_IntValue(result); AS3_Release(result); qspRestoreCallState(&state); return index; } return -1; }
int qspCallGetMSCount() { /* Здесь получаем количество миллисекунд, прошедших с момента последнего вызова функции */ QSPCallState state; int count; AS3_Val args; if (qspCallBacks[QSP_CALL_GETMSCOUNT].IsSet) { qspSaveCallState(&state, QSP_TRUE, QSP_FALSE); args = AS3_Array(""); AS3_Call(qspCallBacks[QSP_CALL_GETMSCOUNT].FuncVal, qspCallBacks[QSP_CALL_GETMSCOUNT].ThisVal, args); AS3_Release(args); flyield(); count = AS3_IntValue(result); AS3_Release(result); qspRestoreCallState(&state); return count; } return 0; }
void qspCallAddMenuItem(QSP_CHAR *name, QSP_CHAR *imgPath) { /* Здесь добавляем пункт меню */ QSPCallState state; AS3_Val args; char *nameUTF8; char *imgUTF8; if (qspCallBacks[QSP_CALL_ADDMENUITEM].IsSet) { qspSaveCallState(&state, QSP_TRUE, QSP_FALSE); nameUTF8 = (name ? qspW2C(name) : 0); imgUTF8 = (imgPath ? qspW2C(imgPath) : 0); args = AS3_Array("StrType, StrType", nameUTF8, imgUTF8); if (nameUTF8) free(nameUTF8); if (imgUTF8) free(imgUTF8); AS3_Call(qspCallBacks[QSP_CALL_ADDMENUITEM].FuncVal, qspCallBacks[QSP_CALL_ADDMENUITEM].ThisVal, args); AS3_Release(args); flyield(); qspRestoreCallState(&state); } }
void qspCallDebug(QSP_CHAR *str) { /* Здесь передаем управление отладчику */ QSPCallState state; char *strUTF8; AS3_Val args; if (qspCallBacks[QSP_CALL_DEBUG].IsSet) { qspSaveCallState(&state, QSP_FALSE, QSP_FALSE); if (str) { strUTF8 = qspW2C(str); args = AS3_Array("StrType", strUTF8); free(strUTF8); } else args = AS3_Array("StrType", 0); AS3_Call(qspCallBacks[QSP_CALL_DEBUG].FuncVal, qspCallBacks[QSP_CALL_DEBUG].ThisVal, args); AS3_Release(args); flyield(); qspRestoreCallState(&state); } }
void qspCallSetInputStrText(QSP_CHAR *text) { /* Здесь устанавливаем текст строки ввода */ QSPCallState state; AS3_Val args; char *textUTF8; if (qspCallBacks[QSP_CALL_SETINPUTSTRTEXT].IsSet) { qspSaveCallState(&state, QSP_TRUE, QSP_FALSE); if (text) { textUTF8 = qspW2C(text); args = AS3_Array("StrType", textUTF8); free(textUTF8); } else args = AS3_Array("StrType", 0); AS3_Call(qspCallBacks[QSP_CALL_SETINPUTSTRTEXT].FuncVal, qspCallBacks[QSP_CALL_SETINPUTSTRTEXT].ThisVal, args); AS3_Release(args); flyield(); qspRestoreCallState(&state); } }
void qspCallCloseFile(QSP_CHAR *file) { /* Здесь выполняем закрытие файла */ QSPCallState state; AS3_Val args; char *strUTF8; if (qspCallBacks[QSP_CALL_CLOSEFILE].IsSet) { qspSaveCallState(&state, QSP_TRUE, QSP_FALSE); if (file) { strUTF8 = qspW2C(file); args = AS3_Array("StrType", strUTF8); free(strUTF8); } else args = AS3_Array("StrType", 0); AS3_Call(qspCallBacks[QSP_CALL_CLOSEFILE].FuncVal, qspCallBacks[QSP_CALL_CLOSEFILE].ThisVal, args); AS3_Release(args); flyield(); qspRestoreCallState(&state); } }
void qspCallSystem(QSP_CHAR *cmd) { /* Здесь выполняем системный вызов */ QSPCallState state; AS3_Val args; char *strUTF8; if (qspCallBacks[QSP_CALL_SYSTEM].IsSet) { qspSaveCallState(&state, QSP_FALSE, QSP_FALSE); if (cmd) { strUTF8 = qspW2C(cmd); args = AS3_Array("StrType", strUTF8); free(strUTF8); } else args = AS3_Array("StrType", 0); AS3_Call(qspCallBacks[QSP_CALL_SYSTEM].FuncVal, qspCallBacks[QSP_CALL_SYSTEM].ThisVal, args); AS3_Release(args); flyield(); qspRestoreCallState(&state); } }
void qspCallPlayFile(QSP_CHAR *file, int volume) { /* Здесь начинаем воспроизведение файла с заданной громкостью */ QSPCallState state; AS3_Val args; char *strUTF8; if (qspCallBacks[QSP_CALL_PLAYFILE].IsSet) { qspSaveCallState(&state, QSP_TRUE, QSP_FALSE); if (file) { strUTF8 = qspW2C(file); args = AS3_Array("StrType, IntType", strUTF8, volume); free(strUTF8); } else args = AS3_Array("StrType, IntType", 0, volume); AS3_Call(qspCallBacks[QSP_CALL_PLAYFILE].FuncVal, qspCallBacks[QSP_CALL_PLAYFILE].ThisVal, args); AS3_Release(args); flyield(); qspRestoreCallState(&state); } }
void qspCallShowMessage(QSP_CHAR *text) { /* Здесь показываем сообщение */ QSPCallState state; AS3_Val args; char *strUTF8; if (qspCallBacks[QSP_CALL_SHOWMSGSTR].IsSet) { qspSaveCallState(&state, QSP_TRUE, QSP_FALSE); if (text) { strUTF8 = qspW2C(text); args = AS3_Array("StrType", strUTF8); free(strUTF8); } else args = AS3_Array("StrType", 0); AS3_Call(qspCallBacks[QSP_CALL_SHOWMSGSTR].FuncVal, qspCallBacks[QSP_CALL_SHOWMSGSTR].ThisVal, args); AS3_Release(args); flyield(); qspRestoreCallState(&state); } }
void qspCallShowPicture(QSP_CHAR *file) { /* Здесь показываем изображение */ QSPCallState state; AS3_Val args; char *strUTF8; if (qspCallBacks[QSP_CALL_SHOWIMAGE].IsSet) { qspSaveCallState(&state, QSP_TRUE, QSP_FALSE); if (file) { strUTF8 = qspW2C(file); args = AS3_Array("StrType", strUTF8); free(strUTF8); } else args = AS3_Array("StrType", 0); AS3_Call(qspCallBacks[QSP_CALL_SHOWIMAGE].FuncVal, qspCallBacks[QSP_CALL_SHOWIMAGE].ThisVal, args); AS3_Release(args); flyield(); qspRestoreCallState(&state); } }
void qspCallOpenGame(QSP_CHAR *file) { /* Здесь позволяем пользователю выбрать файл */ /* состояния игры для загрузки и загружаем его */ QSPCallState state; AS3_Val args; char *strUTF8; if (qspCallBacks[QSP_CALL_OPENGAMESTATUS].IsSet) { qspSaveCallState(&state, QSP_FALSE, QSP_TRUE); if (file) { strUTF8 = qspW2C(file); args = AS3_Array("StrType", strUTF8); free(strUTF8); } else args = AS3_Array("StrType", 0); AS3_Call(qspCallBacks[QSP_CALL_OPENGAMESTATUS].FuncVal, qspCallBacks[QSP_CALL_OPENGAMESTATUS].ThisVal, args); AS3_Release(args); flyield(); qspRestoreCallState(&state); } }
/* * Take the Lua stack item at index i and convert it into an * ActionScript value. */ AS3_Val get_as3_value_from_lua_stack_type(lua_State * L, int i, int type) { /* WARNING: Panic alert! Use L*_FN checkers here! */ LCALL(L, stack); AS3_Val value; switch (type) { case LUA_TSTRING: /* strings */ { size_t length = 0; const char * str = lua_tolstring(L, i, &length); if (str == NULL) /* NOTE: This is unreachable. Assert instead */ { length = 6; str = "(null)"; } /* NOTE: Alchemy .5a truncates embedded zeroes in string * regardless to the passed length */ value = AS3_StringN(str, length); } break; case LUA_TBOOLEAN: /* booleans */ value = lua_toboolean(L, i) ? AS3_True() : AS3_False(); break; case LUA_TNUMBER: /* numbers */ value = AS3_Number(lua_tonumber(L, i)); break; case LUA_TNONE: /* fall through */ case LUA_TNIL: /* nil */ value = AS3_Null(); break; case LUA_TUSERDATA: /* userdata */ { void * userdata = lua_touserdata(L, i); lua_getfield(L, LUA_REGISTRYINDEX, AS3LUA_METATABLE); if (userdata == NULL || !lua_getmetatable(L, i)) { lua_pop(L, 1); /* Pop AS3LUA_METATABLE */ value = as3_value_from_foreign_userdata(L, i); } else if (!lua_rawequal(L, -2, -1)) { lua_pop(L, 2); /* Pop AS3LUA_METATABLE and userdata metatable */ value = as3_value_from_foreign_userdata(L, i); } else { lua_pop(L, 2); /* Pop AS3LUA_METATABLE and userdata metatable */ AS3LuaUserData * userdata = (AS3LuaUserData *)lua_touserdata(L, i); value = userdata->value; /* * We just created one more reference to the AS3 value, * as it still lives inside Lua. * (And will probably be collected by GC.) */ AS3_Acquire(value); } } break; case LUA_TFUNCTION: /* function */ value = setup_callback(L, i); break; case LUA_TLIGHTUSERDATA: /* TODO: blackbox this type */ case LUA_TTABLE: /* TODO: deal with this type */ case LUA_TTHREAD: /* TODO: blackbox this type */ value = AS3_String(lua_typename(L, type)); break; default: /* unreachable */ fatal_error("unknown Lua type"); break; } #ifdef DO_SPAM SPAM(("get_as3_value_from_lua_stack(): end")); AS3_Trace( AS3_Call( getQualifiedClassName_method, NULL, AS3_Array("AS3ValType", value) ) ); #endif /* DO_SPAM */ LCHECK_FN(L, stack, 0, fatal_error); return value; }
void errorToFlash(const char* message) { AS3_Val trace = AS3_NSGetS(NULL, "trace"); AS3_Val params = AS3_Array("StrType", message); AS3_Release(AS3_Call(trace, AS3_Undefined(), params)); }
/* * Function used as a callback for all Lua functions passed through * get_as3_value_from_lua_stack() */ AS3_Val as3_lua_callback(void * data, AS3_Val args) { /* WARNING: Panic alert! Use L*_FN checkers here! */ SPAM(("as3_lua_callback(): begin")); AS3_Val res; LuaFunctionCallbackData * func_data = (LuaFunctionCallbackData *) data; int nargs = 0; int status = 0; int results_base = 0; lua_State * L = func_data->L; if (L == NULL) { /* TODO: Should we crash here? fatal_error("state expired"); / * Does not return * / */ sztrace("as3_lua_callback: state expired"); return AS3_Undefined(); } { /* A new scope for LCALL to work (C89 conformance) */ LCALL(L, stack); /* TODO: Cache that with lua_ref, it is faster */ lua_getfield(L, LUA_REGISTRYINDEX, AS3LUA_CALLBACKS); /* TODO: Assert we have a table here */ lua_rawgeti(L, -1, func_data->ref); /* push stored function */ if (lua_istable(L, -1) == 0) /* Probably nil */ { lua_pop(L, 1); /* Pop bad callback table */ LCHECK_FN(L, stack, 0, fatal_error); fatal_error("function callback not found"); /* Does not return */ } lua_rawgeti(L, -1, AS3LUA_CBFNINDEX); /* push stored callback function */ #ifdef DO_SPAM { SPAM(("as3_lua_callback(): AS3 arguments")); AS3_Val a = AS3_CallS("join", args, AS3_Undefined()); AS3_Trace(a); SAFE_RELEASE(a); } #endif /* DO_SPAM */ /* TODO: Assert we have Lua function (or other callable object) on the top of the stack */ LCHECK_FN(L, stack, 2 + 1, fatal_error); nargs = push_as3_array_to_lua_stack(L, args); /* push arguments */ #ifdef DO_SPAM /* TODO: Remove */ lua_pushcfunction(L, as3_trace); dump_lua_stack(L, LBASE(L, stack) + 2 + 1); lua_pushliteral(L, "ARGUMENTS"); lua_pushnumber(L, nargs); lua_call(L, 3, 0); #endif /* DO_SPAM */ LCHECK_FN(L, stack, 2 + 1 + nargs, fatal_error); results_base = LBASE(L, stack) + 2; status = do_pcall_with_traceback(L, nargs, LUA_MULTRET); if (status != 0) { const char * msg = NULL; LCHECK_FN(L, stack, 2 + 1, fatal_error); /* Tables and error message */ lua_remove(L, -2); /* Remove AS3LUA_CALLBACKS table */ lua_remove(L, -2); /* Remove holder table */ LCHECK_FN(L, stack, 1, fatal_error); /* Only error message */ /* Error message is on stack */ /* NOTE: It is not necessary string! If we want to preserve its type, see lua_DoString. */ if (lua_tostring(L, -1) == NULL) { lua_pop(L, 1); lua_pushliteral(L, "(non-string)"); } LCHECK_FN(L, stack, 1, fatal_error); lua_pushliteral(L, "Error in Lua callback:\n"); lua_insert(L, -2); LCHECK_FN(L, stack, 2, fatal_error); lua_concat(L, 2); LCHECK_FN(L, stack, 1, fatal_error); sztrace((char *)lua_tostring(L, -1)); /* TODO: ?! */ /* lua_error(L); */ msg = lua_tostring(L, -1); lua_pop(L, 1); /* fatal_error(msg); / * Does not return * / */ } /* Process results */ #ifdef DO_SPAM /* TODO: Remove */ /* lua_pushcfunction(L, as3_trace); lua_pushliteral(L, "STACK"); dump_lua_stack(L, results_base); lua_call(L, 2, 0); */ #endif /* DO_SPAM */ res = create_as3_value_from_lua_stack(L, results_base + 1, LTOP(L, stack), TRUE); #ifdef DO_SPAM SPAM(("as3_lua_callback() result type")); AS3_Trace(AS3_Call(getQualifiedClassName_method, NULL, AS3_Array("AS3ValType", res))); #endif /* DO_SPAM */ lua_settop(L, LBASE(L, stack)); /* Cleanup results and two holder tables */ SPAM(("as3_lua_callback(): end")); return res; } /* Unreachable */ }