void CLuaRules::Cob2Lua(const LuaHashString& name, const CUnit* unit, int& argsCount, int args[MAX_LUA_COB_ARGS]) { static int callDepth = 0; if (callDepth >= 16) { LOG_L(L_WARNING, "CLuaRules::Cob2Lua() call overflow: %s", name.GetString().c_str()); args[0] = 0; // failure return; } LUA_CALL_IN_CHECK(L); const int top = lua_gettop(L); if (!lua_checkstack(L, 1 + 3 + argsCount)) { LOG_L(L_WARNING, "CLuaRules::Cob2Lua() lua_checkstack() error: %s", name.GetString().c_str()); args[0] = 0; // failure lua_settop(L, top); return; } if (!name.GetGlobalFunc(L)) { LOG_L(L_WARNING, "CLuaRules::Cob2Lua() missing function: %s", name.GetString().c_str()); args[0] = 0; // failure lua_settop(L, top); return; } lua_pushnumber(L, unit->id); lua_pushnumber(L, unit->unitDef->id); lua_pushnumber(L, unit->team); for (int a = 0; a < argsCount; a++) { lua_pushnumber(L, args[a]); } // call the routine callDepth++; const int* oldArgs = currentCobArgs; currentCobArgs = args; const bool error = !RunCallIn(name, 3 + argsCount, LUA_MULTRET); currentCobArgs = oldArgs; callDepth--; // bail on error if (error) { args[0] = 0; // failure lua_settop(L, top); return; } // get the results const int retArgs = std::min(lua_gettop(L) - top, (MAX_LUA_COB_ARGS - 1)); for (int a = 1; a <= retArgs; a++) { const int index = (a + top); if (lua_isnumber(L, index)) { args[a] = lua_toint(L, index); } else if (lua_isboolean(L, index)) { args[a] = lua_toboolean(L, index) ? 1 : 0; } else if (lua_istable(L, index)) { lua_rawgeti(L, index, 1); lua_rawgeti(L, index, 2); if (lua_isnumber(L, -2) && lua_isnumber(L, -1)) { const int x = lua_toint(L, -2); const int z = lua_toint(L, -1); args[a] = PACKXZ(x, z); } else { args[a] = 0; } lua_pop(L, 2); } else { args[a] = 0; } } args[0] = 1; // success lua_settop(L, top); return; }
/** * called after every damage modification (even HitByWeaponId) * but before the damage is applied * * expects two numbers returned by lua code: * 1st is stored under *newDamage if newDamage != NULL * 2nd is stored under *impulseMult if impulseMult != NULL */ bool CLuaRules::UnitPreDamaged(const CUnit* unit, const CUnit* attacker, float damage, int weaponID, bool paralyzer, float* newDamage, float* impulseMult) { if (!haveUnitPreDamaged) { return false; } LUA_CALL_IN_CHECK(L); lua_checkstack(L, 11); const int errfunc = SetupTraceback(L); static const LuaHashString cmdStr("UnitPreDamaged"); if (!cmdStr.GetGlobalFunc(L)) { // remove error handler if (errfunc) { lua_pop(L, 1); } return false; // the call is not defined } int argCount = 5; lua_pushnumber(L, unit->id); lua_pushnumber(L, unit->unitDef->id); lua_pushnumber(L, unit->team); lua_pushnumber(L, damage); lua_pushboolean(L, paralyzer); if (GetFullRead(L)) { lua_pushnumber(L, weaponID); argCount += 1; if (attacker != NULL) { lua_pushnumber(L, attacker->id); lua_pushnumber(L, attacker->unitDef->id); lua_pushnumber(L, attacker->team); argCount += 3; } } // call the routine RunCallInTraceback(cmdStr, argCount, 2, errfunc); if (newDamage && lua_isnumber(L, -2)) { *newDamage = lua_tonumber(L, -2); } else if (!lua_isnumber(L, -2) || lua_isnil(L, -2)) { // first value is obligatory, so may not be nil LOG_L(L_WARNING, "%s(): 1st value returned should be a number (newDamage)", cmdStr.GetString().c_str()); } if (impulseMult && lua_isnumber(L, -1)) { *impulseMult = lua_tonumber(L, -1); } else if (!lua_isnumber(L, -1) && !lua_isnil(L, -1)) { // second value is optional, so nils are OK LOG_L(L_WARNING, "%s(): 2nd value returned should be a number (impulseMult)", cmdStr.GetString().c_str()); } lua_pop(L, 2); return true; }