bool CSyncedLuaHandle::FeaturePreDamaged( const CFeature* feature, const CUnit* attacker, float damage, int weaponDefID, int projectileID, float* newDamage, float* impulseMult) { LUA_CALL_IN_CHECK(L, false); luaL_checkstack(L, 2 + 9 + 2, __FUNCTION__); static const LuaHashString cmdStr(__FUNCTION__); const LuaUtils::ScopedDebugTraceBack traceBack(L); if (!cmdStr.GetGlobalFunc(L)) return false; int inArgCount = 4; int outArgCount = 2; lua_pushnumber(L, feature->id); lua_pushnumber(L, feature->def->id); lua_pushnumber(L, feature->team); lua_pushnumber(L, damage); if (GetHandleFullRead(L)) { lua_pushnumber(L, weaponDefID); inArgCount += 1; lua_pushnumber(L, projectileID); inArgCount += 1; if (attacker != NULL) { lua_pushnumber(L, attacker->id); lua_pushnumber(L, attacker->unitDef->id); lua_pushnumber(L, attacker->team); inArgCount += 3; } } // call the routine if (!RunCallInTraceback(L, cmdStr, inArgCount, outArgCount, traceBack.GetErrFuncIdx(), false)) return false; 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, outArgCount); return (*newDamage == 0.f && *impulseMult == 0.f); // returns true to disable engine dmg handling }
/** * 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 weaponDefID, int projectileID, bool paralyzer, float* newDamage, float* impulseMult) { if (!haveUnitPreDamaged) return false; LUA_CALL_IN_CHECK(L, false); lua_checkstack(L, 9 + 4); const int errfunc = SetupTraceback(L); static const LuaHashString cmdStr("UnitPreDamaged"); if (!cmdStr.GetGlobalFunc(L)) { if (errfunc) // remove error handler 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 (GetHandleFullRead(L)) { lua_pushnumber(L, weaponDefID); argCount += 1; lua_pushnumber(L, projectileID); 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 const bool success = RunCallInTraceback(cmdStr, argCount, 2, errfunc); if (!success) return false; 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; }
/** * 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 weaponDefID, int projectileID, bool paralyzer, float* newDamage, float* impulseMult) { if (!haveUnitPreDamaged) return false; LUA_CALL_IN_CHECK(L, false); luaL_checkstack(L, 2 + 2 + 10, __FUNCTION__); static const LuaHashString cmdStr(__FUNCTION__); const LuaUtils::ScopedDebugTraceBack traceBack(L); if (!cmdStr.GetGlobalFunc(L)) return false; int inArgCount = 5; int outArgCount = 2; lua_pushnumber(L, unit->id); lua_pushnumber(L, unit->unitDef->id); lua_pushnumber(L, unit->team); lua_pushnumber(L, damage); lua_pushboolean(L, paralyzer); //FIXME pass impulse too? if (GetHandleFullRead(L)) { lua_pushnumber(L, weaponDefID); inArgCount += 1; lua_pushnumber(L, projectileID); inArgCount += 1; if (attacker != NULL) { lua_pushnumber(L, attacker->id); lua_pushnumber(L, attacker->unitDef->id); lua_pushnumber(L, attacker->team); inArgCount += 3; } } // call the routine // NOTE: // RunCallInTraceback removes the error-handler by default // this has to be disabled when using ScopedDebugTraceBack // or it would mess up the stack if (!RunCallInTraceback(cmdStr, inArgCount, outArgCount, traceBack.GetErrFuncIdx(), false)) return false; 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 return-value 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 return-value should be a number (impulseMult)", (cmdStr.GetString()).c_str()); } lua_pop(L, outArgCount); return true; }
int CLuaHandleSynced::CallAsTeam(lua_State* L) { CLuaHandleSynced* lhs = GetSyncedHandle(L); if (lhs->teamsLocked) { luaL_error(L, "CallAsTeam() called when teams are locked"); } const int args = lua_gettop(L); if ((args < 2) || !lua_isfunction(L, 2)) { luaL_error(L, "Incorrect arguments to CallAsTeam()"); } // save the current access const bool prevFullCtrl = GetHandleFullCtrl(L); const bool prevFullRead = GetHandleFullRead(L); const int prevCtrlTeam = GetHandleCtrlTeam(L); const int prevReadTeam = GetHandleReadTeam(L); const int prevReadAllyTeam = GetHandleReadAllyTeam(L); const int prevSelectTeam = GetHandleSelectTeam(L); // parse the new access if (lua_isnumber(L, 1)) { const int teamID = lua_toint(L, 1); if ((teamID < MinSpecialTeam) || (teamID >= teamHandler->ActiveTeams())) { luaL_error(L, "Bad teamID in SetCtrlTeam"); } // ctrl SetHandleCtrlTeam(L, teamID); SetHandleFullCtrl(L, GetHandleCtrlTeam(L) == CEventClient::AllAccessTeam); // read SetHandleReadTeam(L, teamID); SetHandleReadAllyTeam(L, (teamID < 0) ? teamID : teamHandler->AllyTeam(teamID)); SetHandleFullRead(L, GetHandleReadAllyTeam(L) == CEventClient::AllAccessTeam); // select SetHandleSelectTeam(L, teamID); } else if (lua_istable(L, 1)) { const int table = 1; for (lua_pushnil(L); lua_next(L, table) != 0; lua_pop(L, 1)) { if (!lua_israwstring(L, -2) || !lua_isnumber(L, -1)) { continue; } const string key = lua_tostring(L, -2); const int teamID = lua_toint(L, -1); if ((teamID < MinSpecialTeam) || (teamID >= teamHandler->ActiveTeams())) { luaL_error(L, "Bad teamID in SetCtrlTeam"); } if (key == "ctrl") { SetHandleCtrlTeam(L, teamID); SetHandleFullCtrl(L, GetHandleCtrlTeam(L) == CEventClient::AllAccessTeam); } else if (key == "read") { SetHandleReadTeam(L, teamID); SetHandleReadAllyTeam(L, (teamID < 0) ? teamID : teamHandler->AllyTeam(teamID)); SetHandleFullRead(L, GetHandleReadAllyTeam(L) == CEventClient::AllAccessTeam); } else if (key == "select") { SetHandleSelectTeam(L, teamID); } } } else { luaL_error(L, "Incorrect arguments to CallAsTeam()"); } // call the function const int funcArgs = lua_gettop(L) - 2; // protected call so that the permissions are always reverted const int error = lua_pcall(L, funcArgs, LUA_MULTRET, 0); // revert the permissions SetHandleFullCtrl(L, prevFullCtrl); SetHandleFullRead(L, prevFullRead); SetHandleCtrlTeam(L, prevCtrlTeam); SetHandleReadTeam(L, prevReadTeam); SetHandleReadAllyTeam(L, prevReadAllyTeam); SetHandleSelectTeam(L, prevSelectTeam); if (error != 0) { LOG_L(L_ERROR, "error = %i, %s, %s", error, "CallAsTeam", lua_tostring(L, -1)); lua_error(L); } return lua_gettop(L) - 1; // the teamID/table is still on the stack }