-
Notifications
You must be signed in to change notification settings - Fork 253
Zombie api gadget expanded #5835
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
194121b
f69c2dc
b86a17d
b23494c
9bdc04f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -27,16 +27,34 @@ VFS.Include("LuaRules/Configs/CAI/accessory/targetReachableTester.lua") | |
| -- unsure if these are different, differentiating between gaia and "zombie" team somehow may be good? | ||
| local GaiaTeamID = Spring.GetGaiaTeamID() | ||
| local GaiaAllyTeamID = select(6, Spring.GetTeamInfo(GaiaTeamID, false)) | ||
| local WARNING_TIME = 5 -- set to 5 for sounds and such to sync well. | ||
| local random = math.random | ||
| local floor = math.floor | ||
|
|
||
| local mapWidth | ||
| local mapHeight | ||
|
|
||
| local gameframe = 0 | ||
|
|
||
| local NonZombies = { | ||
| ["asteroid"] = true, | ||
| } | ||
|
|
||
| local CEG_SPAWN = [[zombie]] | ||
| local REZ_SOUND = "sounds/misc/resurrect.wav" | ||
| local ZOMBIE_SOUNDS = { | ||
| "sounds/misc/zombie_1.wav", | ||
| "sounds/misc/zombie_2.wav", | ||
| "sounds/misc/zombie_3.wav", | ||
| } | ||
|
|
||
| local resurrectingFeatures = {} -- contains inital gameframe, base rez time, frame rez should complete and a callback function if someone wants to reuse the functionality | ||
|
|
||
|
|
||
| -- Zombie resurrect | ||
|
|
||
| -- unsure if necessary, seems like just an extra failsafe | ||
|
|
||
| -- Get Feature Defname and facing | ||
| local function GetFeatureResurrectData(featureID) | ||
| local featureDefName, facing = Spring.GetFeatureResurrect(featureID) | ||
| if featureDefName == "" then | ||
|
|
@@ -50,39 +68,44 @@ local function GetFeatureResurrectData(featureID) | |
| return featureDefName, facing | ||
| end | ||
|
|
||
| local function TurnFeatureIntoUnit(featureID,teamID,reclaimPercentHealth) | ||
| local featureDefName,facing = GetFeatureResurrectData(featureID) | ||
| local x, y, z = Spring.GetFeaturePosition(featureID) | ||
| local unitID = Spring.CreateUnit(featureDefName, x, y, z, facing, teamID) | ||
| -- Unit and Wreck exist both | ||
| -- could let there be a function passed to this function, that returns the Unit ID for transfer of values | ||
|
|
||
| if (unitID) then | ||
| gadgetHandler:NotifyUnitCreatedByMechanic(unitID, false, "zombies") | ||
| local size = UnitDefNames[featureDefName].xsize | ||
| Spring.SpawnCEG("resurrect", x, y, z, 0, 0, 0, size) | ||
| Spring.GiveOrderToUnit(unitID, CMD.FIRE_STATE, 2, 0) | ||
| GG.PlayFogHiddenSound(REZ_SOUND, 12, x, y, z) | ||
| if reclaimPercentHealth then | ||
| local currentMetal, maxMetal = Spring.GetFeatureResources(featureID) | ||
| if currentMetal and maxMetal and (maxMetal > 0) then | ||
| local health = Spring.GetUnitHealth(unitID) | ||
| if health then | ||
| Spring.SetUnitHealth(unitID, health*(currentMetal/maxMetal)) | ||
| end | ||
| -- Zombie resurrect | ||
| -- Turns a feature into a unit if applicable. Has a callback returning featureID and unitID for data transfer. Returns unitID. | ||
| local function TurnFeatureIntoUnit(featureID,teamID,reclaimPercentHealthBool, unitReviveCallback) | ||
| local featureDefName,facing = GetFeatureResurrectData(featureID) | ||
| local x, y, z = Spring.GetFeaturePosition(featureID) | ||
|
|
||
| local unitID = Spring.CreateUnit(featureDefName, x, y, z, facing, teamID) | ||
|
|
||
| if not (unitID) then | ||
| return nil | ||
| end | ||
|
|
||
| gadgetHandler:NotifyUnitCreatedByMechanic(unitID, false, "zombies") | ||
| local size = UnitDefNames[featureDefName].xsize | ||
| Spring.SpawnCEG("resurrect", x, y, z, 0, 0, 0, size) | ||
| Spring.GiveOrderToUnit(unitID, CMD.FIRE_STATE, 2, 0) | ||
| GG.PlayFogHiddenSound(REZ_SOUND, 12, x, y, z) | ||
|
|
||
| if reclaimPercentHealthBool then | ||
| local currentMetal, maxMetal = Spring.GetFeatureResources(featureID) | ||
| if currentMetal and maxMetal and (maxMetal > 0) then | ||
| local health = Spring.GetUnitHealth(unitID) | ||
| if health then | ||
| Spring.SetUnitHealth(unitID, health*(currentMetal/maxMetal)) | ||
| end | ||
| end | ||
| end | ||
|
|
||
| Spring.DestroyFeature(featureID) | ||
| return unitID | ||
| end | ||
| end | ||
|
|
||
| -- Unit and Wreck exist both for value transfer | ||
| if (unitReviveCallback) then | ||
| unitReviveCallback(unitID,featureID) | ||
| end | ||
|
|
||
| -- Works on non zombie units too. | ||
| Spring.DestroyFeature(featureID) | ||
| return unitID | ||
| end | ||
|
|
||
| -- Sets the zombie specific speed multiplier. Works on non zombie units too. | ||
| local function SetZombieSpeedMult(unitID,speedMult) | ||
| if type(speedMult) ~= 'number' or speedMult < 0 then | ||
| error("SetZombieSpeedMult: mult must be number >= 0") | ||
|
|
@@ -103,14 +126,13 @@ local function RandomFactoryOrders(unitID, unitDefID) -- give factory something | |
| return | ||
| end | ||
| local orders = {} | ||
| for i = 1, math.random(10, 30) do | ||
| orders[#orders + 1] = {-buildopts[math.random(1, #buildopts)], 0, 0 } | ||
| for i = 1, random(10, 30) do | ||
| orders[#orders + 1] = {-buildopts[random(1, #buildopts)], 0, 0 } | ||
| end | ||
| Spring.GiveOrderArrayToUnit(unitID, orders) | ||
| end | ||
|
|
||
|
|
||
|
|
||
| local function GetUnitNearestAlly(unitID, range) | ||
| local best_ally | ||
| local best_dist | ||
|
|
@@ -132,13 +154,14 @@ local function GetUnitNearestAlly(unitID, range) | |
| return best_ally | ||
| end | ||
|
|
||
| local function GiveZombiesRandomOrders(unitID) | ||
| -- Applies Random Attackmove orders and Factory commands to units. | ||
| local function SetZombieBehavior(unitID) | ||
| local unitDefID = (not Spring.GetUnitIsDead(unitID)) and Spring.GetUnitDefID(unitID) | ||
| if not unitDefID then | ||
| return | ||
| end | ||
|
|
||
| local rx,rz,ry | ||
| Spring.GiveOrderToUnit(unitID, CMD.MOVE_STATE, 2, 0) | ||
| local orders = {} | ||
| local near_ally | ||
| if (UnitDefs[unitDefID].canAttack) then | ||
|
|
@@ -151,12 +174,12 @@ local function GiveZombiesRandomOrders(unitID) | |
| end | ||
| end | ||
| local x,y,z = Spring.GetUnitPosition(unitID) | ||
| if (near_ally) and math.random(0, 5) < 4 then -- 60% chance to guard nearest ally | ||
| if (near_ally) and random(0, 5) < 4 then -- 60% chance to guard nearest ally | ||
| orders[#orders + 1] = {CMD.GUARD, {near_ally}, 0} | ||
| end | ||
| for i = 1, math.random(10, 30) do | ||
| local rx = math.random(0, mapWidth) | ||
| local rz = math.random(0, mapHeight) | ||
| for i = 1, random(10, 30) do | ||
| local rx = random(0, mapWidth) | ||
| local rz = random(0, mapHeight) | ||
| local ry = Spring.GetGroundHeight(rx,rz) | ||
| if IsTargetReallyReachable(unitID, rx, ry, rz, x, y, z) then | ||
| orders[#orders+1] = {CMD.FIGHT, {rx, ry, rz}, CMD.OPT_SHIFT} | ||
|
|
@@ -168,16 +191,109 @@ local function GiveZombiesRandomOrders(unitID) | |
| RandomFactoryOrders(unitID, unitDefID) -- give factory something to do | ||
| end | ||
| end | ||
|
|
||
| -- Adds a wreck into the zombie countdown table and returns it for further modification. | ||
| -- Use the rezFrameCallback to repurpose the system for other effects or chain into TurnFeatureIntoUnit for a revived unit with ID Callback. | ||
| -- If no callback is provided, revives the wreck as a unslowed zombie unit. | ||
| local function AddFeatureToZombieCountdown(featureID, buildpower, minRezTime, rezFrameCallback) | ||
| local resName, face = GetFeatureResurrectData(featureID) | ||
| if resName and face and not resurrectingFeatures[featureID] then | ||
| local ud = resName and UnitDefNames[resName] | ||
| if ud and not NonZombies[resName] then | ||
| local rezBaseTime = ud.metalCost / buildpower | ||
| local rezTime = rezBaseTime | ||
| local _,_,_,_,reclaimPercent,_ = Spring.GetFeatureResources(featureID) | ||
|
|
||
| rezTime = rezBaseTime + rezBaseTime * (1 - reclaimPercent) | ||
|
|
||
|
Comment on lines
+205
to
+208
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Starting revive time is also based on reclaim % left in the wreck instead of assuming it is at 100% This is new, but shouldnt change anything for base zombies as they revive on Feature creation at 100% reclaim. Seem logical and inline for how it would work for a delayed revival application however. |
||
| if (rezTime < minRezTime) then | ||
| rezTime = minRezTime | ||
| end | ||
| resurrectingFeatures[featureID] = { | ||
| rezInitFrame = gameframe, -- frame Feature was queued | ||
| rezBaseTime = rezBaseTime, -- base resurrect time in seconds | ||
| rezFrame = gameframe + rezTime * 32, -- frame the resurrect completes or the callback is fired. | ||
| rezFrameCallback = rezFrameCallback, -- callback function fired on rezFrame | ||
| rezWarningTime = WARNING_TIME, -- warning time in seconds for base particles and sfx, set 0 to hide. | ||
| reclaimPercent = reclaimPercent, -- reclaim left in feature in % to compare and adjust reztime | ||
| } | ||
| return resurrectingFeatures[featureID] | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should allow anyone to modify the base values to their liking afterwards Unsure if there would be a better way to do things for this function outside of me assuming some base functionality/behavior as a wanted standard and then exposing the output for tweaks. |
||
| end | ||
| end | ||
| return nil | ||
| end | ||
|
|
||
| -- Get and modify the table as you wish. | ||
| local function GetZombieResurrectData() | ||
| return resurrectingFeatures | ||
| end | ||
|
|
||
| -- Reclaiming the wreck can stretch the revive time up to 2x the base time. | ||
| function gadget:AllowFeatureBuildStep(builderID, builderTeam, featureID, featureDefID, part) | ||
| if (resurrectingFeatures[featureID]) then | ||
| local rezInitFrame = resurrectingFeatures[featureID].rezInitFrame | ||
| local rezBaseTime = resurrectingFeatures[featureID].rezBaseTime | ||
| local reclaimPercent = resurrectingFeatures[featureID].reclaimPercent | ||
|
|
||
| reclaimPercent = reclaimPercent + part | ||
| local rezTime = rezBaseTime + rezBaseTime * (1 - reclaimPercent) | ||
| resurrectingFeatures[featureID].rezFrame = rezInitFrame + rezTime * 32 | ||
|
|
||
| resurrectingFeatures[featureID].reclaimPercent = reclaimPercent | ||
| end | ||
| return true | ||
|
Comment on lines
+231
to
+244
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Was a bit scary to touch, but I think is functionally identical. |
||
| end | ||
|
|
||
| function gadget:FeatureDestroyed(featureID, allyTeam) | ||
| if (resurrectingFeatures[featureID]) then | ||
| resurrectingFeatures[featureID] = nil | ||
| end | ||
| end | ||
|
|
||
| function gadget:GameFrame(f) | ||
| gameframe = f | ||
| if f%32 ~= 0 then | ||
| return | ||
| end | ||
| local spSpawnCEG = Spring.SpawnCEG -- putting the localization here because cannot localize in global scope since spring 97 | ||
| for featureID in pairs(resurrectingFeatures) do | ||
| local rezFrame = resurrectingFeatures[featureID].rezFrame | ||
| if rezFrame <= gameframe then | ||
| if (resurrectingFeatures[featureID].rezFrameCallback) then | ||
|
Stiofan-K marked this conversation as resolved.
|
||
| resurrectingFeatures[featureID].rezFrameCallback(featureID) | ||
| else | ||
| local unitID = TurnFeatureIntoUnit(featureID,GaiaTeamID,true,nil) | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unsure if this sort of default behavior is good practice. |
||
| SetZombieBehavior(unitID) | ||
| end | ||
| else | ||
| local secondsTillRezCall = floor((rezFrame - f) / 32) | ||
| local rezWarningTime = resurrectingFeatures[featureID].rezWarningTime | ||
| --Spring.Echo("Time left for "..featureID..": "..secondsTillRezCall) | ||
| if secondsTillRezCall <= rezWarningTime then | ||
| local r = Spring.GetFeatureRadius(featureID) | ||
| local x, y, z = Spring.GetFeaturePosition(featureID) | ||
| spSpawnCEG(CEG_SPAWN, x, y, z, 0, 0, 0, 10 + r, 10 + r) | ||
|
|
||
| if secondsTillRezCall == rezWarningTime then | ||
| local z_sound = ZOMBIE_SOUNDS[random(#ZOMBIE_SOUNDS)] | ||
| GG.PlayFogHiddenSound(z_sound, 4, x, y, z) | ||
| end | ||
| end | ||
| end | ||
| end | ||
| end | ||
|
|
||
| function gadget:Initialize() | ||
|
|
||
| mapWidth = Game.mapSizeX | ||
| mapHeight = Game.mapSizeZ | ||
|
|
||
| GG.Zombies = { | ||
| TurnFeatureIntoUnit = TurnFeatureIntoUnit, | ||
| SetZombieSpeedMult = SetZombieSpeedMult, | ||
| SetZombieBehavior = GiveZombiesRandomOrders, | ||
| GetFeatureResurrectData = GetFeatureResurrectData | ||
| } | ||
| end | ||
| TurnFeatureIntoUnit = TurnFeatureIntoUnit, | ||
| SetZombieSpeedMult = SetZombieSpeedMult, | ||
| SetZombieBehavior = SetZombieBehavior, | ||
| GetFeatureResurrectData = GetFeatureResurrectData, | ||
| GetZombieResurrectData = GetZombieResurrectData, -- I want to expose these for modification from outside if desired | ||
| AddFeatureToZombieCountdown = AddFeatureToZombieCountdown | ||
| } | ||
| end | ||
Uh oh!
There was an error while loading. Please reload this page.