Пример #1
0
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;
}
Пример #2
0
/**
 * 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;
}