diff --git a/effects/emitters/build_beam_01_emit.bp b/effects/emitters/build_beam_01_emit.bp new file mode 100644 index 0000000000..f999c573fb --- /dev/null +++ b/effects/emitters/build_beam_01_emit.bp @@ -0,0 +1,10 @@ +BeamBlueprint { + Lifetime = 2, + TextureName = '/textures/particles/beam_disruptor.dds', + Thickness = 0.025, + StartColor = {x=0.2,y=0.2,z=1,w=0.3}, # R,G,B,A + EndColor = {x=0.2,y=0.2,z=1,w=0.3}, # R,G,B,A + Length = 8, + UShift = 0.0, + VShift = -0.5, +} diff --git a/effects/emitters/build_beam_02_emit.bp b/effects/emitters/build_beam_02_emit.bp new file mode 100644 index 0000000000..deca0a8d32 --- /dev/null +++ b/effects/emitters/build_beam_02_emit.bp @@ -0,0 +1,10 @@ +BeamBlueprint { + Lifetime = 2, + TextureName = '/textures/particles/beam_white_02.dds', + Thickness = 0.018, + StartColor = {x=0.6,y=0,z=0.1,w=0.2}, # R,G,B,Glow + EndColor = {x=1,y=0.2,z=0,w=0.2}, # R,G,B,Glow + Length = 8, + UShift = 0.0, + VShift = 0.0, +} diff --git a/effects/emitters/build_beam_03_emit.bp b/effects/emitters/build_beam_03_emit.bp new file mode 100644 index 0000000000..0ed33f2f4e --- /dev/null +++ b/effects/emitters/build_beam_03_emit.bp @@ -0,0 +1,10 @@ +BeamBlueprint { + Lifetime = 2, + TextureName = '/textures/particles/beam_white_07.dds', + Thickness = 0.025, + StartColor = {x=1,y=0.2,z=0,w=0.2}, # R,G,B,Glow + EndColor = {x=0,y=0,z=0,w=0}, # R,G,B,Glow + Length = 8, + UShift = 0.0, + VShift = 0.0, +} diff --git a/effects/emitters/build_bot_beam_01_emit.bp b/effects/emitters/build_bot_beam_01_emit.bp new file mode 100644 index 0000000000..7e2915408c --- /dev/null +++ b/effects/emitters/build_bot_beam_01_emit.bp @@ -0,0 +1,10 @@ +BeamBlueprint { + Lifetime = 2, + TextureName = '/textures/particles/beam_white_02.dds', + Thickness = 0.020, + StartColor = {x=0.6,y=0,z=0.1,w=0.0}, # R,G,B,Glow + EndColor = {x=1,y=0.2,z=0,w=0.0}, # R,G,B,Glow + Length = 8, + UShift = 0.0, + VShift = -0.05, +} diff --git a/effects/emitters/build_bot_beam_02_emit.bp b/effects/emitters/build_bot_beam_02_emit.bp new file mode 100644 index 0000000000..62182486e9 --- /dev/null +++ b/effects/emitters/build_bot_beam_02_emit.bp @@ -0,0 +1,10 @@ +BeamBlueprint { + Lifetime = 2, + TextureName = '/textures/particles/beam_white_02.dds', + Thickness = 0.015, + StartColor = {x=0.6,y=0,z=0.1,w=0.0}, # R,G,B,Glow + EndColor = {x=1,y=0.2,z=0,w=0.0}, # R,G,B,Glow + Length = 8, + UShift = 0.0, + VShift = 0.0, +} diff --git a/effects/emitters/build_bot_beam_03_emit.bp b/effects/emitters/build_bot_beam_03_emit.bp new file mode 100644 index 0000000000..80c362a79b --- /dev/null +++ b/effects/emitters/build_bot_beam_03_emit.bp @@ -0,0 +1,11 @@ +BeamBlueprint { + Lifetime = 2, + TextureName = '/textures/particles/beam_white_02.dds', + Thickness = 0.030, + StartColor = {x=1,y=0.2,z=0,w=0.0}, # R,G,B,Glow + EndColor = {x=0,y=0,z=0,w=0}, # R,G,B,Glow + RepeatRate = 0.1, + Length = 2, + UShift = 0.0, + VShift = -0.2, +} diff --git a/lua/EffectUtilities.lua b/lua/EffectUtilities.lua index 17ca2d3db6..cf96ad05d2 100644 --- a/lua/EffectUtilities.lua +++ b/lua/EffectUtilities.lua @@ -10,6 +10,8 @@ local Entity = import('/lua/sim/Entity.lua').Entity local EffectTemplate = import('/lua/EffectTemplates.lua') local RandomFloat = import('/lua/utilities.lua').GetRandomFloat +local DeprecatedWarnings = { } + function CreateEffects(obj, army, EffectTable) local emitters = {} for _, v in EffectTable do @@ -377,6 +379,14 @@ function CreateAeonBuildBaseThread(unitBeingBuilt, builder, EffectsBag) end function CreateCybranBuildBeams(builder, unitBeingBuilt, BuildEffectBones, BuildEffectsBag) + + -- deprecation warning for more effcient alternative + if not DeprecatedWarnings.CreateCybranBuildBeams then + DeprecatedWarnings.CreateCybranBuildBeams = true + WARN("CreateCybranBuildBeams is deprecated: use CreateCybranBuildBeamsOpti instead.") + WARN("Source: " .. repr(debug.getinfo(2))) + end + WaitSeconds(0.2) local BeamBuildEmtBp = '/effects/emitters/build_beam_02_emit.bp' local BeamEndEntities = {} @@ -407,6 +417,14 @@ function CreateCybranBuildBeams(builder, unitBeingBuilt, BuildEffectBones, Build end function SpawnBuildBots(builder, unitBeingBuilt, BuildEffectsBag) + + -- deprecation warning for more effcient alternative + if not DeprecatedWarnings.SpawnBuildBots then + DeprecatedWarnings.SpawnBuildBots = true + WARN("SpawnBuildBots is deprecated: use SpawnBuildBotsOpti instead.") + WARN("Source: " .. repr(debug.getinfo(2))) + end + -- Buildbots are scaled: ~ 1 pr 15 units of BP -- clamped to a max of 10 to avoid insane FPS drop -- with mods that modify BP @@ -464,6 +482,14 @@ function SpawnBuildBots(builder, unitBeingBuilt, BuildEffectsBag) end function CreateCybranEngineerBuildEffects(builder, BuildBones, BuildBots, BuildEffectsBag) + + -- deprecation warning for more effcient alternative + if not DeprecatedWarnings.CreateCybranEngineerBuildEffects then + DeprecatedWarnings.CreateCybranEngineerBuildEffects = true + WARN("CreateCybranEngineerBuildEffects is deprecated: use CreateCybranEngineerBuildEffectsOpti instead.") + WARN("Source: " .. repr(debug.getinfo(2))) + end + -- Create build constant build effect for each build effect bone defined if BuildBones and BuildBots then for _, vBone in BuildBones do @@ -489,15 +515,16 @@ function CreateCybranEngineerBuildEffects(builder, BuildBones, BuildBots, BuildE end end +local BuildEffects = { + '/effects/emitters/sparks_03_emit.bp', + '/effects/emitters/flashes_01_emit.bp', +} +local UnitBuildEffects = { + '/effects/emitters/build_cybran_spark_flash_04_emit.bp', + '/effects/emitters/build_sparks_blue_02_emit.bp', +} + function CreateCybranFactoryBuildEffects(builder, unitBeingBuilt, BuildBones, BuildEffectsBag) - local BuildEffects = { - '/effects/emitters/sparks_03_emit.bp', - '/effects/emitters/flashes_01_emit.bp', - } - local UnitBuildEffects = { - '/effects/emitters/build_cybran_spark_flash_04_emit.bp', - '/effects/emitters/build_sparks_blue_02_emit.bp', - } CreateCybranBuildBeams(builder, unitBeingBuilt, BuildBones.BuildEffectBones, BuildEffectsBag) @@ -1881,3 +1908,34 @@ function DestroyRemainingTeleportChargingEffects(unit, EffectsBag) unit.TeleportCybranSphere:Destroy() end end + +--- Optimized functions -- + +local EffectUtilitiesOpti = import('/lua/EffectUtilitiesOpti.lua') + +--- Creates tracker beams between the builder and its build bots. The +-- bots keep the tracker in their trashbag. +-- @param builder The builder / tracking entity of the build bots. +-- @param buildBones The bones to use as the origin of the beams. +-- @param buildBots The build bots that we're tracking. +-- @param total The number of build bots / bones. The 1st bone will track the 1st bot, etc. +CreateCybranEngineerBuildEffectsOpti = EffectUtilitiesOpti.CreateCybranEngineerBuildEffects +-- original: CreateCybranEngineerBuildEffects + +--- Creates the beams and welding points of the builder and its bots. The +-- bots share the welding point which each other, as does the builder with +-- itself. +-- @param builder A builder with builder.BuildEffectBones set. +-- @param bots The bots of the builder. +-- @param unitBeingBuilt The unit that we're building. +-- @param buildEffectsBag The bag that we use to store / trash all effects. +-- @param stationary Whether or not the builder is a building. +CreateCybranBuildBeamsOpti = EffectUtilitiesOpti.CreateCybranBuildBeams +-- original: CreateCybranBuildBeams + +--- Creates the build drones for the (cybran) builder in question. Expects +-- the builder.BuildBotTotal value to be set. +-- @param builder A cybran builder such as an engineer, hive or commander. +-- @param botBlueprint The blueprint to use for the bot. +SpawnBuildBotsOpti = EffectUtilitiesOpti.SpawnBuildBots +-- original: SpawnBuildBots \ No newline at end of file diff --git a/lua/EffectUtilitiesOpti.lua b/lua/EffectUtilitiesOpti.lua new file mode 100644 index 0000000000..7fd93a81e6 --- /dev/null +++ b/lua/EffectUtilitiesOpti.lua @@ -0,0 +1,254 @@ + +-- imports for functionality +local Entity = import('/lua/sim/Entity.lua').Entity +local EffectTemplate = import('/lua/EffectTemplates.lua') + +-- upvalued cache - do not use after waiting +local VectorCached = Vector(0, 0, 0) + +-- globals as upvalues for performance +local Warp = Warp +local Vector = Vector +local Random = Random +local ArmyBrains = ArmyBrains +local CreateUnit = CreateUnit +local KillThread = KillThread +local setmetatable = setmetatable +local WaitTicks = coroutine.yield + +local CreateEmitterOnEntity = CreateEmitterOnEntity +local AttachBeamEntityToEntity = AttachBeamEntityToEntity + +local IssueClearCommands = IssueClearCommands +local IssueGuard = IssueGuard + +-- moho functions as upvalues for performance +local EntityGetPosition = moho.entity_methods.GetPosition +local EntityBeenDestroyed = moho.entity_methods.BeenDestroyed +local EntityGetPositionXYZ = moho.entity_methods.GetPositionXYZ +local EntityGetOrientation = moho.entity_methods.GetOrientation + +local UnitRevertElevation = moho.unit_methods.RevertElevation + +-- math functions as upvalues for performance +local MathPi = math.pi +local MathSin = math.sin +local MathCos = math.cos + +-- upvalued trashbag functions for performance +local TrashBag = _G.TrashBag +local TrashBagAdd = TrashBag.Add + +-- CYBRAN SPECIFICS -- + +-- all possible bot blueprint values +local CybranBuildBotBlueprints = { + 'ura0001', + 'ura0002', + 'ura0003', + -- 'ura0004' +} + +local CybranBuildBotBeams = { + '/effects/emitters/build_bot_beam_01_emit.bp', + '/effects/emitters/build_bot_beam_02_emit.bp', + '/effects/emitters/build_bot_beam_03_emit.bp', +} + +--- Creates the build drones for the (cybran) builder in question. Expects +-- the builder.BuildBotTotal value to be set. +-- @param builder A cybran builder such as an engineer, hive or commander. +-- @param botBlueprint The blueprint to use for the bot. +function SpawnBuildBots(builder) + + -- kill potential return thread + if builder.ReturnBotsThreadInstance then + KillThread(builder.ReturnBotsThreadInstance) + builder.ReturnBotsThreadInstance = nil + end + + -- initialisation block + -- if there have been no bots before then prepare data to have bots + local bots = builder.BuildBots + if not bots then + builder.BuildBotsNext = 1 + builder.BuildBots = { } + + -- make it weak so that the garbage collection can clean up the table when the unit is destroyed + setmetatable(builder.BuildBots, { __mode = "v" }) + + bots = builder.BuildBots + end + + -- get information about the builder + local x, y, z = EntityGetPositionXYZ(builder) + local q = EntityGetOrientation(builder) + local qx, qy, qz, qw = q[1], q[2], q[3], q[4] + + -- prepare information required to make bots + local angleInitial = 180 + local VecMul = 0.5 + local xVec = 0 + local yVec = 0.1 + local zVec = 0 + local angle = (2 * MathPi) / builder.BuildBotTotal + + -- go over all the bots and see which ones we're missing + local builderArmy = builder.Army + for k = 1, builder.BuildBotTotal do + + -- check if the bot stil exists + local bot = bots[k] + if not bot or EntityBeenDestroyed(bot) then + + -- get a random direction for the bot + xVec = MathSin(angleInitial + (k * angle)) * VecMul + zVec = MathCos(angleInitial + (k * angle)) * VecMul + + -- make the bot + local botBlueprint = CybranBuildBotBlueprints[k] or 'ura0001' + bot = CreateUnit(botBlueprint, builderArmy, x + xVec, y + yVec, z + zVec, qx, qy, qz, qw, 'Air') + + -- make build bots unkillable + bot.SpawnedBy = builder + + -- store the bot + bots[k] = bot + builder.BuildBotsNext = builder.BuildBotsNext + 1 + end + end + + -- make the drones focus builder target + local focus = builder:GetFocusUnit() + + -- focus may be nil if we got paused and building is finished + if focus then + for k = 1, builder.BuildBotTotal do + -- revert drone elevation to blueprint value + local bot = bots[k] + UnitRevertElevation(bot) + end + + -- clear up commands and guard (assist) structure + IssueClearCommands(bots) + IssueGuard(bots, focus) + end +end + +-- add as upvalue for performance for CreateCybranBuildBeamsOpti +local BeamBuildEmtBp = '/effects/emitters/build_beam_02_emit.bp' +local CybranBuildSparks01 = EffectTemplate.CybranBuildSparks01 +local CybranBuildFlash01 = EffectTemplate.CybranBuildFlash01 + +--- Creates the beams and welding points of the builder and its bots. The +-- bots share the welding point which each other, as does the builder with +-- itself. +-- @param builder A builder with builder.BuildEffectBones set. +-- @param bots The bots of the builder. +-- @param unitBeingBuilt The unit that we're building. +-- @param buildEffectsBag The bag that we use to store / trash all effects. +-- @param stationary Whether or not the builder is a building. +function CreateCybranBuildBeams(builder, bots, unitBeingBuilt, buildEffectsBag, stationary) + + -- delay slightly for dramatic effect + WaitTicks(2 + Random(1, 4)) + + -- early out - make sure everything is still alive + if builder.Dead or unitBeingBuilt.Dead then + return + end + + -- initialise + local army = builder.Army + local trash = builder.Trash + local origin = EntityGetPosition(unitBeingBuilt) + + -- create beam entities and their emiters + local beamEndBuilder + + -- hives do not have beams from builders + if not stationary then + beamEndBuilder = builder.BeamEndBuilder or Entity() + builder.BeamEndBuilder = beamEndBuilder + Warp(beamEndBuilder, origin) + TrashBagAdd(buildEffectsBag, CreateEmitterOnEntity(beamEndBuilder, army, CybranBuildSparks01)) + TrashBagAdd(buildEffectsBag, CreateEmitterOnEntity(beamEndBuilder, army, CybranBuildFlash01)) + TrashBagAdd(trash, beamEndBuilder) + end + + local beamEndBots = builder.BeamEndBots or Entity() + builder.BeamEndBots = beamEndBots + Warp(beamEndBots, origin) + TrashBagAdd(buildEffectsBag, CreateEmitterOnEntity(beamEndBots, army, CybranBuildSparks01)) + TrashBagAdd(buildEffectsBag, CreateEmitterOnEntity(beamEndBots, army, CybranBuildFlash01)) + TrashBagAdd(trash, beamEndBots) + + -- create a beam from each build effect bone of the builder + if not stationary then + if builder.BuildEffectBones then + for k, bone in builder.BuildEffectBones do + TrashBagAdd(buildEffectsBag, AttachBeamEntityToEntity(builder, bone, beamEndBuilder, -1, army, BeamBuildEmtBp)) + end + end + end + + -- create a beam from each bot of the builder + if bots then + for k, bot in bots do + local beam = CybranBuildBotBeams[k] or BeamBuildEmtBp + TrashBagAdd(buildEffectsBag, AttachBeamEntityToEntity(bot, "Muzzle_01", beamEndBots, -1, army, beam)) + end + end + + -- make the end entity move around + local ox, oy, oz = origin[1], origin[2], origin[3] + local blueprint = unitBeingBuilt:GetBlueprint() + + -- cache values for computing random offsets + local vc = VectorCached + local cy = blueprint.CollisionOffsetY or 0 + local sx, sy, sz = blueprint.SizeX, blueprint.SizeY, blueprint.SizeZ + local r1, r2, r3 + + -- perform the build animation + while not (builder.Dead or unitBeingBuilt.Dead) do + + -- get a few random numbers + r1, r2, r3 = Random(), Random(), Random() + + -- get a new location for builder + if not stationary then + vc[1] = ox + r1 * sx - (sx * 0.5) + vc[2] = oy + r2 * sy + cy + vc[3] = oz + r3 * sz - (sz * 0.5) + Warp(beamEndBuilder, vc) + end + + -- get a new location for bots + vc[1] = ox + r2 * sx - (sx * 0.5) + vc[2] = oy + r3 * sy + cy + vc[3] = oz + (1 - r1) * sz - (sz * 0.5) + Warp(beamEndBots, vc) + + -- skip a few ticks to make the effect work better + WaitTicks(3) + end +end + +--- Creates tracker beams between the builder and its build bots. The +-- bots keep the tracker in their trashbag. +-- @param builder The builder / tracking entity of the build bots. +-- @param buildBones The bones to use as the origin of the beams. +-- @param buildBots The build bots that we're tracking. +-- @param total The number of build bots / bones. The 1st bone will track the 1st bot, etc. +function CreateCybranEngineerBuildEffects(builder, buildBones, buildBots, total) + local army = builder.Army + for k = 1, total do + local bone = buildBones[k] + local bot = buildBots[k] + if bone and bot and not bot.Tracked then + bot.Tracked = true + TrashBagAdd(bot.Trash, AttachBeamEntityToEntity(builder, bone, bot, -1, army, '/effects/emitters/build_beam_03_emit.bp')) + end + end +end \ No newline at end of file diff --git a/lua/cybranunits.lua b/lua/cybranunits.lua index 41e199da60..930d01e68c 100644 --- a/lua/cybranunits.lua +++ b/lua/cybranunits.lua @@ -25,13 +25,340 @@ local CommandUnit = DefaultUnitsFile.CommandUnit local Util = import('utilities.lua') local EffectTemplate = import('/lua/EffectTemplates.lua') local EffectUtil = import('EffectUtilities.lua') -local CreateCybranBuildBeams = EffectUtil.CreateCybranBuildBeams +local CreateCybranBuildBeams = false + +-- upvalued effect utility functions for performance +local SpawnBuildBotsOpti = EffectUtil.SpawnBuildBotsOpti +local CreateCybranEngineerBuildEffectsOpti = EffectUtil.CreateCybranEngineerBuildEffectsOpti +local CreateCybranBuildBeamsOpti = EffectUtil.CreateCybranBuildBeamsOpti + +-- upvalued globals for performance +local Random = Random +local VDist2Sq = VDist2Sq +local ArmyBrains = ArmyBrains +local KillThread = KillThread +local ForkThread = ForkThread +local WaitTicks = coroutine.yield + +local IssueMove = IssueMove +local IssueClearCommands = IssueClearCommands + +-- upvalued moho functions for performance +local EntityFunctions = _G.moho.entity_methods +local EntityDestroy = EntityFunctions.Destroy +local EntityGetPosition = EntityFunctions.GetPosition +local EntityGetPositionXYZ = EntityFunctions.GetPositionXYZ +EntityFunctions = nil + +local UnitFunctions = _G.moho.unit_methods +local UnitSetConsumptionActive = UnitFunctions.SetConsumptionActive +UnitFunctions = nil + +-- upvalued trashbag functions for performance +local TrashBag = _G.TrashBag +local TrashBagAdd = TrashBag.Add + +--- A class to managing the build bots. Make sure to call all the relevant functions. +CConstructionTemplate = Class() { + + --- Prepares the values required to support bots + OnCreate = function(self) + -- cache the total amount of drones + self.BuildBotTotal = self:GetBlueprint().BuildBotTotal or math.min(math.ceil((10 + builder:GetBuildRate()) / 15), 10) + end, + + --- When dying, destroy everything. + DestroyAllBuildEffects = function(self) + -- make sure we're not dead (then bots are destroyed by trashbag) + if self.Dead then + return + end + + -- check if we ever had bots + local bots = self.BuildBots + if bots then + -- check if we still have active bots + local buildBotCount = self.BuildBotsNext - 1 + if buildBotCount > 0 then + -- return the active bots + local returnBotsThreadInstance = ForkThread(self.ReturnBotsThread, self, 0.2) + TrashBagAdd(self.Trash, returnBotsThreadInstance) + + -- save thread so that we can kill it if the bots suddenly get an additional task. + self.ReturnBotsThreadInstance = returnBotsThreadInstance + end + end + end, + + --- When stopping to build, send the bots back after a bit. + StopBuildingEffects = function(self, built) + -- make sure we're not dead (then bots are destroyed by trashbag) + if self.Dead then + return + end + + -- check if we had bots + local bots = self.BuildBots + if bots then + + -- check if we still have active bots + local buildBotCount = self.BuildBotsNext - 1 + if buildBotCount > 0 then + -- return the active bots + local returnBotsThreadInstance = ForkThread(self.ReturnBotsThread, self, 0.2) + TrashBagAdd(self.Trash, returnBotsThreadInstance) + + -- save thread so that we can kill it if the bots suddenly get an additional task. + self.ReturnBotsThreadInstance = returnBotsThreadInstance + end + end + end, + + --- When pausing, send the bots back after a bit. + OnPaused = function(self, delay) + -- delay until they move back + delay = delay or 0.5 + 2 * Random() + + -- make sure thread is not running already + if self.ReturnBotsThreadInstance then + return + end + + -- check if we have bots + local bots = self.BuildBots + if bots then + local buildBotCount = self.BuildBotsNext - 1 + if buildBotCount > 0 then + -- return the active bots + local returnBotsThreadInstance = ForkThread(self.ReturnBotsThread, self, 0.2) + TrashBagAdd(self.Trash, returnBotsThreadInstance) + + -- save thread so that we can kill it if the bots suddenly get an additional task. + self.ReturnBotsThreadInstance = returnBotsThreadInstance + end + end + end, + + --- When making build effects, try and make the bots. + CreateBuildEffects = function(self, unitBeingBuilt, order, stationary) + + -- Prevent an AI from (ab)using the bots for other purposes than building + local builderArmy = self.Army + local unitBeingBuiltArmy = unitBeingBuilt.Army + if builderArmy == unitBeingBuiltArmy or ArmyBrains[builderArmy].BrainType == "Human" then + SpawnBuildBotsOpti(self) + if stationary then + CreateCybranEngineerBuildEffectsOpti(self, self.BuildEffectBones, self.BuildBots, self.BuildBotTotal, self.BuildEffectsBag) + end + CreateCybranBuildBeamsOpti(self, self.BuildBots, unitBeingBuilt, self.BuildEffectsBag, stationary) + end + end, + + --- When destroyed, destroy the bots too. + OnDestroy = function(self) + -- destroy bots if we have them + if self.BuildBotsNext > 1 then + + -- doesn't need to trashbag: threads that are not infinite and stop get found by the garbage collector + ForkThread(self.DestroyBotsThread, self, self.BuildBots, self.BuildBotTotal) + end + end, + + --- Destroys all the bots of a builder. Assumes the bots exist. + -- @param self The builder in question. + -- @param bots The bots of the builder. + -- @param count The maximum number of bots. + DestroyBotsThread = function(self, bots, count) + + -- kill potential return thread + if self.ReturnBotsThreadInstance then + KillThread(self.ReturnBotsThreadInstance) + self.ReturnBotsThreadInstance = nil + end + + -- slowly kill the drones + for k = 1, count do + local bot = bots[k] + if bot and not bot.Dead then + WaitTicks(Random(1, 10) + 1) + if bot and not bot.Dead then + bot:Kill() + end + end + end + end, + + --- Destroys all the bots of a builder. Assumes the bots exist. + -- @param self The builder in question. + -- @param delay The delay until the bots decide to return. + ReturnBotsThread = function(self, delay) + + -- hold up a bit in case we just switch target + WaitSeconds(delay) + + -- cache for speed + local bots = self.BuildBots + local buildBotTotal = self.BuildBotTotal + local threshold = delay + + -- lower bot elevation + for k = 1, buildBotTotal do + local bot = bots[k] + if bot and not bot.Dead then + bot:SetElevation(1) + end + end + + -- keep sending drones back + while self.BuildBotsNext > 1 do + + -- instruct bots to move back + IssueClearCommands(bots) + IssueMove(bots, EntityGetPosition(self)) + + -- check if they're there yet + for l = 1, 4 do + WaitTicks(3) + + local tx, ty, tz = EntityGetPositionXYZ(self) + for k = 1, buildBotTotal do + local bot = bots[k] + if bot and not bot.Dead then + local bx, by, bz = EntityGetPositionXYZ(bot) + local distance = VDist2Sq(tx, tz, bx, bz) + + -- if close enough, just remove it + threshold = threshold + 0.1 + if distance < threshold then + -- destroy bot without effects + EntityDestroy(bot) + + -- move destroyed bots up + for m = k, buildBotTotal do + bots[m] = bots[m + 1] + end + end + end + end + end + end + + -- clean up state + self.ReturnBotsThreadInstance = nil + self.BeamEndBuilder = nil + self.BeamEndBots = nil + end, +} + +--- The build bot class for drones. It removes a lot of +-- the basic functionality of a unit to save on performance. +CBuildBotUnit = Class(AirUnit) { + + -- Keep track of the builder that made the bot + SpawnedBy = false, + + -- do not perform the logic of these functions + OnMotionHorzEventChange = function(self, new, old) end, -- called a million times, keep it simple + OnMotionVertEventChange = function(self, new, old) end, + OnLayerChange = function(self, new, old) end, + + CreateBuildEffects = function(self, unitBeingBuilt, order) end, -- do not make build effects (engineer / builder takes care of that) + StartBuildingEffects = function(self, built, order) end, + CreateBuildEffects = function(self, built, order) end, + StopBuildingEffects = function(self, built) end, + + OnBuildProgress = function(self, unit, oldProg, newProg) end, -- do not keep track of progress + OnStopBuild = function(self, unitBeingBuilt) end, + + EnableUnitIntel = function(self, disabler, intel) end, -- do not bother doing intel + DisableUnitIntel = function(self, disabler, intel) end, + OnIntelEnabled = function(self) end, + OnIntelDisabled = function(self) end, + ShouldWatchIntel = function(self) end, + IntelWatchThread = function(self) end, + + AddDetectedByHook = function(self, hook) end, -- do not bother keeping track of collision beams + RemoveDetectedByHook = function(self, hook) end, + OnDetectedBy = function(self, index) end, + + CreateWreckage = function (self, overkillRatio) end, -- don't make wreckage + UpdateConsumptionValues = function(self) end, -- avoids junk in resource overlay + ShouldUseVetSystem = function(self) return false end, -- never use vet + OnStopBeingBuilt = function(self, builder, layer) end, -- do not perform this logic when being made + OnStartRepair = function(self, unit) end, -- do not run this logic + OnKilled = function(self) end, -- just fall out of the sky + + OnCollisionCheck = function(self, other, firingWeapon) return false end, -- we never collide + OnCollisionCheckWeapon = function(self, firingWeapon) return false end, + + OnPrepareArmToBuild = function(self) end, + + OnStartBuilderTracking = function(self) end, -- don't track anything + OnStopBuilderTracking = function(self) end, + + DestroyUnit = function(self) end, -- prevent misscalls + DestroyAllTrashBags = function(self) end, + + OnStartSacrifice = function(self, target_unit) end, + OnStopSacrifice = function(self, target_unit) end, + + -- only initialise what we need + OnPreCreate = function(self) + self.Trash = TrashBag() + end, + + -- only initialise what we need + OnCreate = function(self) + -- prevent drone from consuming anything and remove collision shape + UnitSetConsumptionActive(self, false) + end, + + -- short-cut when being destroyed + OnDestroy = function(self) + self.Dead = true + self.Trash:Destroy() + self.SpawnedBy.BuildBotsNext = self.SpawnedBy.BuildBotsNext - 1 + end, + + Kill = function(self) + -- make it go boom + if self.PlayDestructionEffects then + self:CreateDestructionEffects(1.0) + end + + self:Destroy() + end, + + -- prevent this type of operations + OnStartCapture = function(self, target) + IssueStop({self}) -- You can't capture! + end, + + OnStartReclaim = function(self, target) + IssueStop({self}) -- You can't reclaim! + end, + + -- short cut - just get destroyed + OnImpact = function(self, with) + + -- make it go boom + if self.PlayDestructionEffects then + self:CreateDestructionEffects(1.0) + end + + -- make it sound boom + self:PlayUnitSound('Destroyed') + + -- make it gone + self:Destroy() + end, +} -- AIR FACTORY STRUCTURES CAirFactoryUnit = Class(AirFactoryUnit) { CreateBuildEffects = function(self, unitBeingBuilt, order) if not unitBeingBuilt then return end - WaitSeconds(0.1) + WaitTicks(2) EffectUtil.CreateCybranFactoryBuildEffects(self, unitBeingBuilt, self:GetBlueprint().General.BuildBones, self.BuildEffectsBag) end, @@ -76,7 +403,13 @@ CAirUnit = Class(AirUnit) {} CConcreteStructureUnit = Class(ConcreteStructureUnit) {} -- CONSTRUCTION UNITS -CConstructionUnit = Class(ConstructionUnit){ +CConstructionUnit = Class(ConstructionUnit, CConstructionTemplate){ + + OnCreate = function(self) + ConstructionUnit.OnCreate(self) + CConstructionTemplate.OnCreate(self) + end, + OnStopBeingBuilt = function(self, builder, layer) ConstructionUnit.OnStopBeingBuilt(self, builder, layer) -- If created with F2 on land, then play the transform anim. @@ -85,6 +418,30 @@ CConstructionUnit = Class(ConstructionUnit){ end end, + DestroyAllBuildEffects = function(self) + ConstructionUnit.DestroyAllBuildEffects(self) + CConstructionTemplate.DestroyAllBuildEffects(self) + end, + + StopBuildingEffects = function(self, built) + ConstructionUnit.StopBuildingEffects(self, built) + CConstructionTemplate.StopBuildingEffects(self, built) + end, + + OnPaused = function(self) + ConstructionUnit.OnPaused(self) + CConstructionTemplate.OnPaused(self) + end, + + CreateBuildEffects = function(self, unitBeingBuilt, order) + CConstructionTemplate.CreateBuildEffects(self, unitBeingBuilt, order) + end, + + OnDestroy = function(self) + ConstructionUnit.OnDestroy(self) + CConstructionTemplate.OnDestroy(self) + end, + LayerChangeTrigger = function(self, new, old) if self:GetBlueprint().Display.AnimationWater then if self.TerrainLayerTransitionThread then @@ -115,11 +472,6 @@ CConstructionUnit = Class(ConstructionUnit){ self.TransformManipulator = nil end end, - - CreateBuildEffects = function(self, unitBeingBuilt, order) - local buildbots = EffectUtil.SpawnBuildBots(self, unitBeingBuilt, self.BuildEffectsBag) - EffectUtil.CreateCybranBuildBeams(self, unitBeingBuilt, self.BuildEffectBones, self.BuildEffectsBag) - end, } -- ENERGY CREATION UNITS @@ -334,10 +686,12 @@ CConstructionEggUnit = Class(CStructureUnit) { -- TODO: This should be made more general and put in defaultunits.lua in case other factions get similar buildings -- CConstructionStructureUnit -CConstructionStructureUnit = Class(CStructureUnit) { +CConstructionStructureUnit = Class(CStructureUnit, CConstructionTemplate) { OnCreate = function(self) - -- Structure stuff + + -- Initialize the class CStructureUnit.OnCreate(self) + CConstructionTemplate.OnCreate(self) local bp = self:GetBlueprint() @@ -361,14 +715,50 @@ CConstructionStructureUnit = Class(CStructureUnit) { self.BuildingUnit = false end, + DestroyAllBuildEffects = function(self) + CStructureUnit.DestroyAllBuildEffects(self) + CConstructionTemplate.DestroyAllBuildEffects(self) + end, + + StopBuildingEffects = function(self, built) + CStructureUnit.StopBuildingEffects(self, built) + CConstructionTemplate.StopBuildingEffects(self, built) + end, + + OnPaused = function(self) + CStructureUnit.OnPaused(self) + CStructureUnit.StopBuildingEffects(self, self.UnitBeingBuilt) + CConstructionTemplate.OnPaused(self, 0) + + self.AnimationManipulator:SetRate(-0.25) + end, + + OnUnpaused = function(self) + CStructureUnit.OnUnpaused(self) + CStructureUnit.StartBuildingEffects(self, self.UnitBeingBuilt, self.UnitBuildOrder) + + self.AnimationManipulator:SetRate(1) + end, + + CreateBuildEffects = function(self, unitBeingBuilt, order) + CConstructionTemplate.CreateBuildEffects(self, self.UnitBeingBuilt, self.UnitBuildOrder, true) + end, + + OnDestroy = function(self) + CStructureUnit.OnDestroy(self) + CConstructionTemplate.OnDestroy(self) + end, + OnStartBuild = function(self, unitBeingBuilt, order) - self.UnitBeingBuilt = unitBeingBuilt - self.UnitBuildOrder = order - self.BuildingUnit = true + CStructureUnit.OnStartBuild(self, unitBeingBuilt, order) + -- play animation of the hive opening self.AnimationManipulator:PlayAnim(self.BuildingOpenAnim, false):SetRate(1) - CStructureUnit.OnStartBuild(self, unitBeingBuilt, order) + -- keep track of who we are building + self.UnitBeingBuilt = unitBeingBuilt + self.UnitBuildOrder = order + self.BuildingUnit = true end, OnStopBeingBuilt = function(self, builder, layer) @@ -380,41 +770,17 @@ CConstructionStructureUnit = Class(CStructureUnit) { end end, - CreateBuildEffects = function(self, unitBeingBuilt, order) - local buildbots = EffectUtil.SpawnBuildBots(self, unitBeingBuilt, table.getn(self.BuildEffectBones), self.BuildEffectsBag) - if buildbots then - EffectUtil.CreateCybranEngineerBuildEffects(self, self.BuildEffectBones, buildbots, self.BuildEffectsBag) - else - EffectUtil.CreateCybranBuildBeams(self, unitBeingBuilt, self.BuildEffectBones, self.BuildEffectsBag) - end - end, - -- This will only be called if not in StructureUnit's upgrade state OnStopBuild = function(self, unitBeingBuilt) CStructureUnit.OnStopBuild(self, unitBeingBuilt) + -- revert animation + self.AnimationManipulator:SetRate(-0.25) + + -- lose track of who we are building self.UnitBeingBuilt = nil self.UnitBuildOrder = nil self.BuildingUnit = false - - self.AnimationManipulator:SetRate(-1) - end, - - OnPaused = function(self) - -- When factory is paused take some action - self:StopUnitAmbientSound('ConstructLoop') - CStructureUnit.OnPaused(self) - if self.BuildingUnit then - CStructureUnit.StopBuildingEffects(self, self.UnitBeingBuilt) - end - end, - - OnUnpaused = function(self) - if self.BuildingUnit then - self:PlayUnitAmbientSound('ConstructLoop') - CStructureUnit.StartBuildingEffects(self, self.UnitBeingBuilt, self.UnitBuildOrder) - end - CStructureUnit.OnUnpaused(self) end, OnProductionPaused = function(self) @@ -431,14 +797,6 @@ CConstructionStructureUnit = Class(CStructureUnit) { self:SetProductionActive(true) end, - StartBuildingEffects = function(self, unitBeingBuilt, order) - CStructureUnit.StartBuildingEffects(self, unitBeingBuilt, order) - end, - - StopBuildingEffects = function(self, unitBeingBuilt) - CStructureUnit.StopBuildingEffects(self, unitBeingBuilt) - end, - OnStopBuilderTracking = function(self) CStructureUnit.OnStopBuilderTracking(self) @@ -472,7 +830,37 @@ CConstructionStructureUnit = Class(CStructureUnit) { -- CCommandUnit -- Cybran Command Units (ACU and SCU) have stealth and cloak enhancements, toggles can be handled in one class -CCommandUnit = Class(CommandUnit) { +CCommandUnit = Class(CommandUnit, CConstructionTemplate) { + + OnCreate = function(self) + CommandUnit.OnCreate(self) + CConstructionTemplate.OnCreate(self) + end, + + DestroyAllBuildEffects = function(self) + CommandUnit.DestroyAllBuildEffects(self) + CConstructionTemplate.DestroyAllBuildEffects(self) + end, + + StopBuildingEffects = function(self, built) + CommandUnit.StopBuildingEffects(self, built) + CConstructionTemplate.StopBuildingEffects(self, built) + end, + + OnPaused = function(self) + CommandUnit.OnPaused(self) + CConstructionTemplate.OnPaused(self) + end, + + CreateBuildEffects = function(self, unitBeingBuilt, order) + CConstructionTemplate.CreateBuildEffects(self, unitBeingBuilt, order) + end, + + OnDestroy = function(self) + CommandUnit.OnDestroy(self) + CConstructionTemplate.OnDestroy(self) + end, + OnScriptBitSet = function(self, bit) if bit == 8 then -- Cloak toggle self:StopUnitAmbientSound('ActiveLoop') diff --git a/lua/sim/Unit.lua b/lua/sim/Unit.lua index 6975ef7cf8..ca8830e7b5 100644 --- a/lua/sim/Unit.lua +++ b/lua/sim/Unit.lua @@ -2629,11 +2629,7 @@ Unit = Class(moho.unit_methods) { StopBuildingEffects = function(self, built) self.BuildEffectsBag:Destroy() - if self.buildBots then - for _, b in self.buildBots do - ChangeState(b, b.IdleState) - end - end + end, OnStartSacrifice = function(self, target_unit) diff --git a/units/URA0001/URA0001_Albedo.dds b/units/URA0001/URA0001_Albedo.dds new file mode 100644 index 0000000000..f7699bc5f3 Binary files /dev/null and b/units/URA0001/URA0001_Albedo.dds differ diff --git a/units/URA0001/URA0001_SpecTeam.dds b/units/URA0001/URA0001_SpecTeam.dds new file mode 100644 index 0000000000..64f6912487 Binary files /dev/null and b/units/URA0001/URA0001_SpecTeam.dds differ diff --git a/units/URA0001/URA0001_lod0.scm b/units/URA0001/URA0001_lod0.scm new file mode 100644 index 0000000000..cff10e45db Binary files /dev/null and b/units/URA0001/URA0001_lod0.scm differ diff --git a/units/URA0001/URA0001_script.lua b/units/URA0001/URA0001_script.lua index 9a64672f5b..cab2a932d8 100644 --- a/units/URA0001/URA0001_script.lua +++ b/units/URA0001/URA0001_script.lua @@ -4,113 +4,32 @@ -- Summary : Cybran Builder bot units -- Copyright © 2006 Gas Powered Games, Inc. All rights reserved. ----------------------------------------------------------------- -local CAirUnit = import('/lua/cybranunits.lua').CAirUnit -local CreateCybranBuildBeams = import('/lua/EffectUtilities.lua').CreateCybranBuildBeams -local EffectUtil = import('/lua/EffectUtilities.lua') -local EffectTemplate = import('/lua/EffectTemplates.lua') -URA0001 = Class(CAirUnit) { - spawnedBy = nil, +-- upvalued globals for performance +local CreateBuilderArmController = CreateBuilderArmController - OnCreate = function(self) - CAirUnit.OnCreate(self) - self.BuildArmManipulator = CreateBuilderArmController(self, 'URA0001' , 'URA0001', 0) - self.BuildArmManipulator:SetAimingArc(-180, 180, 360, -90, 90, 360) - self.BuildArmManipulator:SetPrecedence(5) - self.Trash:Add(self.BuildArmManipulator) - self:SetConsumptionActive(false) - end, - - CreateBuildEffects = function(self, unitBeingBuilt, order) - self.BuildEffectsBag:Add(AttachBeamEntityToEntity(self, 'Muzzle_03', self, 'Muzzle_01', self.Army, '/effects/emitters/build_beam_02_emit.bp')) - self.BuildEffectsBag:Add(AttachBeamEntityToEntity(self, 'Muzzle_03', self, 'Muzzle_02', self.Army, '/effects/emitters/build_beam_02_emit.bp')) - CreateCybranBuildBeams(self, unitBeingBuilt, {'Muzzle_03',}, self.BuildEffectsBag) - end, - - OnStartCapture = function(self, target) - IssueStop({self}) -- You can't capture! - end, - - OnStartReclaim = function(self, target) - IssueStop({self}) -- You can't reclaim! - end, - - -- We never want to waste effort sinking these - ShallSink = function(self) - return false - end, +-- upvalued moho functions for performance +local BuilderArmManipulator = _G.moho.BuilderArmManipulator +local BuilderArmManipulatorSetAimingArc = BuilderArmManipulator.SetAimingArc +local BuilderArmManipulatorSetPrecedence = BuilderArmManipulator.SetPrecedence +BuilderArmManipulator = nil - -- Removed all collider related stuff - OnImpact = function(self, with) - if with == 'Water' then - self:PlayUnitSound('AirUnitWaterImpact') - EffectUtil.CreateEffects(self, self.Army, EffectTemplate.DefaultProjectileWaterImpact) - end +-- upvalued trashbag functions for performance +local TrashBag = _G.TrashBag +local TrashBagAdd = TrashBag.Add - self:ForkThread(self.DeathThread, self.OverKillRatio) - end, +local CBuildBotUnit = import('/lua/cybranunits.lua').CBuildBotUnit +URA0001 = Class(CBuildBotUnit) { - OnStopBuild = function(self, unitBeingBuilt) - CAirUnit.OnStopBuild(self, unitBeingBuilt) - ChangeState(self, self.IdleState) - end, - - -- Don't explode when killed, merely fall out of the sky. - OnKilled = function(self) - self:StopBuildingEffects() - end, - - -- Don't cycle intel! - EnableUnitIntel = function(self, disabler, intel) - end, + OnCreate = function(self) + CBuildBotUnit.OnCreate(self) - -- Don't make wreckage - CreateWreckage = function (self, overkillRatio) - overkillRatio = 1.1 - CAirUnit.CreateWreckage(self, overkillRatio) + -- make the drone aim for the target + local BuildArmManipulator = CreateBuilderArmController(self, 'URA0001' , 'URA0001', 0) + BuilderArmManipulatorSetAimingArc(BuildArmManipulator, -180, 180, 360, -90, 90, 360) + BuilderArmManipulatorSetPrecedence(BuildArmManipulator, 5) + TrashBagAdd(self.Trash, BuildArmManipulator) end, - -- Prevent the unit from reporting consumption values (avoids junk in the resource overlay) - UpdateConsumptionValues = function(self) end, - - IdleState = State { - Main = function(self) - IssueClearCommands({self}) - IssueMove({self}, self:GetPosition()) - WaitSeconds(0.5) - IssueMove({self}, self.spawnedBy:GetPosition()) - - local delay = 0.1 - local wait = 0 - - while wait < 4 do - local pos = self:GetPosition() - local bpos = self.spawnedBy:GetPosition() - - if VDist2(pos[1], pos[3], bpos[1], bpos[3]) < 1 then - break - end - - wait = wait + delay - WaitSeconds(delay) - end - - self:Destroy() - end, - }, - - BuildState = State { - Main = function(self) - local focus = self.spawnedBy:GetFocusUnit() - - if not focus or focus:BeenDestroyed() or focus.Dead then - ChangeState(self, self.IdleState) - end - - IssueClearCommands({self}) - IssueGuard({self}, focus) - end, - }, } - TypeClass = URA0001 diff --git a/units/URA0001/URA0001_unit.bp b/units/URA0001/URA0001_unit.bp index c11159cb02..7d898dc976 100644 --- a/units/URA0001/URA0001_unit.bp +++ b/units/URA0001/URA0001_unit.bp @@ -6,11 +6,11 @@ UnitBlueprint { CirclingDirChangeFrequencySec = 1, CirclingElevationChangeRatio = 0.5, CirclingRadiusChangeMaxRatio = 0.9, - CirclingRadiusChangeMinRatio = 0.6, - CirclingRadiusVsAirMult = 0.66, + CirclingRadiusChangeMinRatio = 0.5, + CirclingRadiusVsAirMult = 0.34, CirclingTurnMult = 3, KLift = 3, - KLiftDamping = 1, + KLiftDamping = 2, KMove = 4, KMoveDamping = 1, KTurn = 4, @@ -22,26 +22,23 @@ UnitBlueprint { Winged = false, }, Categories = { + -- to allow it to build / repair when assist 'CONSTRUCTION', 'ENGINEER', - 'POD', 'REPAIR', - 'UNTARGETABLE', + + -- for unit restrictions + 'POD', + + -- for UI 'NOFORMATION', - 'INSIGNIFICANTUNIT', - 'VISIBLETORECON' - }, - Defense = { - AirThreatLevel = 0, - ArmorType = 'Normal', - EconomyThreatLevel = 0, - Health = 30, - MaxHealth = 30, - RegenRate = 0, - SubThreatLevel = 0, - SurfaceThreatLevel = 0, + + -- makes it a dummy-isch unit + 'UNTARGETABLE', + 'INVULNERABLE', + 'UNSPAWNABLE', + 'UNSELECTABLE', }, - Description = 'Build Bot Effect', Display = { Mesh = { IconFadeInZoom = 2000, @@ -58,7 +55,7 @@ UnitBlueprint { }, PlaceholderMeshName = 'URA0001', SpawnRandomRotation = true, - UniformScale = 0.14, + UniformScale = 0.12, }, Economy = { BuildCostEnergy = 0, @@ -104,13 +101,6 @@ UnitBlueprint { Intel = { VisionRadius = 0, }, - Interface = { - HelpText = 'Build Bot Effect', - }, - LifeBarHeight = 0.075, - LifeBarOffset = 0.25, - LifeBarRender = false, - LifeBarSize = 0.01, Physics = { BankingSlope = 0.5, BuildOnLayerCaps = { @@ -122,9 +112,9 @@ UnitBlueprint { LAYER_Water = false, }, DragCoefficient = 0.2, - Elevation = 3, + Elevation = 2, MaxAcceleration = 10.5, - MaxSpeed = 20.5, + MaxSpeed = 10.5, MaxSpeedReverse = 0, MaxSteerForce = 0, MinSpeedPercent = 0, @@ -134,23 +124,7 @@ UnitBlueprint { TurnRadius = 360, TurnRate = 180, }, - SelectionThickness = 0.2, - SizeX = 0.25, - SizeY = 0.25, - SizeZ = 0.25, - StrategicIconSortPriority = 105, - Wreckage = { - Blueprint = '/props/DefaultWreckage/DefaultWreckage_prop.bp', - EnergyMult = 0, - HealthMult = 0.9, - MassMult = 0.9, - ReclaimTimeMultiplier = 1, - WreckageLayers = { - Air = false, - Land = true, - Seabed = false, - Sub = false, - Water = false, - }, - }, -} + SizeX = 0.01, + SizeY = 0.01, + SizeZ = 0.01, +} \ No newline at end of file diff --git a/units/URA0002/URA0002_lod0.scm b/units/URA0002/URA0002_lod0.scm new file mode 100644 index 0000000000..55ae882548 Binary files /dev/null and b/units/URA0002/URA0002_lod0.scm differ diff --git a/units/URA0002/URA0002_script.lua b/units/URA0002/URA0002_script.lua new file mode 100644 index 0000000000..408c0abc8d --- /dev/null +++ b/units/URA0002/URA0002_script.lua @@ -0,0 +1,35 @@ +----------------------------------------------------------------- +-- File : /cdimage/units/URA0001/URA0001_script.lua +-- Author(s): Gordon Duclos +-- Summary : Cybran Builder bot units +-- Copyright © 2006 Gas Powered Games, Inc. All rights reserved. +----------------------------------------------------------------- + +-- upvalued globals for performance +local CreateBuilderArmController = CreateBuilderArmController + +-- upvalued moho functions for performance +local BuilderArmManipulator = _G.moho.BuilderArmManipulator +local BuilderArmManipulatorSetAimingArc = BuilderArmManipulator.SetAimingArc +local BuilderArmManipulatorSetPrecedence = BuilderArmManipulator.SetPrecedence +BuilderArmManipulator = nil + +-- upvalued trashbag functions for performance +local TrashBag = _G.TrashBag +local TrashBagAdd = TrashBag.Add + +local CBuildBotUnit = import('/lua/cybranunits.lua').CBuildBotUnit +URA0002 = Class(CBuildBotUnit) { + + OnCreate = function(self) + CBuildBotUnit.OnCreate(self) + + -- make the drone aim for the target + local BuildArmManipulator = CreateBuilderArmController(self, 'URA0002' , 'URA0002', 0) + BuilderArmManipulatorSetAimingArc(BuildArmManipulator, -180, 180, 360, -90, 90, 360) + BuilderArmManipulatorSetPrecedence(BuildArmManipulator, 5) + TrashBagAdd(self.Trash, BuildArmManipulator) + end, + +} +TypeClass = URA0002 diff --git a/units/URA0002/URA0002_unit.bp b/units/URA0002/URA0002_unit.bp new file mode 100644 index 0000000000..01780cfdcf --- /dev/null +++ b/units/URA0002/URA0002_unit.bp @@ -0,0 +1,130 @@ +UnitBlueprint { + Air = { + BankFactor = 0.1, + BankForward = false, + CanFly = true, + CirclingDirChangeFrequencySec = 1.5, + CirclingElevationChangeRatio = 0.5, + CirclingRadiusChangeMaxRatio = 1.1, + CirclingRadiusChangeMinRatio = 0.6, + CirclingRadiusVsAirMult = 0.56, + CirclingTurnMult = 3, + KLift = 3, + KLiftDamping = 2, + KMove = 4, + KMoveDamping = 1, + KTurn = 4, + KTurnDamping = 2, + LiftFactor = 7, + MaxAirspeed = 8, + MinAirspeed = 8, + StartTurnDistance = 5, + Winged = false, + }, + Categories = { + -- to allow it to build / repair when assist + 'CONSTRUCTION', + 'ENGINEER', + 'REPAIR', + + -- for unit restrictions + 'POD', + + -- for UI + 'NOFORMATION', + + -- makes it a dummy-isch unit + 'UNTARGETABLE', + 'INVULNERABLE', + 'UNSPAWNABLE', + 'UNSELECTABLE', + }, + Display = { + Mesh = { + IconFadeInZoom = 2000, + LODs = { + { + AlbedoName = '/Units/URA0001/URA0001_Albedo.dds', + LODCutoff = 215, + MeshName = '/Units/URA0002/URA0002_LOD0.scm', + NormalsName = '/UNITS/URA0001/URA0001_NormalsTS.dds', + ShaderName = 'Insect', + SpecularName = '/Units/URA0001/URA0001_SpecTeam.dds', + }, + }, + }, + PlaceholderMeshName = 'URA0001', + SpawnRandomRotation = true, + UniformScale = 0.13, + }, + Economy = { + BuildCostEnergy = 0, + BuildCostMass = 0, + BuildRate = 0.0001, + BuildTime = 0, + BuildableCategory = { + 'BUILTBYTIER1ENGINEER CYBRAN', + }, + ConsumptionPerSecondEnergy = 0, + ConsumptionPerSecondMass = 0, + MaxBuildDistance = 100, + }, + Footprint = { + MaxSlope = 0.25, + SizeX = 1, + SizeZ = 1, + }, + General = { + CapCost = 0, + Category = 'Construction', + Classification = 'RULEUC_Engineer', + CommandCaps = { + RULEUCC_Attack = false, + RULEUCC_CallTransport = true, + RULEUCC_Capture = false, + RULEUCC_Guard = true, + RULEUCC_Move = true, + RULEUCC_Nuke = false, + RULEUCC_Patrol = false, + RULEUCC_Reclaim = true, + RULEUCC_Repair = true, + RULEUCC_RetaliateToggle = true, + RULEUCC_Stop = true, + RULEUCC_Transport = false, + }, + FactionName = 'Cybran', + Icon = 'air', + SelectionPriority = 3, + TechLevel = 'RULEUTL_Basic', + UnitWeight = 1, + }, + Intel = { + VisionRadius = 0, + }, + Physics = { + BankingSlope = 0.5, + BuildOnLayerCaps = { + LAYER_Air = true, + LAYER_Land = false, + LAYER_Orbit = false, + LAYER_Seabed = false, + LAYER_Sub = false, + LAYER_Water = false, + }, + DragCoefficient = 0.2, + Elevation = 3.5, + MaxAcceleration = 10.5, + MaxSpeed = 10.5, + MaxSpeedReverse = 0, + MaxSteerForce = 0, + MinSpeedPercent = 0, + MotionType = 'RULEUMT_Air', + RotateBodyWhileMoving = true, + TurnFacingRate = 100, + TurnRadius = 360, + TurnRate = 180, + }, + SizeX = 0.01, + SizeY = 0.01, + SizeZ = 0.01, +} \ No newline at end of file diff --git a/units/URA0003/URA0003_lod0.scm b/units/URA0003/URA0003_lod0.scm new file mode 100644 index 0000000000..819d609aa2 Binary files /dev/null and b/units/URA0003/URA0003_lod0.scm differ diff --git a/units/URA0003/URA0003_lod0_Spin.sca b/units/URA0003/URA0003_lod0_Spin.sca new file mode 100644 index 0000000000..7dff418c06 Binary files /dev/null and b/units/URA0003/URA0003_lod0_Spin.sca differ diff --git a/units/URA0003/URA0003_script.lua b/units/URA0003/URA0003_script.lua new file mode 100644 index 0000000000..becd7fa9a6 --- /dev/null +++ b/units/URA0003/URA0003_script.lua @@ -0,0 +1,37 @@ +----------------------------------------------------------------- +-- File : /cdimage/units/URA0001/URA0001_script.lua +-- Author(s): Gordon Duclos +-- Summary : Cybran Builder bot units +-- Copyright © 2006 Gas Powered Games, Inc. All rights reserved. +----------------------------------------------------------------- + +-- upvalued globals for performance +local CreateBuilderArmController = CreateBuilderArmController + +-- upvalued moho functions for performance +local BuilderArmManipulator = _G.moho.BuilderArmManipulator +local BuilderArmManipulatorSetAimingArc = BuilderArmManipulator.SetAimingArc +local BuilderArmManipulatorSetPrecedence = BuilderArmManipulator.SetPrecedence +BuilderArmManipulator = nil + +-- upvalued trashbag functions for performance +local TrashBag = _G.TrashBag +local TrashBagAdd = TrashBag.Add + +local CBuildBotUnit = import('/lua/cybranunits.lua').CBuildBotUnit +URA0003 = Class(CBuildBotUnit) { + + OnCreate = function(self) + CBuildBotUnit.OnCreate(self) + + local trash = self.Trash + + -- make the drone aim for the target + local BuildArmManipulator = CreateBuilderArmController(self, 'URA0003' , 'URA0003', 0) + BuilderArmManipulatorSetAimingArc(BuildArmManipulator, -180, 180, 360, -90, 90, 360) + BuilderArmManipulatorSetPrecedence(BuildArmManipulator, 5) + TrashBagAdd(trash, BuildArmManipulator) + end, + +} +TypeClass = URA0003 diff --git a/units/URA0003/URA0003_unit.bp b/units/URA0003/URA0003_unit.bp new file mode 100644 index 0000000000..5b3be6581f --- /dev/null +++ b/units/URA0003/URA0003_unit.bp @@ -0,0 +1,131 @@ +UnitBlueprint { + Air = { + BankFactor = 0.1, + BankForward = false, + CanFly = true, + CirclingDirChangeFrequencySec = 2, + CirclingElevationChangeRatio = 1.5, + CirclingRadiusChangeMaxRatio = 0.5, + CirclingRadiusChangeMinRatio = 0.2, + CirclingRadiusVsAirMult = 0.49, + CirclingTurnMult = 3, + KLift = 1, + KLiftDamping = 4, + KMove = 4, + KMoveDamping = 1, + KTurn = 4, + KTurnDamping = 2, + LiftFactor = 7, + MaxAirspeed = 8, + MinAirspeed = 8, + StartTurnDistance = 5, + Winged = false, + }, + Categories = { + -- to allow it to build / repair when assist + 'CONSTRUCTION', + 'ENGINEER', + 'REPAIR', + + -- for unit restrictions + 'POD', + + -- for UI + 'NOFORMATION', + + -- makes it a dummy-isch unit + 'UNTARGETABLE', + 'INVULNERABLE', + 'UNSPAWNABLE', + 'UNSELECTABLE', + }, + Display = { + Mesh = { + IconFadeInZoom = 2000, + LODs = { + { + AlbedoName = '/Units/URA0001/URA0001_Albedo.dds', + LODCutoff = 215, + MeshName = '/Units/URA0003/URA0003_LOD0.scm', + NormalsName = '/UNITS/URA0001/URA0001_NormalsTS.dds', + ShaderName = 'Insect', + SpecularName = '/Units/URA0001/URA0001_SpecTeam.dds', + }, + }, + }, + AnimationLoop = '/units/URA0003/URA0003_lod0_Spin.sca', + PlaceholderMeshName = 'URA0001', + SpawnRandomRotation = true, + UniformScale = 0.14, + }, + Economy = { + BuildCostEnergy = 0, + BuildCostMass = 0, + BuildRate = 0.0001, + BuildTime = 0, + BuildableCategory = { + 'BUILTBYTIER1ENGINEER CYBRAN', + }, + ConsumptionPerSecondEnergy = 0, + ConsumptionPerSecondMass = 0, + MaxBuildDistance = 100, + }, + Footprint = { + MaxSlope = 0.25, + SizeX = 1, + SizeZ = 1, + }, + General = { + CapCost = 0, + Category = 'Construction', + Classification = 'RULEUC_Engineer', + CommandCaps = { + RULEUCC_Attack = false, + RULEUCC_CallTransport = true, + RULEUCC_Capture = false, + RULEUCC_Guard = true, + RULEUCC_Move = true, + RULEUCC_Nuke = false, + RULEUCC_Patrol = false, + RULEUCC_Reclaim = true, + RULEUCC_Repair = true, + RULEUCC_RetaliateToggle = true, + RULEUCC_Stop = true, + RULEUCC_Transport = false, + }, + FactionName = 'Cybran', + Icon = 'air', + SelectionPriority = 3, + TechLevel = 'RULEUTL_Basic', + UnitWeight = 1, + }, + Intel = { + VisionRadius = 0, + }, + Physics = { + BankingSlope = 0.5, + BuildOnLayerCaps = { + LAYER_Air = true, + LAYER_Land = false, + LAYER_Orbit = false, + LAYER_Seabed = false, + LAYER_Sub = false, + LAYER_Water = false, + }, + DragCoefficient = 0.2, + Elevation = 8, + MaxAcceleration = 10.5, + MaxSpeed = 10.5, + MaxSpeedReverse = 0, + MaxSteerForce = 0, + MinSpeedPercent = 0, + MotionType = 'RULEUMT_Air', + RotateBodyWhileMoving = true, + TurnFacingRate = 100, + TurnRadius = 360, + TurnRate = 180, + }, + SizeX = 0.01, + SizeY = 0.01, + SizeZ = 0.01, +} \ No newline at end of file diff --git a/units/URA0004/URA0004_script.lua b/units/URA0004/URA0004_script.lua new file mode 100644 index 0000000000..7ff5ad5d3d --- /dev/null +++ b/units/URA0004/URA0004_script.lua @@ -0,0 +1,38 @@ +----------------------------------------------------------------- +-- File : /cdimage/units/URA0001/URA0001_script.lua +-- Author(s): Gordon Duclos +-- Summary : Cybran Builder bot units +-- Copyright © 2006 Gas Powered Games, Inc. All rights reserved. +----------------------------------------------------------------- + +-- upvalued globals for performance +local CreateBuilderArmController = CreateBuilderArmController + +-- upvalued moho functions for performance +local BuilderArmManipulator = _G.moho.BuilderArmManipulator +local BuilderArmManipulatorSetAimingArc = BuilderArmManipulator.SetAimingArc +local BuilderArmManipulatorSetPrecedence = BuilderArmManipulator.SetPrecedence +BuilderArmManipulator = nil + +-- upvalued trashbag functions for performance +local TrashBag = _G.TrashBag +local TrashBagAdd = TrashBag.Add + +local CBuildBotUnit = import('/lua/cybranunits.lua').CBuildBotUnit +URA0004 = Class(CBuildBotUnit) { + + OnCreate = function(self) + CBuildBotUnit.OnCreate(self) + + -- make the drone aim for the target + local BuildArmManipulator = CreateBuilderArmController(self, 'URA0004' , 'URA0004', 0) + BuilderArmManipulatorSetAimingArc(BuildArmManipulator, -180, 180, 360, -90, 90, 360) + BuilderArmManipulatorSetPrecedence(BuildArmManipulator, 5) + TrashBagAdd(self.Trash, BuildArmManipulator) + + -- run animation + -- TODO + end, + +} +TypeClass = URA0004 diff --git a/units/URA0004/URA0004_unit.bp b/units/URA0004/URA0004_unit.bp new file mode 100644 index 0000000000..3ec5d98d74 --- /dev/null +++ b/units/URA0004/URA0004_unit.bp @@ -0,0 +1,118 @@ +UnitBlueprint { + Air = { + BankFactor = 0.1, + BankForward = false, + CanFly = true, + CirclingDirChangeFrequencySec = 2, + CirclingElevationChangeRatio = 0.5, + CirclingRadiusChangeMaxRatio = 2.1, + CirclingRadiusChangeMinRatio = 0.6, + CirclingRadiusVsAirMult = 0.99, + CirclingTurnMult = 3, + KLift = 3, + KLiftDamping = 2, + KMove = 4, + KMoveDamping = 1, + KTurn = 4, + KTurnDamping = 2, + LiftFactor = 7, + MaxAirspeed = 6, + MinAirspeed = 5, + StartTurnDistance = 5, + Winged = false, + }, + Categories = { + -- to allow it to build / repair when assist + 'CONSTRUCTION', + 'ENGINEER', + 'REPAIR', + + -- for unit restrictions + 'POD', + + -- for UI + 'NOFORMATION', + + -- makes it a dummy-isch unit + 'UNTARGETABLE', + 'INVULNERABLE', + 'UNSPAWNABLE', + 'UNSELECTABLE', + }, + Display = { + Mesh = { + LODs = { + { + AlbedoName = '/Units/URA0004/URA0004_Albedo.dds', + LODCutoff = 200, + MeshName = '/Units/URA0004/URA0004_LOD0.scm', + NormalsName = '/UNITS/URA0004/URA0004_NormalsTS.dds', + ShaderName = 'Insect', + SpecularName = '/Units/URA0004/URA0004_SpecTeam.dds', + }, + }, + }, + PlaceholderMeshName = 'URA0004', + SpawnRandomRotation = true, + UniformScale = 0.12, + }, + Economy = { + BuildRate = 0.00001, + MaxBuildDistance = 100, + }, + + Intel = { + VisionRadius = 0, + WaterVisionRadius = 0, + }, + General = { + CapCost = 0, + Category = 'Construction', + Classification = 'RULEUC_Engineer', + CommandCaps = { + RULEUCC_Attack = false, + RULEUCC_CallTransport = true, + RULEUCC_Capture = false, + RULEUCC_Guard = true, + RULEUCC_Move = true, + RULEUCC_Nuke = false, + RULEUCC_Patrol = false, + RULEUCC_Reclaim = true, + RULEUCC_Repair = true, + RULEUCC_RetaliateToggle = true, + RULEUCC_Stop = true, + RULEUCC_Transport = false, + }, + FactionName = 'Cybran', + Icon = 'air', + SelectionPriority = 3, + TechLevel = 'RULEUTL_Basic', + UnitWeight = 1, + }, + Physics = { + BankingSlope = 0.5, + BuildOnLayerCaps = { + LAYER_Air = true, + LAYER_Land = false, + LAYER_Orbit = false, + LAYER_Seabed = false, + LAYER_Sub = false, + LAYER_Water = false, + }, + DragCoefficient = 0.2, + Elevation = 5, + MaxAcceleration = 10.5, + MaxSpeed = 20.5, + MaxSpeedReverse = 0, + MaxSteerForce = 0, + MinSpeedPercent = 0, + MotionType = 'RULEUMT_Air', + RotateBodyWhileMoving = true, + TurnFacingRate = 100, + TurnRadius = 360, + TurnRate = 180, + }, + SizeX = 0.01, + SizeY = 0.01, + SizeZ = 0.01, +} diff --git a/units/URL0001/URL0001_script.lua b/units/URL0001/URL0001_script.lua index 6bcd942f9b..c71de6af08 100644 --- a/units/URL0001/URL0001_script.lua +++ b/units/URL0001/URL0001_script.lua @@ -50,6 +50,7 @@ URL0001 = Class(ACUUnit, CCommandUnit) { -- Creation OnCreate = function(self) ACUUnit.OnCreate(self) + CCommandUnit.OnCreate(self) self:SetCapturable(false) self:HideBone('Back_Upgrade', true) self:HideBone('Right_Upgrade', true) @@ -94,12 +95,6 @@ URL0001 = Class(ACUUnit, CCommandUnit) { self.BuildingUnit = true end, - -- Build/Upgrade - CreateBuildEffects = function(self, unitBeingBuilt, order) - EffectUtil.SpawnBuildBots(self, unitBeingBuilt, self.BuildEffectsBag) - EffectUtil.CreateCybranBuildBeams(self, unitBeingBuilt, self.BuildEffectBones, self.BuildEffectsBag) - end, - CreateEnhancement = function(self, enh) ACUUnit.CreateEnhancement(self, enh) if enh == 'Teleporter' then diff --git a/units/URL0001/URL0001_unit.bp b/units/URL0001/URL0001_unit.bp index 753c50e2e9..bbb7a76a1b 100644 --- a/units/URL0001/URL0001_unit.bp +++ b/units/URL0001/URL0001_unit.bp @@ -114,6 +114,7 @@ UnitBlueprint { LodCutoff = 'UnitMove_LodCutoff', }, }, + BuildBotTotal = 2, Buffs = { Regen = { Level1 = 4, diff --git a/units/URL0105/URL0105_script.lua b/units/URL0105/URL0105_script.lua new file mode 100644 index 0000000000..758b19260c --- /dev/null +++ b/units/URL0105/URL0105_script.lua @@ -0,0 +1,15 @@ +#**************************************************************************** +#** +#** File : /cdimage/units/URL0105/URL0105_script.lua +#** Author(s): David Tomandl +#** +#** Summary : Cybran T1 Engineer Script +#** +#** Copyright © 2005 Gas Powered Games, Inc. All rights reserved. +#**************************************************************************** + +local CConstructionUnit = import('/lua/cybranunits.lua').CConstructionUnit + +URL0105 = Class(CConstructionUnit) {} + +TypeClass = URL0105 \ No newline at end of file diff --git a/units/URL0105/URL0105_unit.bp b/units/URL0105/URL0105_unit.bp index d250e39bdd..729d75a40d 100644 --- a/units/URL0105/URL0105_unit.bp +++ b/units/URL0105/URL0105_unit.bp @@ -62,6 +62,7 @@ UnitBlueprint { }, }, BuildIconSortPriority = 10, + BuildBotTotal = 1, Categories = { 'PRODUCTSC1', 'SELECTABLE', diff --git a/units/URL0208/URL0208_unit.bp b/units/URL0208/URL0208_unit.bp index 53dae2d71f..d87c8da250 100644 --- a/units/URL0208/URL0208_unit.bp +++ b/units/URL0208/URL0208_unit.bp @@ -62,6 +62,7 @@ UnitBlueprint { }, }, BuildIconSortPriority = 10, + BuildBotTotal = 2, Categories = { 'PRODUCTSC1', 'SELECTABLE', diff --git a/units/URL0301/URL0301_script.lua b/units/URL0301/URL0301_script.lua index 96600fc7ad..96d4711d47 100644 --- a/units/URL0301/URL0301_script.lua +++ b/units/URL0301/URL0301_script.lua @@ -5,7 +5,9 @@ -- Copyright Å  2005 Gas Powered Games, Inc. All rights reserved. ----------------------------------------------------------------- -local CCommandUnit = import('/lua/cybranunits.lua').CCommandUnit +local CybranUnits = import('/lua/cybranunits.lua') +local CCommandUnit = CybranUnits.CCommandUnit + local CWeapons = import('/lua/cybranweapons.lua') local EffectUtil = import('/lua/EffectUtilities.lua') local Buff = import('/lua/sim/Buff.lua') @@ -49,12 +51,6 @@ URL0301 = Class(CCommandUnit) { CCommandUnit.__init(self, 'RightDisintegrator') end, - -- Engineering effects - CreateBuildEffects = function(self, unitBeingBuilt, order) - EffectUtil.SpawnBuildBots(self, unitBeingBuilt, self.BuildEffectsBag) - EffectUtil.CreateCybranBuildBeams(self, unitBeingBuilt, self.BuildEffectBones, self.BuildEffectsBag) - end, - OnStopBeingBuilt = function(self, builder, layer) CCommandUnit.OnStopBeingBuilt(self, builder, layer) self:BuildManipulatorSetEnabled(false) @@ -161,6 +157,7 @@ URL0301 = Class(CCommandUnit) { self:SetProductionPerSecondEnergy(bpEcon.ProductionPerSecondEnergy or 0) self:SetProductionPerSecondMass(bpEcon.ProductionPerSecondMass or 0) elseif enh =='Switchback' then + self.BuildBotTotal = 4 if not Buffs['CybranSCUBuildRate'] then BuffBlueprint { Name = 'CybranSCUBuildRate', @@ -178,6 +175,7 @@ URL0301 = Class(CCommandUnit) { end Buff.ApplyBuff(self, 'CybranSCUBuildRate') elseif enh == 'SwitchbackRemove' then + self.BuildBotTotal = 3 if Buff.HasBuff(self, 'CybranSCUBuildRate') then Buff.RemoveBuff(self, 'CybranSCUBuildRate') end diff --git a/units/URL0301/URL0301_unit.bp b/units/URL0301/URL0301_unit.bp index d2e342b4b3..1d790055b0 100644 --- a/units/URL0301/URL0301_unit.bp +++ b/units/URL0301/URL0301_unit.bp @@ -112,6 +112,7 @@ UnitBlueprint { }, }, BuildIconSortPriority = 10, + BuildBotTotal = 3, Categories = { 'PRODUCTSC1', 'SELECTABLE', diff --git a/units/URL0309/URL0309_unit.bp b/units/URL0309/URL0309_unit.bp index a7a6ae6e6d..5581c78eb4 100644 --- a/units/URL0309/URL0309_unit.bp +++ b/units/URL0309/URL0309_unit.bp @@ -62,6 +62,7 @@ UnitBlueprint { }, }, BuildIconSortPriority = 10, + BuildBotTotal = 3, Categories = { 'PRODUCTSC1', 'SELECTABLE', diff --git a/units/XRB0104/XRB0104_unit.bp b/units/XRB0104/XRB0104_unit.bp index bf90da3a31..23b11dfb36 100644 --- a/units/XRB0104/XRB0104_unit.bp +++ b/units/XRB0104/XRB0104_unit.bp @@ -58,6 +58,7 @@ UnitBlueprint { }, }, BuildIconSortPriority = 200, + BuildBotTotal = 1, Categories = { 'PRODUCTFA', 'SELECTABLE', diff --git a/units/XRB0204/XRB0204_unit.bp b/units/XRB0204/XRB0204_unit.bp index cebbd2e32b..877a2e5ddd 100644 --- a/units/XRB0204/XRB0204_unit.bp +++ b/units/XRB0204/XRB0204_unit.bp @@ -63,6 +63,7 @@ UnitBlueprint { }, }, BuildIconSortPriority = 200, + BuildBotTotal = 2, Categories = { 'PRODUCTFA', 'SELECTABLE', diff --git a/units/XRB0304/XRB0304_unit.bp b/units/XRB0304/XRB0304_unit.bp index 5de0ade07a..7b2a2df21a 100644 --- a/units/XRB0304/XRB0304_unit.bp +++ b/units/XRB0304/XRB0304_unit.bp @@ -63,6 +63,7 @@ UnitBlueprint { }, }, BuildIconSortPriority = 200, + BuildBotTotal = 3, Categories = { 'PRODUCTFA', 'SELECTABLE',