diff --git a/doc/changelog.txt b/doc/changelog.txt index 1ac79b4997..a0efdc128f 100644 --- a/doc/changelog.txt +++ b/doc/changelog.txt @@ -25,6 +25,11 @@ Lua: - add `Spring.SelectUnit(unitID, bool append = false) -> nil`, single-unit version of SelectUnit{Array,Map} that doesn't require a table - add `Spring.DeselectUnit(unitID) -> nil`, deselects a unit + - add `Spring.SetUnitShieldRechargeDelay(unitID, [weaponNum], [seconds]) -> nil`. Resets a unit's + shield regeneration delay. The weapon number is optional if the unit has a single shield. The + timer value is also optional, if you leave it nil it will emulate a weapon hit. Note that a + weapon hit (both via nil here, and "real" hits) will never decrease the remaining timer, though + it can increase it. An explicit numerical value always sets the timer to that many seconds. - add `wupget:Unit{Entered,Left}Underwater(unitID, unitDefID, teamID)`. Works very similar to the existing Water callins, but EnteredWater applies when the unit dips its toes in water while EnteredUnderwater applies when the unit is completely submerged. diff --git a/rts/Lua/LuaSyncedCtrl.cpp b/rts/Lua/LuaSyncedCtrl.cpp index 53d6379b7d..05a3635b99 100644 --- a/rts/Lua/LuaSyncedCtrl.cpp +++ b/rts/Lua/LuaSyncedCtrl.cpp @@ -190,6 +190,7 @@ bool LuaSyncedCtrl::PushEntries(lua_State* L) REGISTER_LUA_CFUNC(SetUnitBlocking); REGISTER_LUA_CFUNC(SetUnitCrashing); REGISTER_LUA_CFUNC(SetUnitShieldState); + REGISTER_LUA_CFUNC(SetUnitShieldRechargeDelay); REGISTER_LUA_CFUNC(SetUnitFlanking); REGISTER_LUA_CFUNC(SetUnitTravel); REGISTER_LUA_CFUNC(SetUnitFuel); @@ -2925,6 +2926,42 @@ int LuaSyncedCtrl::SetUnitShieldState(lua_State* L) return 0; } +/*** + * @function Spring.SetUnitShieldRechargeDelay + * @number unitID + * @number[opt] weaponID (optional if the unit only has one shield) + * @number[opt] rechargeTime (in seconds; emulates a regular hit if nil) + * @treturn nil + */ +int LuaSyncedCtrl::SetUnitShieldRechargeDelay(lua_State* L) +{ + const auto unit = ParseUnit(L, __func__, 1); + if (unit == nullptr) + return 0; + + auto shield = static_cast (unit->shieldWeapon); + if (lua_isnumber(L, 2)) { + const size_t index = lua_tointeger(L, 2) - LUA_WEAPON_BASE_INDEX; + if (index < unit->weapons.size()) + shield = dynamic_cast (unit->weapons[index]); + } + if (shield == nullptr) + return 0; + + if (lua_isnumber(L, 3)) { + const auto seconds = lua_tofloat(L, 3); + const auto frames = static_cast (seconds * GAME_SPEED); + shield->SetRechargeDelay(frames, true); + } else { + /* Note, overwrite set to false on purpose. This is to emulate a regular + * weapon hit. This lets a sophisticated shield handler gadget coexist + * with a basic "emulate hits" gadget without the latter having to care. + * You can put the weaponDef value explicitly if you want to overwrite. */ + shield->SetRechargeDelay(shield->weaponDef->shieldRechargeDelay, false); + } + + return 0; +} /*** * @function Spring.SetUnitFlanking diff --git a/rts/Lua/LuaSyncedCtrl.h b/rts/Lua/LuaSyncedCtrl.h index 1972f98004..d75b254d7a 100644 --- a/rts/Lua/LuaSyncedCtrl.h +++ b/rts/Lua/LuaSyncedCtrl.h @@ -99,6 +99,7 @@ class LuaSyncedCtrl static int SetUnitBlocking(lua_State* L); static int SetUnitCrashing(lua_State* L); static int SetUnitShieldState(lua_State* L); + static int SetUnitShieldRechargeDelay(lua_State* L); static int SetUnitFlanking(lua_State* L); static int SetUnitTravel(lua_State* L); static int SetUnitFuel(lua_State* L); diff --git a/rts/Sim/Weapons/PlasmaRepulser.cpp b/rts/Sim/Weapons/PlasmaRepulser.cpp index c12c419f0e..dc3ac73b42 100644 --- a/rts/Sim/Weapons/PlasmaRepulser.cpp +++ b/rts/Sim/Weapons/PlasmaRepulser.cpp @@ -165,11 +165,18 @@ void CPlasmaRepulser::Update() sscPool.UpdateCollection(this); } +void CPlasmaRepulser::SetRechargeDelay(int delay, bool overwrite) +{ + if (overwrite) + rechargeDelay = delay; + else + rechargeDelay = std::max(rechargeDelay, delay); +} + // Returns true if the projectile is destroyed. bool CPlasmaRepulser::IncomingProjectile(CWeaponProjectile* p, const float3& hitPos) { const int defHitFrames = weaponDef->visibleShieldHitFrames; - const int defRechargeDelay = weaponDef->shieldRechargeDelay; // gadget handles the collision event, don't touch the projectile // start-pos only makes sense for beams, pass current p->pos here @@ -187,7 +194,7 @@ bool CPlasmaRepulser::IncomingProjectile(CWeaponProjectile* p, const float3& hit if (teamHandler.Team(owner->team)->res.energy < weaponDef->shieldEnergyUse) return false; - rechargeDelay = defRechargeDelay; + SetRechargeDelay(weaponDef->shieldRechargeDelay, false); if (weaponDef->shieldRepulser) { // bounce the projectile diff --git a/rts/Sim/Weapons/PlasmaRepulser.h b/rts/Sim/Weapons/PlasmaRepulser.h index 1ee7b1e9fc..7690c75e7d 100644 --- a/rts/Sim/Weapons/PlasmaRepulser.h +++ b/rts/Sim/Weapons/PlasmaRepulser.h @@ -25,6 +25,7 @@ class CPlasmaRepulser: public CWeapon void SetEnabled(bool b) { isEnabled = b; } + void SetRechargeDelay(int delay, bool overwrite); void SetCurPower(float p) { curPower = p; } bool IsEnabled() const { return isEnabled; }