This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

@@ -0,0 +1,4 @@
kSentryHealth = 1200

kEggBeaconMaxHealth = 715
kEggBeaconMaxArmor = 200
@@ -0,0 +1,21 @@
kSentryDamage = 10

kTeamResourcePerTick = 4
kMaxTeamResources = 999
kPlayingTeamInitialTeamRes = 999

kCompoundFireDamageDelay = 0
kCompundFireDamageScalar = 3.7

kExoFlamerDamage = 25
kExoWelderDamagePerSecond = 28
kExoPlayerWeldRate = 15
kExoStructureWeldRate = 65
kNanoArmorHealPerSecond = 2

kHiveBuildTime = 60

kARCMinRange = 0 -- why is this even a thing??????

kEnzymeCloudDuration = 6
kMucousShieldDuration = 6
@@ -1,193 +1,14 @@
local orig_Whip_OnInit = Whip.OnInitialized
function Whip:OnInitialized()
orig_Whip_OnInit(self)

if Server then
local targetTypes = { kAlienStaticTargets, kAlienMobileTargets }, { self.FilterTarget(self) }
self.slapTargetSelector = TargetSelector():Init(self, Whip.kRange, true, targetTypes)
self.bombardTargetSelector = TargetSelector():Init(self, Whip.kBombardRange, true, targetTypes)
end
end

function Whip:FilterTarget()

local attacker = self
return function (target, targetPosition) return attacker:GetCanFireAtTargetActual(target, targetPosition) end

end
function Whip:GetCanFireAtTargetActual(target, targetPoint)

if target:isa("AvocaArc") and not target:GetInAttackMode() then
return false
end

return true

end
if Server then

function Whip:UpdateRootState()

local infested = true --self:GetGameEffectMask(kGameEffect.OnInfestation)
local moveOrdered = self:GetCurrentOrder() and self:GetCurrentOrder():GetType() == kTechId.Move
-- unroot if we have a move order or infestation recedes
if self.rooted and (moveOrdered or not infested) then
self:Unroot()
end

-- root if on infestation and not moving/teleporting
if not self.rooted and infested and not (moveOrdered or self:GetIsTeleporting()) then
self:Root()
end

end
end
function Whip:OnKill(attacker, doer, point, direction)
--if attacker and attacker:isa("ARC") then AddPayLoadTime(1) end
end

function Harvester:GetCanAutoBuild()

return true

end

if Server then


function Hive:UpdateAliensWeaponsManually() ///Seriously this makes more sense than spamming some complicated formula every 0.5 seconds no?
for _, alien in ientitylist(Shared.GetEntitiesWithClassname("Alien")) do
alien:HiveCompleteSoRefreshTechsManually()
end
end

local function LocationsMatch(who,whom)

local whoname = GetLocationForPoint(who:GetOrigin())
local whomname = GetLocationForPoint(whom:GetOrigin())
return true --whoname == whomname
end


local function ToSpawnFormula(self,panicstospawn, where)
for i = 1, panicstospawn do
local bitch = GetPayLoadArc()
if bitch and GetIsPointWithinHiveRadius(bitch:GetOrigin()) then
local spawnpoint = FindFreeSpace(bitch:GetOrigin(), 4, 8)
if spawnpoint then
local panicattack = CreateEntity(PanicAttack.kMapName, spawnpoint, 2)
panicattack:SetConstructionComplete()
panicattack:SetMature()
end
end
end

end
local function GetRange(who, where)
local ArcFormula = (where - who:GetOrigin()):GetLengthXZ()
return ArcFormula
end
local function SendAnxietyAttack(self, where, who)
for i = 1, #who do
local panicattack = who[i]
local bitch = GetDeployedPayLoadArc()
if bitch and GetIsPointWithinHiveRadius(bitch:GetOrigin()) and GetRange(panicattack,bitch:GetOrigin()) >= 16 then
local spawnpoint = FindFreeSpace(bitch:GetOrigin(), 4, 8)
if spawnpoint then
panicattack:SetOrigin(spawnpoint)
end
end
end
end
local function PanicInitiate(self,where)
local panicattacks = {}

for _, panicattack in ipairs(GetEntitiesWithinRange("PanicAttack", where, 9999)) do
if panicattack:GetIsAlive() then
table.insert(panicattacks,panicattack)
end
end

local countofpanic = Clamp(table.count(panicattacks), 0, 8)
local maxpanic = 4
local panicstospawn = math.abs(maxpanic - countofpanic)
panicstospawn = Clamp(panicstospawn, 1, 2)

if panicstospawn >= 1 then ToSpawnFormula(self,panicstospawn, where) end

if countofpanic >= 1 then
SendAnxietyAttack(self, where, panicattacks) -- not sure
end

end

local orig_Hive_OnTakeDamage = Hive.OnTakeDamage
function Hive:OnTakeDamage(damage, attacker, doer, point)

if doer and doer:isa("ARC") then
Print("PanicAttack Initiated")
PanicInitiate(self,self:GetOrigin())
if self:GetIsBuilt() then AddPayLoadTime(10) end
end

return orig_Hive_OnTakeDamage(self,damage, attacker, doer, point)
end



local kAuxPowerBackupSound = PrecacheAsset("sound/NS2.fev/marine/power_node/backup")

local function BuildRoomPower(who)

local nearestPower = GetNearest(who:GetOrigin(), "PowerPoint", 1, function(ent) return LocationsMatch(who,ent) end)
if nearestPower and nearestPower:GetIsDisabled() then
local cheaptrick = CreateEntity(PowerPoint.kMapName, nearestPower:GetOrigin(), 1)
cheaptrick:SetConstructionComplete()
DestroyEntity(nearestPower)
end


who:AddTimedCallback(function()
local bigarc = CreateEntity(BigArc.kMapName, who:GetOrigin(), 1)
bigarc:GiveDeploy()
end, 8)

end

local function GetTechPoint(where)
for _, techpoint in ipairs(GetEntitiesWithinRange("TechPoint", where, 8)) do
if techpoint then return techpoint end
end
end
local function DestroyAvocaArcInRadius(where)
for _, avocaarc in ipairs(GetEntitiesWithinRange("AvocaArc", where, kARCRange)) do
if avocaarc then avocaarc:Kill() end
end
end
local orig_Hive_OnKill = Hive.OnKill
function Hive:OnKill(attacker, doer, point, direction)
self:UpdateAliensWeaponsManually()
if self:GetIsBuilt() then AddPayLoadTime(16) end
local child = GetTechPoint(self:GetOrigin())
BuildRoomPower(child)
DestroyAvocaArcInRadius(self:GetOrigin())
child:SetIsVisible(false)
return orig_Hive_OnKill(self,attacker, doer, point, direction)
end
/*
local orig_Hive_OnResearchComplete = Hive.OnResearchComplete
function Hive:OnResearchComplete(researchId)
self:UpdateAliensWeaponsManually()
return orig_Hive_OnResearchComplete(researchId, self)
end
*/

if Server then

local orig_Hive_OnDestroy = Hive.OnDestroy
function Hive:OnDEstroy()
orig_Hive_OnDestroy(self)
self:UpdateAliensWeaponsManually()
end

local orig_NutrientMist_Perform = NutrientMist.Perform
function NutrientMist:Perform()
@@ -197,7 +18,7 @@ function NutrientMist:Perform()

for index, entity in ipairs(entities) do

entity:SetWebbed(8)
entity:SetWebbed(4)

end
end

This file was deleted.

@@ -1,18 +1,7 @@

--Kyle 'Avoca Abent'
kMarineResearchDelay = 15
local function TresCheck(cost)
return GetGamerules().team1:GetTeamResources() >= cost
end
local function DeductTres(cost,teamnum)
if teamnum == 1 then
local marineteam = GetGamerules().team1
marineteam:SetTeamResources(marineteam:GetTeamResources() - cost)
else
local alienteam = GetGamerules().team2
alienteam:SetTeamResources(alienteam:GetTeamResources() - cost)
end
end

function Conductor:AutoBioMass()
for _, hive in ientitylist(Shared.GetEntitiesWithClassname("Hive")) do
hive:AddTimedCallback(Hive.UpdateManually, 15)
@@ -22,101 +11,3 @@ function Hive:GetBioMassLevel()
return self.bioMassLevel
end

function Hive:OnConstructionComplete()
--biomass 0
-- Play special tech point animation at same time so it appears that we bash through it.
self:AddTimedCallback(Hive.UpdateManually, 15)
local attachedTechPoint = self:GetAttached()
if attachedTechPoint then
attachedTechPoint:SetIsSmashed(true)
else
Print("Hive not attached to tech point")
end

local team = self:GetTeam()

if team then
team:OnHiveConstructed(self)
end

if self.hiveType == 1 then
self:OnResearchComplete(kTechId.UpgradeToCragHive)
elseif self.hiveType == 2 then
self:OnResearchComplete(kTechId.UpgradeToShadeHive)
elseif self.hiveType == 3 then
self:OnResearchComplete(kTechId.UpgradeToShiftHive)
end

local cysts = GetEntitiesForTeamWithinRange( "Cyst", self:GetTeamNumber(), self:GetOrigin(), self:GetCystParentRange())
for _, cyst in ipairs(cysts) do
cyst:ChangeParent(self)
end
end
function Hive:UpdateManually()
if Server then
self:UpdatePassive()
end
return self:GetIsAlive()
end

local function GetBioMassLevel()
local teamInfo = GetTeamInfoEntity(2)
local bioMass = (teamInfo and teamInfo.GetBioMassLevel) and teamInfo:GetBioMassLevel() or 0
return math.round(bioMass / 4, 1, 3)
end
function Hive:UpdatePassive()
if GetHasTech(self, kTechId.Xenocide) or not GetGamerules():GetGameStarted() or not self:GetIsBuilt() or self:GetIsResearching() then return true end

local teamInfo = GetTeamInfoEntity(2)
local teambioMass = (teamInfo and teamInfo.GetBioMassLevel) and teamInfo:GetBioMassLevel() or 0

local techid = nil


if teambioMass >= 2 and not GetHasTech(self, kTechId.Charge) then
techid = kTechId.Charge
elseif teambioMass >= 3 and not GetHasTech(self, kTechId.BileBomb) then
techid = kTechId.BileBomb
elseif teambioMass >= 3 and not GetHasTech(self, kTechId.MetabolizeEnergy) then
techid = kTechId.MetabolizeEnergy
elseif teambioMass >= 4 and not GetHasTech(self, kTechId.Leap) then
techid = kTechId.Leap
elseif teambioMass >= 4 and not GetHasTech(self, kTechId.Spores) then
techid = kTechId.Spores
elseif teambioMass >= 5 and not GetHasTech(self, kTechId.Umbra) then
techid = kTechId.Umbra
elseif teambioMass >= 5 and not GetHasTech(self, kTechId.MetabolizeHealth) then
techid = kTechId.MetabolizeHealth
elseif teambioMass >= 6 and not GetHasTech(self, kTechId.BoneShield) then
techid = kTechId.BoneShield
elseif teambioMass >= 7 and not GetHasTech(self, kTechId.Stab) then
techid = kTechId.Stab
elseif teambioMass >= 8 and not GetHasTech(self, kTechId.Stomp) then
techid = kTechId.Stomp
elseif teambioMass >= 9 and not GetHasTech(self, kTechId.Xenocide) then
techid = kTechId.Xenocide
end

if techid == nil and self.bioMassLevel <= 1 then
techid = kTechId.ResearchBioMassOne
elseif techid == nil and self.bioMassLevel == 2 then
techid = kTechId.ResearchBioMassTwo
elseif techid == nil and self.bioMassLevel == 3 then
techid = kTechId.ResearchBioMassThree
elseif techid == nil and self.bioMassLevel == 4 then
techid = kTechId.ResearchBioMassFour
end

if techid == nil then return true end
local cost = LookupTechData(techid, kTechDataCostKey, 0)
if TresCheck(cost) then
DeductTres(cost, 2)
local techNode = self:GetTeam():GetTechTree():GetTechNode( techid )
self:SetResearching(techNode, self)
end


end



@@ -24,12 +24,13 @@ local crags = 0

end
local function GetDefenseEntsInRange(who)
/*
local shifts = GetEntitiesForTeamWithinRange("Shift", 2, who:GetOrigin(), 24)
local crags = GetCragsCount(who:GetOrigin())
local hivecrags = GetEntitiesWithinRange("HiveCrag", who:GetOrigin(), 24)
local shades = GetEntitiesForTeamWithinRange("Shade", 2, who:GetOrigin(), 24)
local drifters = GetEntitiesForTeamWithinRange("DrifterAvoca", 2, who:GetOrigin(), 9999)
return shifts, crags, hivecrags, shades, drifters
*/
return 0,0,0,0--shifts, crags, hivecrags, shades, drifters
end
local function UpdateTypeOfHive(who)
local hasshade = false
@@ -123,14 +124,14 @@ local function SpawnUpgChamber(origin)
end

end
function Conductor:HiveDefenseMain(hive, shifts, crags, hivecrags, shades, drifters)
function Conductor:HiveDefenseMain(hive, shifts, crags, hivecrags, shades)
-- local tres = kStructureDropCost
if not hive:GetIsAlive() then return end
local origin = hive:GetOrigin()
local canafford = GetCanSpawnAlienEntity(0)
if canafford then SpawnUpgChamber(origin) end


/*
if #shifts <= math.random(1,3) then
local tres = 0 --kShiftCost
-- if GetCanSpawnAlienEntity(tres) then
@@ -176,12 +177,12 @@ function Conductor:HiveDefenseMain(hive, shifts, crags, hivecrags, shades, drift
local tres = 0 --kShadeCost
if not spawned then
-- if GetCanSpawnAlienEntity(tres) then
local drifter = CreateEntity(DrifterAvoca.kMapName, FindFreeSpace(origin), 2)
local drifter = CreateEntity(Drifter.kMapName, FindFreeSpace(origin), 2)
-- drifter:GetTeam():SetTeamResources(drifter:GetTeam():GetTeamResources() - tres)
--end
end
end

*/


end
@@ -1,12 +1,12 @@
Script.Load("lua/ClassMods/HiveDefense.lua")
Script.Load("lua/ClassMods/AirLock.lua")
Script.Load("lua/ClassMods/AutoMacsArcs.lua")




Script.Load("lua/ClassMods/AlienStructureMods.lua")
Script.Load("lua/ClassMods/MarineStructureMods.lua")
Script.Load("lua/ClassMods/PlayerMods.lua")


if Server then
Script.Load("lua/ClassMods/ArmoryArmor.lua")
Script.Load("lua/ClassMods/AutoResearch.lua")
Script.Load("lua/ClassMods/AutoResearch.lua")
end
@@ -1,31 +1,54 @@
function SentryBattery:GetUnitNameOverride(viewer)
local unitName = GetDisplayName(self)
unitName = string.format(Locale.ResolveString("BackupPower") )
return unitName
end

function GhostStructureMixin:__initmixin()

-- init the entity in ghost structure mode
if Server then
self.isGhostStructure = self:isa("Extractor")
self.isGhostStructure = false
end

end
function RoboticsFactory:GetTechButtons(techId)
end

local techButtons = { kTechId.None, kTechId.None, kTechId.None, kTechId.None,
kTechId.None, kTechId.None, kTechId.None, kTechId.None }

if self:GetTechId() ~= kTechId.ARCRoboticsFactory then
techButtons[5] = kTechId.UpgradeRoboticsFactory
end
local function GetHasSentryBatteryInRadius(self)
local backupbattery = GetEntitiesWithinRange("SentryBattery", self:GetOrigin(), 6)
for index, battery in ipairs(backupbattery) do
if GetIsUnitActive(battery) then return true end
end

return false
end

return techButtons

function PowerConsumerMixin:GetIsPowered()
return self.powered or self.powerSurge or GetHasSentryBatteryInRadius(self)
end


if Server then


function ConstructMixin:AdjustHPArmor()
if GetIsRoomPowerUp(self) then --if phase 1?
if not self:GetIsInCombat() then self:AddHealth(100) self:AddArmor(25) end
else
self:DeductHealth(100)
end
return self:GetIsBuilt()
end

local orig consOn = ConstructMixin.OnConstructionComplete
function ConstructMixin:OnConstructionComplete(builder)
consOn(self, builder)
if self:GetTeamNumber() == 1 then
self:AddTimedCallback(ConstructMixin.AdjustHPArmor, 4)
end
end

function ConstructMixin:OnUpdate(deltaTime)
if ( self.GetIsInCombat ) and not self:GetIsInCombat() and not self:isa("PowerPoint") and self:GetTeamNumber() == 1 and not self:GetIsBuilt() and GetIsRoomPowerUp(self) then
-- Print("derp")
self:Construct(0.0125)
end
end


local function LocationsMatch(who,whom)

local whoname = GetLocationForPoint(who:GetOrigin())
@@ -44,80 +67,23 @@ function CommandStructure:OnUpdateAnimationInput(modelMixin)
PROFILE("CommandStructure:OnUpdateAnimationInput")
modelMixin:SetAnimationInput("occupied", true)

end
local function SpawnJanitorForEach(where)

local wherelocation = GetLocationForPoint(where)
wherelocation = wherelocation and wherelocation:GetName() or ""
if not wherelocation then return end

for _, eligable in ipairs(GetEntitiesWithMixinForTeamWithinRange("Construct", 1, where, 72)) do
if not eligable:isa("PowerPoint") and not eligable:isa("Extractor") and not GetIsPointInMarineBase(eligable:GetOrigin()) then
local location = GetLocationForPoint(eligable:GetOrigin())
local locationName = location and location:GetName() or ""
local sameLocation = locationName == wherelocation
if sameLocation then
local Janitor = CreateEntity(Janitor.kMapName, FindFreeSpace(eligable:GetOrigin()), 2)
Janitor:SetConstructionComplete()
Janitor:SetMature()
end --
end
end--

end

local function SpawnSurgeForEach(where)

local wherelocation = GetLocationForPoint(where)
wherelocation = wherelocation and wherelocation:GetName() or ""
if not wherelocation then return end

for _, eligable in ipairs(GetEntitiesWithMixinForTeamWithinRange("Construct", 2, where, 72)) do
-- if not eligable:isa("Harvester") and not eligable:isa("Cyst") and not eligable:isa("Hive") then --and not GetIsPointInMarineBase(eligable:GetOrigin()) then
local location = GetLocationForPoint(eligable:GetOrigin())
local locationName = location and location:GetName() or ""
local sameLocation = locationName == wherelocation
if sameLocation then
eligable:DeductHealth(400, nil, nil, true, false, true)
eligable:TriggerEffects("arc_hit_primary")
end --
-- end
end--

end
local orig_PowerPoint_StopDamagedSound = PowerPoint.StopDamagedSound
function PowerPoint:StopDamagedSound()
orig_PowerPoint_StopDamagedSound(self)
if self:GetHealthScalar() ~= 1 then return end
SpawnSurgeForEach(self:GetOrigin())
AddPayLoadTime(kTimeAddPowerBuilt)
local nearestHarvester = GetNearest(self:GetOrigin(), "Harvester", 2, function(ent) return LocationsMatch(self,ent) end)
if nearestHarvester then nearestHarvester:Kill() end
end

local orig_PowerPoint_OnKill = PowerPoint.OnKill
function PowerPoint:OnKill(attacker, doer, point, direction)
orig_PowerPoint_OnKill(self)
AddPayLoadTime(kTimeRemovePowerKilled)
--if not GetIsPointInMarineBase(self:GetOrigin()) then KillAllStructuresInLocation(self:GetOrigin(), 1) end
SpawnJanitorForEach(self:GetOrigin())

local nearestExtractor = GetNearest(self:GetOrigin(), "Extractor", 1, function(ent) return LocationsMatch(self,ent) end)
if nearestExtractor then
nearestExtractor:Kill()
end

end




/*

local function GetIsVaporizing(where)
for _, vape in ipairs(GetEntitiesWithinRange("Vaporizer", where, 16)) do
if vape then return true end
end
end



function CommandStation:ModifyDamageTaken(damageTable, attacker, doer, damageType, hitPoint)

if hitPoint ~= nil and GetIsVaporizing(self:GetOrigin()) then
@@ -147,7 +113,7 @@ function InfantryPortal:ModifyDamageTaken(damageTable, attacker, doer, damageTyp
end
function ConstructMixin:ModifyDamageTaken(damageTable, attacker, doer, damageType, hitPoint)

if not self:isa("CommandStructure") and not self:isa("Cyst") and hitPoint ~= nil and (attacker ~= nil and attacker:isa("Player") or attacker:isa("Janitor") ) then
if not self:isa("CommandStructure") and not self:isa("Cyst") and hitPoint ~= nil and (attacker ~= nil and attacker:isa("Player") ) then
local mult = 1
local wherelocation = GetLocationForPoint(self:GetOrigin())
if not wherelocation then return end
@@ -175,110 +141,10 @@ function ArmsLab:ModifyDamageTaken(damageTable, attacker, doer, damageType, hitP

end

*/






local function GetDestinationGate(self)
local phaseGates = {}
-- Find next phase gate to teleport to

if self:isa("PhaseAvoca") then

for index, payload in ipairs( GetEntitiesForTeam("AvocaArc", self:GetTeamNumber()) ) do
if GetIsUnitActive(payload) then
return payload
end
end

end

for index, phaseGate in ipairs( GetEntitiesForTeam("PhaseGate", self:GetTeamNumber()) ) do
if GetIsUnitActive(phaseGate) and not phaseGate:isa("PhaseAvoca") then
table.insert(phaseGates, phaseGate)
end
end



if table.count(phaseGates) < 2 then
return nil
end
-- Find our index and add 1
local index = table.find(phaseGates, self)
if (index ~= nil) then

local nextIndex = ConditionalValue(index == table.count(phaseGates), 1, index + 1)
ASSERT(nextIndex >= 1)
ASSERT(nextIndex <= table.count(phaseGates))
return phaseGates[nextIndex]

end

return nil
end

--So that we can teleport to the payload without having to run to it all the time :P
local function ComputeDestinationLocationId(self, destGate)

local destLocationId = Entity.invalidId
if destGate then

local location = GetLocationForPoint(destGate:GetOrigin())
if location then
destLocationId = location:GetId()
end

end

return destLocationId

end
function PhaseGate:Update()

self.phase = (self.timeOfLastPhase ~= nil) and (Shared.GetTime() < (self.timeOfLastPhase + 0.3))

local destinationPhaseGate = GetDestinationGate(self)
if destinationPhaseGate ~= nil and GetIsUnitActive(self) and self.deployed and (destinationPhaseGate.deployed or destinationPhaseGate:isa("ARC") ) then

self.destinationEndpoint = destinationPhaseGate:GetOrigin()
self.linked = true
self.targetYaw = destinationPhaseGate:GetAngles().yaw
self.destLocationId = ComputeDestinationLocationId(self, destinationPhaseGate)

else
self.linked = false
self.targetYaw = 0
self.destLocationId = Entity.invalidId
end

return true

end
function InfantryPortal:OhNoYouDidnt()

--for _, powerconsumer in ipairs(GetEntitiesWithMixinForTeamWithinRange("PowerConsumer", 1, self:GetOrigin(), 24)) do
-- if powerconsumer ~= self and (powerconsumer:GetRequiresPower() and not powerconsumer:GetIsPowered()) then
self:SetPowerSurgeDuration(16)
--powerconsumer:TriggerEffects("arc_hit_secondary")
-- end
-- end

self:TriggerEffects("arc_hit_primary")

return not self:GetIsPowered()

end

local orig_InfantryPortal_OnPowerOff = InfantryPortal.OnPowerOff
function InfantryPortal:OnPowerOff()
orig_InfantryPortal_OnPowerOff(self)
self:AddTimedCallback(InfantryPortal.OhNoYouDidnt, 8)
end




end
@@ -1,112 +1,3 @@
--Thanks for the trick, modular exo
local orig_Marine_GetMaxSpeed = Marine.GetMaxSpeed
function Marine:GetMaxSpeed(possible)
local original = orig_Marine_GetMaxSpeed(self)
local moveSpeed = (self:GetGameEffectMask(kGameEffect.OnInfestation) ) and original * 0.65 or original

return moveSpeed



end



local orig_Alien_OnCreate = Alien.OnCreate
function Alien:OnCreate()
orig_Alien_OnCreate(self)
if Server then
self:AddTimedCallback(function() UpdateAvocaAvailability(self, self:GetTierOneTechId(), self:GetTierTwoTechId(), self:GetTierThreeTechId()) end, .8)
elseif Client then
GetGUIManager():CreateGUIScriptSingle("GUIInsight_TopBar")
end
end


if Server then


local orig_Marine_InitWeapons = Marine.InitWeapons
function Marine:InitWeapons()
orig_Marine_InitWeapons(self)
self:GiveItem(Welder.kMapName)
self:SetQuickSwitchTarget(Pistol.kMapName)
self:SetActiveWeapon(Rifle.kMapName)
end


function Alien:HiveCompleteSoRefreshTechsManually()
UpdateAvocaAvailability(self, self:GetTierOneTechId(), self:GetTierTwoTechId(), self:GetTierThreeTechId())
end

function Marine:ModifyGravityForce(gravityTable)
if self:GetIsOnGround() then
gravityTable.gravity = 0
elseif self:GetHasCatpackBoost() then
gravityTable.gravity = -5
end
end



function Exo:PerformEjectOnPree()

if self:GetIsAlive() then

local reuseWeapons = self.storedWeaponsIds ~= nil

local marine = self:Replace(self.prevPlayerMapName or Marine.kMapName, self:GetTeamNumber(), false, self:GetOrigin() + Vector(0, 0.2, 0))
local health = Clamp(self.prevPlayerHealth or kMarineHealth-30, 1, 70)
marine:SetHealth(health)
marine:SetMaxArmor(self.prevPlayerMaxArmor or kMarineArmor)
marine:SetArmor(self.prevPlayerArmor or kMarineArmor)

--exosuit:SetOwner(marine)

marine.onGround = false
local initialVelocity = self:GetViewCoords().zAxis
initialVelocity:Scale(4)
initialVelocity.y = 9
marine:SetVelocity(initialVelocity)

if reuseWeapons then

for _, weaponId in ipairs(self.storedWeaponsIds) do

local weapon = Shared.GetEntity(weaponId)
if weapon then
marine:AddWeapon(weapon)
end

end

end

marine:SetHUDSlotActive(1)

if marine:isa("JetpackMarine") then
marine:SetFuel(0)
end

end

return false

end
function Exo:PreOnKill(attacker, doer, point, direction)
self:PerformEjectOnPree()
end









end



if Client then
@@ -0,0 +1,10 @@

function CommandStation:OnAdjustModelCoords(modelCoords)
local coords = modelCoords
local scale = 0.5
coords.xAxis = coords.xAxis * scale
coords.yAxis = coords.yAxis * scale
coords.zAxis = coords.zAxis * scale

return coords
end
@@ -0,0 +1,13 @@
function CommandStructure:LoginPlayer(player, forced )

return

end

function CommandStructure:UpdateCommanderLogin(force )

return

end


@@ -0,0 +1,28 @@
Script.Load("lua/InfestationMixin.lua")


local networkVars =

{
}

AddMixinNetworkVars(InfestationMixin, networkVars)

local originit = Crag.OnInitialized
function Crag:OnInitialized()
originit(self)
InitMixin(self, InfestationMixin)
end

function Crag:GetInfestationRadius()
return kInfestationRadius
end



function Crag:GetMinRangeAC()
return 14/3
end

Shared.LinkClassToMap("Crag", Crag.kMapName, networkVars)

@@ -0,0 +1,20 @@
if Server then
function Cyst:GetIsActuallyConnected()
return true
end
end


function Cyst:GetInfestationRadius()
return math.max(kInfestationRadius, kCystRedeployRange)
end

function Cyst:GetCystParentRange()
return 999
end
function Cyst:GetCanAutoBuild()

return true

end

@@ -1,10 +1,28 @@
class 'DrifterAvoca' (Drifter)
DrifterAvoca.kMapName = "drifteravoca"

local kDrifterConstructSound = PrecacheAsset("sound/NS2.fev/alien/drifter/drift")

--All this just to make drifters stack, rediculous.
local kDetectInterval = 0.5
local kDetectRange = 1.5
local kDrifterConstructSound = PrecacheAsset("sound/NS2.fev/alien/drifter/drift")
Drifter.kOrdered2DSoundName = PrecacheAsset("sound/NS2.fev/alien/drifter/ordered_2d")
Drifter.kOrdered3DSoundName = PrecacheAsset("sound/NS2.fev/alien/drifter/ordered")
local function ScanForNearbyEnemy(self)

-- Check for nearby enemy units. Uncloak if we find any.
self.lastDetectedTime = self.lastDetectedTime or 0
if self.lastDetectedTime + kDetectInterval < Shared.GetTime() then

if #GetEntitiesForTeamWithinRange("Player", GetEnemyTeamNumber(self:GetTeamNumber()), self:GetOrigin(), kDetectRange) > 0 then

self:TriggerUncloak()

end
self.lastDetectedTime = Shared.GetTime()

end

end

local kDrifterSelfOrderRange = 12

local function IsBeingGrown(self, target)

if target.hasDrifterEnzyme then
@@ -33,14 +51,23 @@ local function IsBeingGrown(self, target)

end
local function FindTask(self)
local eligable = GetNearestMixin(self:GetOrigin(), "Construct", 2, function(ent) return not ent:isa("AutoCyst") and not ent:GetIsBuilt() and not IsBeingGrown(self, ent) and (not ent.GetCanAutoBuild or ent:GetCanAutoBuild()) end)
if eligable then
self:GiveOrder(kTechId.Grow, eligable:GetId(), eligable:GetOrigin(), nil, false, false)

-- find ungrown structures
for _, structure in ipairs(GetEntitiesWithMixinForTeamWithinRange("Construct", self:GetTeamNumber(), self:GetOrigin(), kDrifterSelfOrderRange)) do

if not structure:GetIsBuilt() and (not structure.GetCanAutoBuild or structure:GetCanAutoBuild()) then

self:GiveOrder(kTechId.Grow, structure:GetId(), structure:GetOrigin(), nil, false, false)

return

end

end

end


local function UpdateTasks(self, deltaTime)

if not self:GetIsAlive() then
@@ -83,36 +110,7 @@ local function UpdateTasks(self, deltaTime)
end

end
local function ScanForNearbyEnemy(self)

-- Check for nearby enemy units. Uncloak if we find any.
self.lastDetectedTime = self.lastDetectedTime or 0
if self.lastDetectedTime + kDetectInterval < Shared.GetTime() then

if #GetEntitiesForTeamWithinRange("Player", GetEnemyTeamNumber(self:GetTeamNumber()), self:GetOrigin(), kDetectRange) > 0 then

self:TriggerUncloak()

end
self.lastDetectedTime = Shared.GetTime()

end

end
function DrifterAvoca:OnGetMapBlipInfo()
local success = false
local blipType = kMinimapBlipType.Undefined
local blipTeam = -1
local isAttacked = HasMixin(self, "Combat") and self:GetIsInCombat()
blipType = kMinimapBlipType.Drifter
blipTeam = self:GetTeamNumber()
if blipType ~= 0 then
success = true
end

return success, blipType, blipTeam, isAttacked, false --isParasited
end
function DrifterAvoca:OnUpdate(deltaTime)
function Drifter:OnUpdate(deltaTime)

ScriptActor.OnUpdate(self, deltaTime)

@@ -133,7 +131,7 @@ function DrifterAvoca:OnUpdate(deltaTime)
self.hasCelerity = GetHasTech(self, kTechId.ShiftHive) == true
self.hasRegeneration = GetHasTech(self, kTechId.CragHive) == true
--]]
if self.hasRegeneration then
--if self.hasRegeneration then

if self:GetIsHealable() and ( not self.timeLastAlienAutoHeal or self.timeLastAlienAutoHeal + kAlienRegenerationTime <= Shared.GetTime() ) then

@@ -142,7 +140,7 @@ function DrifterAvoca:OnUpdate(deltaTime)

end

end
--end

self.canUseAbilities = self.timeAbilityUsed + kDrifterAbilityCooldown < Shared.GetTime()

@@ -165,4 +163,82 @@ function DrifterAvoca:OnUpdate(deltaTime)
end

end
Shared.LinkClassToMap("DrifterAvoca", DrifterAvoca.kMapName, networkVars)
local function PlayOrderedSounds(self)

StartSoundEffectOnEntity(Drifter.kOrdered3DSoundName, self)

local commanders = GetEntitiesForTeam("Commander", self:GetTeamNumber())
local currentComm = commanders and commanders[1] or nil

if currentComm then
Server.PlayPrivateSound(currentComm, Drifter.kOrdered2DSoundName, currentComm, 1.0, Vector(0, 0, 0))
end

end
function Drifter:OnOverrideOrder(order)

local orderTarget = nil

if order:GetParam() ~= nil then
orderTarget = Shared.GetEntity(order:GetParam())
end

local orderType = order:GetType()

if orderType == kTechId.Default or orderType == kTechId.Grow or orderType == kTechId.Move then

if orderTarget and HasMixin(orderTarget, "Construct") and not orderTarget:GetIsBuilt() and GetAreFriends(self, orderTarget) and (not orderTarget.GetCanAutoBuild or orderTarget:GetCanAutoBuild()) then
order:SetType(kTechId.Grow)
elseif orderTarget and orderTarget:isa("Alien") and orderTarget:GetIsAlive() then
order:SetType(kTechId.Follow)
else
order:SetType(kTechId.Move)
end

end

if GetAreEnemies(self, orderTarget) then
order.orderParam = -1
end

PlayOrderedSounds(self)

end
function Drifter:ProcessGrowOrder(moveSpeed, deltaTime)

local currentOrder = self:GetCurrentOrder()

if currentOrder ~= nil then

local target = Shared.GetEntity(currentOrder:GetParam())

if not target or target:GetIsBuilt() or not target:GetIsAlive() then
self:CompletedCurrentOrder()
else

local targetPos = target:GetOrigin()
local toTarget = targetPos - self:GetOrigin()
-- Continuously turn towards the target. But don't mess with path finding movement if it was done.

if (toTarget):GetLength() > 3 then
self:MoveToTarget(PhysicsMask.AIMovement, targetPos, moveSpeed, deltaTime)
else

if toTarget then
self:SmoothTurn(deltaTime, GetNormalizedVector(toTarget), 0)
end
local speed = 0.025
-- if target:isa("Hive") then
-- speed = speed / 4
-- end
if IsBeingGrown(self, target) then target:Construct(speed) end
target:RefreshDrifterConstruct()
self.constructing = true
end

end

end

end
--Shared.LinkClassToMap("Drifter", Drifter.kMapName, networkVars)
@@ -0,0 +1,62 @@
if Server then


local origInit = Egg.OnInitialized
function Egg:OnInitialized()
origInit(self)
self:AddTimedCallback(Egg.ResearchSpecifics, 8 )
end

function Egg:GetClassToGestate()
return self:GetMapNameOf()
end

function Egg:GetMapNameOf()
local techId = self:GetTechId()
local mapanme = LookupTechData(self:GetGestateTechId(), kTechDataMapName, Skulk.kMapName)
--Print("mapanme is %s", mapanme)

if techId == kTechId.GorgeEgg then
-- Print("GorgeEgg")
return Gorge.kMapName
elseif techId == kTechId.LerkEgg then
-- Print("LerkEgg")
return Lerk.kMapName
elseif techId == kTechId.FadeEgg then
-- Print("FadeEgg")
return Fade.kMapName
elseif techId == kTechId.OnosEgg then
-- Print("OnosEgg")
return Onos.kMapName
end
return Skulk.kMapName
end

function Egg:ResearchSpecifics()

local techIds = {}
local tree = GetTechTree(2)

if self:GetTechId() == kTechId.Egg then
table.insert(techIds, kTechId.GorgeEgg )
elseif self:GetTechId() == kTechId.GorgeEgg then
table.insert(techIds, kTechId.LerkEgg )
elseif self:GetTechId() == kTechId.LerkEgg and GetHasTech(self, kTechId.BioMassNine) then
table.insert(techIds, kTechId.FadeEgg )
elseif self:GetTechId() == kTechId.FadeEgg and GetHasTech(self, kTechId.BioMassNine) then
table.insert(techIds, kTechId.OnosEgg )
end

local random = table.random(techIds)
local techNode = tree:GetTechNode(random)

if techNode then
self:SetResearching(techNode, self)
self.Auto = false
end


return false
end

end
@@ -0,0 +1,60 @@
if Server then


function Exosuit:OnUseDeferred()
-- Print("Derp")
local player = self.useRecipient
self.useRecipient = nil

if player and not player:GetIsDestroyed() and self:GetIsValidRecipient(player) then

local weapons = player:GetWeapons()
for i = 1, #weapons do
weapons[i]:SetParent(nil)
end

local exoPlayer = nil

if self.layout == "MinigunMinigun" then
exoPlayer = player:GiveDualExo()
elseif self.layout == "RailgunRailgun" then
exoPlayer = player:GiveDualRailgunExo()
elseif self.layout == "ClawRailgun" then
exoPlayer = player:GiveClawRailgunExo()
elseif self.layout == "WelderWelder" then
exoPlayer = player:GiveDualWelder()
elseif self.layout == "FlamerFlamer" then
exoPlayer = player:GiveDualFlamer()
else
exoPlayer = player:GiveExo()
end

if exoPlayer then

for i = 1, #weapons do
exoPlayer:StoreWeapon(weapons[i])
end

exoPlayer:SetMaxArmor(self:GetMaxArmor())
exoPlayer:SetArmor(self:GetArmor())
exoPlayer:SetFlashlightOn(self:GetFlashlightOn())
exoPlayer:TransferParasite(self)

local newAngles = player:GetViewAngles()
newAngles.pitch = 0
newAngles.roll = 0
newAngles.yaw = GetYawFromVector(self:GetCoords().zAxis)
exoPlayer:SetOffsetAngles(newAngles)
-- the coords of this entity are the same as the players coords when he left the exo, so reuse these coords to prevent getting stuck
exoPlayer:SetCoords(self:GetCoords())

self:TriggerEffects("pickup")
DestroyEntity(self)

end

end

end

end
@@ -0,0 +1,260 @@
Script.Load("lua/StunMixin.lua")
Script.Load("lua/PhaseGateUserMixin.lua")
Script.Load("lua/Mixins/LadderMoveMixin.lua")
Script.Load("lua/Additions/ExoWelder.lua")

local networkVars = {


--isLockedEjecting = "private boolean",

-- wallboots = "private boolean",
-- wallWalking = "compensated boolean",
-- timeLastWallWalkCheck = "private compensated time",

}
/*
local kNormalWallWalkFeelerSize = 0.25
local kNormalWallWalkRange = 0.3
local kJumpWallRange = 0.4
local kJumpWallFeelerSize = 0.1
local kWallJumpInterval = 0.4
local kWallJumpForce = 5.2 // scales down the faster you are
local kMinWallJumpForce = 0.1
local kVerticalWallJumpForce = 4.3
*/

AddMixinNetworkVars(StunMixin, networkVars)
AddMixinNetworkVars(PhaseGateUserMixin, networkVars)
AddMixinNetworkVars(LadderMoveMixin, networkVars)

local kDualWelderModelName = PrecacheAsset("models/marine/exosuit/exosuit_rr.model")
local kDualWelderAnimationGraph = PrecacheAsset("models/marine/exosuit/exosuit_rr.animation_graph")

local kHoloMarineMaterialname = PrecacheAsset("cinematics/vfx_materials/marine_ip_spawn.material")



local origcreate = Exo.OnCreate
function Exo:OnCreate()
origcreate(self)
InitMixin(self, PhaseGateUserMixin)
InitMixin(self, LadderMoveMixin)
-- InitMixin(self, WallMovementMixin)
--self.isLockedEjecting = false
-- self.wallboots = true
-- self.wallWalking = false
-- self.wallWalkingNormalGoal = Vector.yAxis
-- self.timeLastWallJump = 0

end
/*
function Exo:GetIsWallWalking()
return self.wallWalking and self.wallboots
end
function Exo:GetIsWallWalkingPossible()
return true--not self:GetRecentlyJumped() and not self:GetCrouching() -- and self.wallboots
end
function Exo:GetPerformsVerticalMove()
return self:GetIsWallWalking()
end
function Exo:OverrideUpdateOnGround(onGround)
return onGround or self:GetIsWallWalking()
end
local origangles = Marine.GetDesiredAngles
function Exo:GetDesiredAngles()

if self:GetIsWallWalking() then return self.currentWallWalkingAngles end
return origangles(self)
end
function Exo:GetIsUsingBodyYaw()
return not self:GetIsWallWalking()
end
function Exo:GetIsUsingBodyYaw()
return not self:GetIsWallWalking()
end
function Exo:GetAngleSmoothingMode()

if self:GetIsWallWalking() then
return "quatlerp"
else
return "euler"
end

end
function Exo:OnWorldCollision(normal, impactForce, newVelocity)

PROFILE("Exo:OnWorldCollision")

self.wallWalking = self:GetIsWallWalkingPossible() and normal.y < 0.5

end
function Exo:PreUpdateMove(input, runningPrediction)
PROFILE("Exo:PreUpdateMove")
self.prevY = self:GetOrigin().y

if self:GetIsWallWalking() then

// Most of the time, it returns a fraction of 0, which means
// trace started outside the world (and no normal is returned)
local goal = self:GetAverageWallWalkingNormal(kNormalWallWalkRange, kNormalWallWalkFeelerSize)
if goal ~= nil then

self.wallWalkingNormalGoal = goal
self.wallWalking = true
-- self:SetEnergy(self:GetEnergy() - kWallWalkEnergyCost)

else
self.wallWalking = false
end

end

if not self:GetIsWallWalking() then
// When not wall walking, the goal is always directly up (running on ground).
self.wallWalkingNormalGoal = Vector.yAxis
end



// if self.leaping and Shared.GetTime() > self.timeOfLeap + kLeapTime then
// self.leaping = false
// end

self.currentWallWalkingAngles = self:GetAnglesFromWallNormal(self.wallWalkingNormalGoal or Vector.yAxis) or self.currentWallWalkingAngles


end
function Exo:GetMoveSpeedIs2D()
return not self:GetIsWallWalking()
end
function Exo:GetCanStep()
return not self:GetIsWallWalking()
end
*/


local function HealSelf(self)


local toheal = true
-- Print("toheal is %s", toheal)
if toheal then
local amt = kNanoArmorHealPerSecond
amt = amt * ConditionalValue(self:GetIsInCombat(), 0, 2)
self:SetArmor(self:GetArmor() + amt, true)
end
return true
end

local kPhaseDelay = 2

function Exo:GetCanPhase()

if Server then
return self:GetIsAlive() and Shared.GetTime() > self.timeOfLastPhase + kPhaseDelay and not GetConcedeSequenceActive()
else
return self:GetIsAlive() and Shared.GetTime() > self.timeOfLastPhase + kPhaseDelay
end
end

local oninit = Exo.OnInitialized
function Exo:OnInitialized()

oninit(self)
InitMixin(self, StunMixin)
self:SetTechId(kTechId.Exo)
self:AddTimedCallback(function() HealSelf(self) return true end, 1)
-- self.currentWallWalkingAngles = Angles(0.0, 0.0, 0.0)
-- self.timeLastWallJump = 0
end
local origmodel = Exo.InitExoModel

function Exo:InitExoModel()

local hasWelders = false
local modelName = kDualWelderModelName
local graphName = kDualWelderAnimationGraph

if self.layout == "WelderWelder" or self.layout == "FlamerFlamer" then
modelName = kDualWelderModelName
graphName = kDualWelderAnimationGraph
self.hasDualGuns = true
hasWelders = true
self:SetModel(modelName, graphName)
end


if hasWelders then
else
origmodel(self)
end





end
local origweapons = Exo.InitWeapons
function Exo:InitWeapons()

local weaponHolder = self:GetWeapon(ExoWeaponHolder.kMapName)
if not weaponHolder then
weaponHolder = self:GiveItem(ExoWeaponHolder.kMapName, false)
end


if self.layout == "WelderWelder" then
weaponHolder:SetWelderWeapons()
self:SetHUDSlotActive(1)
return
elseif self.layout == "FlamerFlamer" then
weaponHolder:SetFlamerWeapons()
self:SetHUDSlotActive(1)
return
end



origweapons(self)


end



function Exo:GetIsStunAllowed()
return not self.timeLastStun or self.timeLastStun + 8 < Shared.GetTime()
end

function Exo:OnStun()
if Server then
local stunwall = CreateEntity(StunWall.kMapName, self:GetOrigin(), 2)
StartSoundEffectForPlayer(AlienCommander.kBoneWallSpawnSound, self)
end
end

/*
function Exo:EjectExo()

if self:GetCanEject() then

if Server then
self:PerformDelayedEject()
end

end

end
if Server then

function Exo:PerformDelayedEject()
self:SetCameraDistance(3)
if Client then CreateSpinEffect(self) end
self.isLockedEjecting = true
self:AddTimedCallback(function() self.isLockedEjecting = false self:SetCameraDistance(0) Exo.PerformEject(self) end, 1)

end
end
*/
Shared.LinkClassToMap("Exo", Exo.kMapName, networkVars)
@@ -0,0 +1,72 @@
ModLoader.SetupFileHook( "lua/Marine.lua", "lua/Marine_Avoca.lua", "post" )

ModLoader.SetupFileHook( "lua/Alien.lua", "lua/Alien_Avoca.lua", "post" )

ModLoader.SetupFileHook( "lua/Exo.lua", "lua/Exo_Avoca.lua", "post" )

ModLoader.SetupFileHook( "lua/Whip.lua", "lua/Whip_Avoca.lua", "post" )

ModLoader.SetupFileHook( "lua/Hive.lua", "lua/Hive_Avoca.lua", "post" )

ModLoader.SetupFileHook( "lua/Armory.lua", "lua/Armory_Avoca.lua", "post" )

ModLoader.SetupFileHook( "lua/Egg.lua", "lua/Egg_Avoca.lua", "post" )

ModLoader.SetupFileHook( "lua/Location.lua", "lua/Location_Avoca.lua", "post" )

ModLoader.SetupFileHook( "lua/Cyst.lua", "lua/Cyst_Avoca.lua", "post" )

ModLoader.SetupFileHook( "lua/Balance.lua", "lua/Balance_Avoca.lua", "post" )

ModLoader.SetupFileHook( "lua/BalanceHealth.lua", "lua/BalanceHealth_Avoca.lua", "post" )

ModLoader.SetupFileHook( "lua/Shade.lua", "lua/Shade_Avoca.lua", "post" )

ModLoader.SetupFileHook( "lua/Shift.lua", "lua/Shift_Avoca.lua", "post" )

ModLoader.SetupFileHook( "lua/ARC.lua", "lua/ARC_Avoca.lua", "post" )

ModLoader.SetupFileHook( "lua/PowerPointLightHandler.lua", "lua/PowerPointLightHandler_Avoca.lua", "post" )


ModLoader.SetupFileHook( "lua/RoboticsFactory.lua", "lua/RoboticsFactory_Avoca.lua", "post" )


ModLoader.SetupFileHook( "lua/PhaseGate.lua", "lua/PhaseGate_Avoca.lua", "post" )

ModLoader.SetupFileHook( "lua/Crag.lua", "lua/Crag_Avoca.lua", "post" )

ModLoader.SetupFileHook( "lua/Gorge.lua", "lua/Gorge_Avoca.lua", "post" )

ModLoader.SetupFileHook( "lua/SentryBattery.lua", "lua/SentryBattery_Avoca.lua", "post" )

ModLoader.SetupFileHook( "lua/Drifter.lua", "lua/Drifter_Avoca.lua", "post" )

ModLoader.SetupFileHook( "lua/PowerPoint.lua", "lua/PowerPoint_Avoca.lua", "post" )

ModLoader.SetupFileHook( "lua/Sentry.lua", "lua/Sentry_Avoca.lua", "post" )

ModLoader.SetupFileHook( "lua/Exo.lua", "lua/Exo_Avoca.lua", "post" )

ModLoader.SetupFileHook( "lua/CommandStation.lua", "lua/CommandStation_Avoca.lua", "post" )

ModLoader.SetupFileHook( "lua/PrototypeLab.lua", "lua/PrototypeLab_Avoca.lua", "post" )

ModLoader.SetupFileHook( "lua/Weapons/Marine/ExoWeaponHolder.lua", "lua/Weapons/Marine/ExoWeaponHolder_Avoca.lua", "post" )

ModLoader.SetupFileHook( "lua/TechData.lua", "lua/TechData_Avoca.lua", "post" )

ModLoader.SetupFileHook( "lua/MarineTeam.lua", "lua/MarineTeam_Avoca.lua", "post" )

ModLoader.SetupFileHook( "lua/Exosuit.lua", "lua/ExoSuit_Avoca.lua", "post" )

ModLoader.SetupFileHook( "lua/InfantryPortal.lua", "lua/InfantryPortal_Avoca.lua", "post" )

ModLoader.SetupFileHook( "lua/CommandStructure.lua", "lua/CommandStructure_Avoca.lua", "post" )

ModLoader.SetupFileHook( "lua/Spectator.lua", "lua/Spectator_Avoca.lua", "post" )

ModLoader.SetupFileHook( "lua/Weapons/Marine/Flamethrower.lua", "lua/Weapons/Marine/Flamethrower_Avoca.lua", "post" )

ModLoader.SetupFileHook( "lua/TechTreeConstants.lua", "lua/TechTreeConstants_Avoca.lua", "post" )