-
Notifications
You must be signed in to change notification settings - Fork 252
Zombie api gadget #5784
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?
Zombie api gadget #5784
Changes from all commits
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 | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,191 @@ | ||||||||||||
| -------------------------------------------------------------------------------- | ||||||||||||
| -------------------------------------------------------------------------------- | ||||||||||||
|
|
||||||||||||
| function gadget:GetInfo() | ||||||||||||
| return { | ||||||||||||
| name = "Zombie helper api", | ||||||||||||
| desc = "The place to handle your zombie esque needs!", | ||||||||||||
| author = "Stiofan", | ||||||||||||
| date = "June 2026", | ||||||||||||
|
Comment on lines
+8
to
+9
Member
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. largely just shuffling of existing code
Suggested change
|
||||||||||||
| license = "GPL v2 or later", | ||||||||||||
| layer = math.huge, | ||||||||||||
| enabled = true | ||||||||||||
| } | ||||||||||||
| end | ||||||||||||
|
|
||||||||||||
| -------------------------------------------------------------------------------- | ||||||||||||
| -------------------------------------------------------------------------------- | ||||||||||||
|
|
||||||||||||
| -- pathing tester. Is this the correct way to import these things? | ||||||||||||
| 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 mapWidth | ||||||||||||
| local mapHeight | ||||||||||||
|
|
||||||||||||
| local REZ_SOUND = "sounds/misc/resurrect.wav" | ||||||||||||
|
|
||||||||||||
| --unused, may be used depending on how things shake out | ||||||||||||
| local ZOMBIE_SOUNDS = { | ||||||||||||
| "sounds/misc/zombie_1.wav", | ||||||||||||
| "sounds/misc/zombie_2.wav", | ||||||||||||
|
Comment on lines
+31
to
+34
Member
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. sounds easy to copypaste if/when that happens |
||||||||||||
| "sounds/misc/zombie_3.wav", | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
|
|
||||||||||||
|
|
||||||||||||
|
|
||||||||||||
| -- Zombie resurrect | ||||||||||||
|
|
||||||||||||
| -- unsure if necessary, seems like just an extra failsafe | ||||||||||||
| local function GetFeatureResurrectData(featureID) | ||||||||||||
| local featureDefName, facing = Spring.GetFeatureResurrect(featureID) | ||||||||||||
| if featureDefName == "" then | ||||||||||||
| local featureDef = FeatureDefs[Spring.GetFeatureDefID(featureID)] | ||||||||||||
| local featureName = featureDef.name or "" | ||||||||||||
| if featureDef.resurrectable == 1 then | ||||||||||||
| featureDefName = featureName:gsub('(.*)_.*', '%1') --filter out _dead | ||||||||||||
| facing = facing or 0 | ||||||||||||
| end | ||||||||||||
| end | ||||||||||||
| return featureDefName, facing | ||||||||||||
| end | ||||||||||||
|
|
||||||||||||
| local function TurnFeatureIntoUnit(featureID,teamID,reclaimPercentHealth) | ||||||||||||
|
|
||||||||||||
| local featureDefName,facing = GetFeatureResurrectData(featureID) | ||||||||||||
| local x, y, z = Spring.GetFeaturePosition(featureID) | ||||||||||||
|
|
||||||||||||
| if reclaimPercentHealth then | ||||||||||||
| local currentMetal, maxMetal = Spring.GetFeatureResources(featureID) | ||||||||||||
| if currentMetal and maxMetal and (maxMetal > 0) then | ||||||||||||
| partialReclaim = currentMetal/maxMetal | ||||||||||||
|
Comment on lines
+62
to
+65
Member
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. When the code does not enter these |
||||||||||||
| end | ||||||||||||
| end | ||||||||||||
|
|
||||||||||||
| Spring.DestroyFeature(featureID) | ||||||||||||
| local unitID = Spring.CreateUnit(featureDefName, x, y, z, facing, teamID) | ||||||||||||
|
Comment on lines
+69
to
+70
Member
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. these could be swapped, would keep a brief window where they exist together to allow transferring some traits from the feature to the unit in the future, if needed |
||||||||||||
|
|
||||||||||||
| 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 partialReclaim ~= 1 then | ||||||||||||
| local health = Spring.GetUnitHealth(unitID) | ||||||||||||
| if health then | ||||||||||||
| Spring.SetUnitHealth(unitID, health*partialReclaim) | ||||||||||||
|
Comment on lines
+78
to
+81
Member
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. and since |
||||||||||||
| end | ||||||||||||
| end | ||||||||||||
| end | ||||||||||||
|
|
||||||||||||
| return unitID | ||||||||||||
| end | ||||||||||||
|
|
||||||||||||
| -- Works on non zombie units too. | ||||||||||||
| local function SetZombieSpeedMult(unitID,speedMult) | ||||||||||||
| Spring.SetUnitRulesParam(unitID, "zombieSpeedMult", speedMult, LOS_ACCESS) | ||||||||||||
|
Member
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. Now that it's an API it needs a bit more care around argument correctness, perhaps add something like
Suggested change
|
||||||||||||
| GG.UpdateUnitAttributes(unitID) | ||||||||||||
| end | ||||||||||||
|
|
||||||||||||
|
|
||||||||||||
| -- Zombie commands | ||||||||||||
|
|
||||||||||||
| local function RandomFactoryOrders(unitID, unitDefID) -- give factory something to do | ||||||||||||
| local buildopts = UnitDefs[unitDefID].buildOptions | ||||||||||||
| if (not buildopts) or #buildopts <= 0 then | ||||||||||||
| return | ||||||||||||
| end | ||||||||||||
| local orders = {} | ||||||||||||
| for i = 1, math.random(10, 30) do | ||||||||||||
| orders[#orders + 1] = {-buildopts[math.random(1, #buildopts)], 0, 0 } | ||||||||||||
| end | ||||||||||||
| if (#orders > 0) then | ||||||||||||
| if not Spring.GetUnitIsDead(unitID) then | ||||||||||||
|
Comment on lines
+107
to
+108
Member
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. death checks could be done at the top, before rolling dice 30 times. the orders check is redundant since there's always at least 10 orders. |
||||||||||||
| Spring.GiveOrderArrayToUnitArray({unitID}, orders) | ||||||||||||
|
Member
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. the array always has just 1 unit, so could be just |
||||||||||||
| end | ||||||||||||
| end | ||||||||||||
| end | ||||||||||||
|
|
||||||||||||
|
|
||||||||||||
| local function disSQ(x1, y1, x2, y2) | ||||||||||||
| return (x1 - x2)^2 + (y1 - y2)^2 | ||||||||||||
| end | ||||||||||||
|
Comment on lines
+115
to
+117
Member
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. could use |
||||||||||||
|
|
||||||||||||
| local function GetUnitNearestAlly(unitID, range) | ||||||||||||
| local best_ally | ||||||||||||
| local best_dist | ||||||||||||
| local x, y, z = Spring.GetUnitPosition(unitID) | ||||||||||||
| local units = Spring.GetUnitsInCylinder(x, z, range) | ||||||||||||
| for i = 1, #units do | ||||||||||||
| local allyID = units[i] | ||||||||||||
| local allyTeam = Spring.GetUnitTeam(allyID) | ||||||||||||
| local allyDefID = Spring.GetUnitDefID(allyID) | ||||||||||||
| if (allyID ~= unitID) and (allyTeam == GaiaTeamID) and (Spring.Utilities.getMovetype(UnitDefs[allyDefID]) ~= false) then | ||||||||||||
| local ox, oy, oz = Spring.GetUnitPosition(allyID) | ||||||||||||
| local dist = disSQ(x, z, ox ,oz) | ||||||||||||
| if IsTargetReallyReachable(unitID, ox, oy, oz, x, y, z) and ((best_dist == nil) or (dist < best_dist)) then | ||||||||||||
| best_ally = allyID | ||||||||||||
| best_dist = dist | ||||||||||||
| end | ||||||||||||
| end | ||||||||||||
| end | ||||||||||||
| return best_ally | ||||||||||||
| end | ||||||||||||
|
|
||||||||||||
| local function GiveZombiesRandomOrders(unitID) | ||||||||||||
| local unitDefID = (not Spring.GetUnitIsDead(unitID)) and Spring.GetUnitDefID(unitID) | ||||||||||||
| if not unitDefID then | ||||||||||||
| return | ||||||||||||
| end | ||||||||||||
|
|
||||||||||||
| local rx,rz,ry | ||||||||||||
| local orders = {} | ||||||||||||
| local near_ally | ||||||||||||
| if (UnitDefs[unitDefID].canAttack) then | ||||||||||||
| -- May be uncessecary, but it depends on the kind of behavior that is wanted. I suppose mirroring the previous behavior is the objective | ||||||||||||
| near_ally = GetUnitNearestAlly(unitID, 300) | ||||||||||||
| if (near_ally) then | ||||||||||||
| if Spring.GetUnitCurrentCommand(near_ally) == CMD.GUARD then | ||||||||||||
| near_ally = nil -- avoiding chain guards | ||||||||||||
| end | ||||||||||||
| 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 | ||||||||||||
| orders[#orders + 1] = {CMD.GUARD, {near_ally}, 0} | ||||||||||||
| end | ||||||||||||
| for i = 1, math.random(10, 30) do | ||||||||||||
| rx = math.random(0, mapWidth) | ||||||||||||
| rz = math.random(0, mapHeight) | ||||||||||||
| 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} | ||||||||||||
| end | ||||||||||||
| end | ||||||||||||
| if (#orders > 0) then | ||||||||||||
| if not Spring.GetUnitIsDead(unitID) then | ||||||||||||
| Spring.GiveOrderArrayToUnitArray({unitID},orders) | ||||||||||||
| end | ||||||||||||
| end | ||||||||||||
| if (UnitDefs[unitDefID].isFactory) then | ||||||||||||
| RandomFactoryOrders(unitID, unitDefID) -- give factory something to do | ||||||||||||
| end | ||||||||||||
| end | ||||||||||||
|
|
||||||||||||
| function gadget:Initialize() | ||||||||||||
|
|
||||||||||||
| mapWidth = Game.mapSizeX | ||||||||||||
| mapHeight = Game.mapSizeZ | ||||||||||||
|
|
||||||||||||
| GG.Zombies = { | ||||||||||||
| TurnFeatureIntoUnit = TurnFeatureIntoUnit, | ||||||||||||
| SetZombieSpeedMult = SetZombieSpeedMult, | ||||||||||||
| SetZombieBehavior = GiveZombiesRandomOrders, | ||||||||||||
| GetFeatureResurrectData = GetFeatureResurrectData | ||||||||||||
| } | ||||||||||||
| end | ||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
needs a synced code check, same as zombies