Diff
checker
Text
Text
Images
Documents
Excel
Folders
Legal
Enterprise
Desktop
Pricing
Sign in
Download Diffchecker Desktop
Compare text
Find the difference between two text files
Tools
History
Real-time editor
Hide unchanged lines
Disable line wrap
Layout
Split
Unified
Diff precision
Smart
Word
Char
Syntax highlighting
Choose syntax
Ignore
Transform text
Go to first change
Edit input
Diffchecker Desktop
The most secure way to run Diffchecker. Get the Diffchecker Desktop app: your diffs never leave your computer!
Get Desktop
Untitled diff
Created
11 years ago
Diff never expires
Clear
Export
Share
Explain
16 removals
Lines
Total
Removed
Characters
Total
Removed
To continue using this feature, upgrade to
Diff
checker
Pro
View Pricing
246 lines
Copy
9 additions
Lines
Total
Added
Characters
Total
Added
To continue using this feature, upgrade to
Diff
checker
Pro
View Pricing
239 lines
Copy
local BaseHassler = Class(function(self, inst)
local BaseHassler = Class(function(self, inst)
self.inst = inst
self.inst = inst
self.warning = false
self.warning = false
self.timetoattack = nil
self.timetoattack = nil
self.warnduration = 60
self.warnduration = 60
self.timetonextwarningsound = 0
self.timetonextwarningsound = 0
self.announcewarningsoundinterval = 4
self.announcewarningsoundinterval = 4
self.hasslerprefab = "deerclops"
self.hasslerprefab = "deerclops"
self.warningsound = "dontstarve/creatures/deerclops/distant"
self.warningsound = "dontstarve/creatures/deerclops/distant"
self.attacksperwinter = 1
self.attacksperwinter = 1
self.attackduringsummer = false
self.attackduringsummer = false
self.attackdelay = nil
self.attackdelay = nil
self.attackrandom = nil
self.attackrandom = nil
Copy
Copied
Copy
Copied
self.inst:ListenForEvent("snowcoverchange", function(inst
)
self.inst:ListenForEvent("snowcoverchange", function(inst
, data)
local snow_cover = GetSeasonManager() and GetSeasonManager():GetSnowPercent() or 0
if
data and data.
snow
>= 0.2 then
if
snow
_cover
>= 0.2 then
if not self.timetoattack then
if not self.timetoattack then
self:StartAttacks()
self:StartAttacks()
end
end
Copy
Copied
Copy
Copied
elseif
snow
_cover
<= 0 and self.attackduringsummer and not self.timetoattack then
elseif
data and data.
snow
<= 0 and self.attackduringsummer and not self.timetoattack then
self:StartAttacks()
self:StartAttacks()
else
else
self:CeaseAttacks()
self:CeaseAttacks()
end
end
end, GetWorld() )
end, GetWorld() )
end)
end)
local HASSLER_SPAWN_DIST = 40
local HASSLER_SPAWN_DIST = 40
local WANDER_AWAY_DIST = 100
local WANDER_AWAY_DIST = 100
function BaseHassler:SetHasslerPrefab(prefab)
function BaseHassler:SetHasslerPrefab(prefab)
self.hasslerprefab = prefab
self.hasslerprefab = prefab
end
end
function BaseHassler:SetWarningSound(sound)
function BaseHassler:SetWarningSound(sound)
self.warningsound = sound
self.warningsound = sound
end
end
function BaseHassler:SetAttacksPerWinter(attacks)
function BaseHassler:SetAttacksPerWinter(attacks)
self.attacksperwinter = attacks
self.attacksperwinter = attacks
end
end
function BaseHassler:SetAttackDuringSummer(attack)
function BaseHassler:SetAttackDuringSummer(attack)
self.attackduringsummer = attack
self.attackduringsummer = attack
end
end
function BaseHassler:OnSave()
function BaseHassler:OnSave()
if not self.noserial then
if not self.noserial then
return
return
{
{
warning = self.warning,
warning = self.warning,
timetoattack = self.timetoattack,
timetoattack = self.timetoattack,
attackdelay = self.attackdelay,
attackdelay = self.attackdelay,
attackrandom = self.attackrandom,
attackrandom = self.attackrandom,
}
}
end
end
self.noserial = false
self.noserial = false
end
end
function BaseHassler:OnLoad(data)
function BaseHassler:OnLoad(data)
self.warning = data.warning or false
self.warning = data.warning or false
self.timetoattack = data.timetoattack
self.timetoattack = data.timetoattack
self.attackdelay = data.attackdelay
self.attackdelay = data.attackdelay
self.attackrandom = data.attackrandom
self.attackrandom = data.attackrandom
if self.timetoattack then
if self.timetoattack then
self.inst:StartUpdatingComponent(self)
self.inst:StartUpdatingComponent(self)
end
end
end
end
function BaseHassler:OnProgress()
function BaseHassler:OnProgress()
self.noserial = true
self.noserial = true
end
end
function BaseHassler:GetDebugString()
function BaseHassler:GetDebugString()
if not self.timetoattack then
if not self.timetoattack then
return "DORMANT"
return "DORMANT"
elseif self.timetoattack > 0 then
elseif self.timetoattack > 0 then
return string.format("%s Deerclops is coming in %2.2f", self.warning and "WARNING" or "WAITING", self.timetoattack)
return string.format("%s Deerclops is coming in %2.2f", self.warning and "WARNING" or "WAITING", self.timetoattack)
else
else
return string.format("ATTACKING!!!")
return string.format("ATTACKING!!!")
end
end
end
end
Copy
Copied
Copy
Copied
function BaseHassler:LongUpdate(dt)
self:OnUpdate(dt)
end
function BaseHassler:OnUpdate(dt)
function BaseHassler:OnUpdate(dt)
if not self.timetoattack then
if not self.timetoattack then
self:CeaseAttacks()
self:CeaseAttacks()
return
return
end
end
self.timetoattack = self.timetoattack - dt
self.timetoattack = self.timetoattack - dt
if self.timetoattack <= 0 then
if self.timetoattack <= 0 then
self.warning = false
self.warning = false
self:ReleaseHassler()
self:ReleaseHassler()
self:CeaseAttacks()
self:CeaseAttacks()
else
else
if not self.warning and self.timetoattack < self.warnduration then
if not self.warning and self.timetoattack < self.warnduration then
self.warning = true
self.warning = true
self.timetonextwarningsound = 0
self.timetonextwarningsound = 0
end
end
end
end
if self.warning then
if self.warning then
self.timetonextwarningsound = self.timetonextwarningsound - dt
self.timetonextwarningsound = self.timetonextwarningsound - dt
if self.timetonextwarningsound <= 0 then
if self.timetonextwarningsound <= 0 then
self.announcewarningsoundinterval = self.announcewarningsoundinterval - 1
self.announcewarningsoundinterval = self.announcewarningsoundinterval - 1
if self.announcewarningsoundinterval <= 0 then
if self.announcewarningsoundinterval <= 0 then
self.announcewarningsoundinterval = 10 + math.random(5)
self.announcewarningsoundinterval = 10 + math.random(5)
Copy
Copied
Copy
Copied
GetPlayer()
.components.talker:Say(GetString(
GetPlayer()
.prefab, "ANNOUNCE_DEERCLOPS"))
self.inst
.components.talker:Say(GetString(
self.inst
.prefab, "ANNOUNCE_DEERCLOPS"))
end
end
local inst = CreateEntity()
local inst = CreateEntity()
inst.entity:AddTransform()
inst.entity:AddTransform()
inst.entity:AddSoundEmitter()
inst.entity:AddSoundEmitter()
inst.persists = false
inst.persists = false
local theta = math.random() * 2 * PI
local theta = math.random() * 2 * PI
local radius = 5
local radius = 5
self.timetonextwarningsound = 15 + math.random(4)
self.timetonextwarningsound = 15 + math.random(4)
if self.timetoattack < 30 then
if self.timetoattack < 30 then
self.timetonextwarningsound = 10 + math.random(1)
self.timetonextwarningsound = 10 + math.random(1)
radius = radius
radius = radius
elseif self.timetoattack < 60 then
elseif self.timetoattack < 60 then
radius = radius + 10
radius = radius + 10
elseif self.timetoattack < 90 then
elseif self.timetoattack < 90 then
radius = radius + 15
radius = radius + 15
else
else
radius = radius + 20
radius = radius + 20
end
end
Copy
Copied
Copy
Copied
local offset = Vector3(
GetPlayer()
.Transform:GetWorldPosition()) + Vector3(radius * math.cos( theta ), 0, -radius * math.sin( theta ))
local offset = Vector3(
self.inst
.Transform:GetWorldPosition()) + Vector3(radius * math.cos( theta ), 0, -radius * math.sin( theta ))
inst.Transform:SetPosition(offset.x,offset.y,offset.z)
inst.Transform:SetPosition(offset.x,offset.y,offset.z)
inst.SoundEmitter:PlaySound(self.warningsound)
inst.SoundEmitter:PlaySound(self.warningsound)
inst:DoTaskInTime(1.5, function() inst:Remove() end)
inst:DoTaskInTime(1.5, function() inst:Remove() end)
end
end
end
end
end
end
function BaseHassler:StartAttacks()
function BaseHassler:StartAttacks()
local timeLeftInSeason = GetSeasonManager():GetDaysLeftInSeason() * TUNING.TOTAL_DAY_TIME
local timeLeftInSeason = GetSeasonManager():GetDaysLeftInSeason() * TUNING.TOTAL_DAY_TIME
if self.attacksperwinter > 0 then
if self.attacksperwinter > 0 then
if self.attacksperwinter < 1 then
if self.attacksperwinter < 1 then
--special case: plan attack for NEXT season
--special case: plan attack for NEXT season
local summersToSkip = math.floor( (1 / self.attacksperwinter) - 1 )
local summersToSkip = math.floor( (1 / self.attacksperwinter) - 1 )
local wintersToSkip = math.max(0, summersToSkip-1)
local wintersToSkip = math.max(0, summersToSkip-1)
self.attackdelay = 0.5*timeLeftInSeason + TUNING.TOTAL_DAY_TIME*(summersToSkip*GetSeasonManager().summerlength + wintersToSkip*GetSeasonManager().winterlength)
self.attackdelay = 0.5*timeLeftInSeason + TUNING.TOTAL_DAY_TIME*(summersToSkip*GetSeasonManager().summerlength + wintersToSkip*GetSeasonManager().winterlength)
self.attackrandom = 0.25*timeLeftInSeason
self.attackrandom = 0.25*timeLeftInSeason
else
else
self.attackdelay = timeLeftInSeason / self.attacksperwinter
self.attackdelay = timeLeftInSeason / self.attacksperwinter
self.attackrandom = 0.25*self.attackdelay
self.attackrandom = 0.25*self.attackdelay
end
end
self:PlanNextAttack()
self:PlanNextAttack()
self.inst:StartUpdatingComponent(self)
self.inst:StartUpdatingComponent(self)
end
end
end
end
function BaseHassler:PlanNextAttack()
function BaseHassler:PlanNextAttack()
if (not GetSeasonManager():IsWinter() and not self.attackduringsummer) or not self.attackdelay then
if (not GetSeasonManager():IsWinter() and not self.attackduringsummer) or not self.attackdelay then
self:CeaseAttacks()
self:CeaseAttacks()
return
return
end
end
self.timetoattack = GetRandomWithVariance(self.attackdelay, self.attackrandom or 0)
self.timetoattack = GetRandomWithVariance(self.attackdelay, self.attackrandom or 0)
end
end
function BaseHassler:CeaseAttacks()
function BaseHassler:CeaseAttacks()
self.timetoattack = nil
self.timetoattack = nil
self.warning = false
self.warning = false
self.inst:StopUpdatingComponent(self)
self.inst:StopUpdatingComponent(self)
end
end
function BaseHassler:GetSpawnPoint(pt)
function BaseHassler:GetSpawnPoint(pt)
local theta = math.random() * 2 * PI
local theta = math.random() * 2 * PI
local radius = HASSLER_SPAWN_DIST
local radius = HASSLER_SPAWN_DIST
local offset = FindWalkableOffset(pt, theta, radius, 12, true)
local offset = FindWalkableOffset(pt, theta, radius, 12, true)
if offset then
if offset then
return pt+offset
return pt+offset
end
end
end
end
function BaseHassler:GetWanderAwayPoint(pt)
function BaseHassler:GetWanderAwayPoint(pt)
local theta = math.random() * 2 * PI
local theta = math.random() * 2 * PI
local radius = WANDER_AWAY_DIST
local radius = WANDER_AWAY_DIST
local ground = GetWorld()
local ground = GetWorld()
-- Walk the circle trying to find a valid spawn point
-- Walk the circle trying to find a valid spawn point
local steps = 12
local steps = 12
for i = 1, 12 do
for i = 1, 12 do
local offset = Vector3(radius * math.cos( theta ), 0, -radius * math.sin( theta ))
local offset = Vector3(radius * math.cos( theta ), 0, -radius * math.sin( theta ))
local wander_point = pt + offset
local wander_point = pt + offset
if ground.Map and ground.Map:GetTileAtPoint(wander_point.x, wander_point.y, wander_point.z) ~= GROUND.IMPASSABLE
if ground.Map and ground.Map:GetTileAtPoint(wander_point.x, wander_point.y, wander_point.z) ~= GROUND.IMPASSABLE
and ground.Pathfinder:IsClear(pt.x, pt.y, pt.z, wander_point.x, wander_point.y, wander_point.z, {ignorewalls = true} ) then
and ground.Pathfinder:IsClear(pt.x, pt.y, pt.z, wander_point.x, wander_point.y, wander_point.z, {ignorewalls = true} ) then
return wander_point
return wander_point
end
end
theta = theta - (2 * PI / steps)
theta = theta - (2 * PI / steps)
end
end
end
end
function BaseHassler:ReleaseHassler()
function BaseHassler:ReleaseHassler()
Copy
Copied
Copy
Copied
local pt = Vector3(
GetPlayer()
.Transform:GetWorldPosition())
local pt = Vector3(
self.inst
.Transform:GetWorldPosition())
local spawn_pt = self:GetSpawnPoint(pt)
local spawn_pt = self:GetSpawnPoint(pt)
if spawn_pt then
if spawn_pt then
local hassler = TheSim:FindFirstEntityWithTag(self.hasslerprefab)
local hassler = TheSim:FindFirstEntityWithTag(self.hasslerprefab)
if not hassler then
if not hassler then
hassler = SpawnPrefab(self.hasslerprefab)
hassler = SpawnPrefab(self.hasslerprefab)
end
end
if hassler then
if hassler then
hassler.Physics:Teleport(spawn_pt:Get())
hassler.Physics:Teleport(spawn_pt:Get())
Copy
Copied
Copy
Copied
local target = GetClosestInstWithTag("structure",
GetPlayer()
, 40)
local target = GetClosestInstWithTag("structure",
self.inst
, 40)
if target then
if target then
local targetPos = Vector3(target.Transform:GetWorldPosition() )
local targetPos = Vector3(target.Transform:GetWorldPosition() )
hassler.components.knownlocations:RememberLocation("targetbase", targetPos)
hassler.components.knownlocations:RememberLocation("targetbase", targetPos)
local wanderAwayPoint = self:GetWanderAwayPoint(targetPos)
local wanderAwayPoint = self:GetWanderAwayPoint(targetPos)
if wanderAwayPoint then
if wanderAwayPoint then
hassler.components.knownlocations:RememberLocation("home", wanderAwayPoint)
hassler.components.knownlocations:RememberLocation("home", wanderAwayPoint)
end
end
else
else
Copy
Copied
Copy
Copied
hassler.components.combat:SetTarget(
GetPlayer()
)
hassler.components.combat:SetTarget(
self.inst
)
end
end
end
end
end
end
end
end
return BaseHassler
return BaseHassler
Saved diffs
Original text
Open file
local BaseHassler = Class(function(self, inst) self.inst = inst self.warning = false self.timetoattack = nil self.warnduration = 60 self.timetonextwarningsound = 0 self.announcewarningsoundinterval = 4 self.hasslerprefab = "deerclops" self.warningsound = "dontstarve/creatures/deerclops/distant" self.attacksperwinter = 1 self.attackduringsummer = false self.attackdelay = nil self.attackrandom = nil self.inst:ListenForEvent("snowcoverchange", function(inst) local snow_cover = GetSeasonManager() and GetSeasonManager():GetSnowPercent() or 0 if snow_cover >= 0.2 then if not self.timetoattack then self:StartAttacks() end elseif snow_cover <= 0 and self.attackduringsummer and not self.timetoattack then self:StartAttacks() else self:CeaseAttacks() end end, GetWorld() ) end) local HASSLER_SPAWN_DIST = 40 local WANDER_AWAY_DIST = 100 function BaseHassler:SetHasslerPrefab(prefab) self.hasslerprefab = prefab end function BaseHassler:SetWarningSound(sound) self.warningsound = sound end function BaseHassler:SetAttacksPerWinter(attacks) self.attacksperwinter = attacks end function BaseHassler:SetAttackDuringSummer(attack) self.attackduringsummer = attack end function BaseHassler:OnSave() if not self.noserial then return { warning = self.warning, timetoattack = self.timetoattack, attackdelay = self.attackdelay, attackrandom = self.attackrandom, } end self.noserial = false end function BaseHassler:OnLoad(data) self.warning = data.warning or false self.timetoattack = data.timetoattack self.attackdelay = data.attackdelay self.attackrandom = data.attackrandom if self.timetoattack then self.inst:StartUpdatingComponent(self) end end function BaseHassler:OnProgress() self.noserial = true end function BaseHassler:GetDebugString() if not self.timetoattack then return "DORMANT" elseif self.timetoattack > 0 then return string.format("%s Deerclops is coming in %2.2f", self.warning and "WARNING" or "WAITING", self.timetoattack) else return string.format("ATTACKING!!!") end end function BaseHassler:LongUpdate(dt) self:OnUpdate(dt) end function BaseHassler:OnUpdate(dt) if not self.timetoattack then self:CeaseAttacks() return end self.timetoattack = self.timetoattack - dt if self.timetoattack <= 0 then self.warning = false self:ReleaseHassler() self:CeaseAttacks() else if not self.warning and self.timetoattack < self.warnduration then self.warning = true self.timetonextwarningsound = 0 end end if self.warning then self.timetonextwarningsound = self.timetonextwarningsound - dt if self.timetonextwarningsound <= 0 then self.announcewarningsoundinterval = self.announcewarningsoundinterval - 1 if self.announcewarningsoundinterval <= 0 then self.announcewarningsoundinterval = 10 + math.random(5) GetPlayer().components.talker:Say(GetString(GetPlayer().prefab, "ANNOUNCE_DEERCLOPS")) end local inst = CreateEntity() inst.entity:AddTransform() inst.entity:AddSoundEmitter() inst.persists = false local theta = math.random() * 2 * PI local radius = 5 self.timetonextwarningsound = 15 + math.random(4) if self.timetoattack < 30 then self.timetonextwarningsound = 10 + math.random(1) radius = radius elseif self.timetoattack < 60 then radius = radius + 10 elseif self.timetoattack < 90 then radius = radius + 15 else radius = radius + 20 end local offset = Vector3(GetPlayer().Transform:GetWorldPosition()) + Vector3(radius * math.cos( theta ), 0, -radius * math.sin( theta )) inst.Transform:SetPosition(offset.x,offset.y,offset.z) inst.SoundEmitter:PlaySound(self.warningsound) inst:DoTaskInTime(1.5, function() inst:Remove() end) end end end function BaseHassler:StartAttacks() local timeLeftInSeason = GetSeasonManager():GetDaysLeftInSeason() * TUNING.TOTAL_DAY_TIME if self.attacksperwinter > 0 then if self.attacksperwinter < 1 then --special case: plan attack for NEXT season local summersToSkip = math.floor( (1 / self.attacksperwinter) - 1 ) local wintersToSkip = math.max(0, summersToSkip-1) self.attackdelay = 0.5*timeLeftInSeason + TUNING.TOTAL_DAY_TIME*(summersToSkip*GetSeasonManager().summerlength + wintersToSkip*GetSeasonManager().winterlength) self.attackrandom = 0.25*timeLeftInSeason else self.attackdelay = timeLeftInSeason / self.attacksperwinter self.attackrandom = 0.25*self.attackdelay end self:PlanNextAttack() self.inst:StartUpdatingComponent(self) end end function BaseHassler:PlanNextAttack() if (not GetSeasonManager():IsWinter() and not self.attackduringsummer) or not self.attackdelay then self:CeaseAttacks() return end self.timetoattack = GetRandomWithVariance(self.attackdelay, self.attackrandom or 0) end function BaseHassler:CeaseAttacks() self.timetoattack = nil self.warning = false self.inst:StopUpdatingComponent(self) end function BaseHassler:GetSpawnPoint(pt) local theta = math.random() * 2 * PI local radius = HASSLER_SPAWN_DIST local offset = FindWalkableOffset(pt, theta, radius, 12, true) if offset then return pt+offset end end function BaseHassler:GetWanderAwayPoint(pt) local theta = math.random() * 2 * PI local radius = WANDER_AWAY_DIST local ground = GetWorld() -- Walk the circle trying to find a valid spawn point local steps = 12 for i = 1, 12 do local offset = Vector3(radius * math.cos( theta ), 0, -radius * math.sin( theta )) local wander_point = pt + offset if ground.Map and ground.Map:GetTileAtPoint(wander_point.x, wander_point.y, wander_point.z) ~= GROUND.IMPASSABLE and ground.Pathfinder:IsClear(pt.x, pt.y, pt.z, wander_point.x, wander_point.y, wander_point.z, {ignorewalls = true} ) then return wander_point end theta = theta - (2 * PI / steps) end end function BaseHassler:ReleaseHassler() local pt = Vector3(GetPlayer().Transform:GetWorldPosition()) local spawn_pt = self:GetSpawnPoint(pt) if spawn_pt then local hassler = TheSim:FindFirstEntityWithTag(self.hasslerprefab) if not hassler then hassler = SpawnPrefab(self.hasslerprefab) end if hassler then hassler.Physics:Teleport(spawn_pt:Get()) local target = GetClosestInstWithTag("structure", GetPlayer(), 40) if target then local targetPos = Vector3(target.Transform:GetWorldPosition() ) hassler.components.knownlocations:RememberLocation("targetbase", targetPos) local wanderAwayPoint = self:GetWanderAwayPoint(targetPos) if wanderAwayPoint then hassler.components.knownlocations:RememberLocation("home", wanderAwayPoint) end else hassler.components.combat:SetTarget(GetPlayer()) end end end end return BaseHassler
Changed text
Open file
local BaseHassler = Class(function(self, inst) self.inst = inst self.warning = false self.timetoattack = nil self.warnduration = 60 self.timetonextwarningsound = 0 self.announcewarningsoundinterval = 4 self.hasslerprefab = "deerclops" self.warningsound = "dontstarve/creatures/deerclops/distant" self.attacksperwinter = 1 self.attackduringsummer = false self.attackdelay = nil self.attackrandom = nil self.inst:ListenForEvent("snowcoverchange", function(inst, data) if data and data.snow >= 0.2 then if not self.timetoattack then self:StartAttacks() end elseif data and data.snow <= 0 and self.attackduringsummer and not self.timetoattack then self:StartAttacks() else self:CeaseAttacks() end end, GetWorld() ) end) local HASSLER_SPAWN_DIST = 40 local WANDER_AWAY_DIST = 100 function BaseHassler:SetHasslerPrefab(prefab) self.hasslerprefab = prefab end function BaseHassler:SetWarningSound(sound) self.warningsound = sound end function BaseHassler:SetAttacksPerWinter(attacks) self.attacksperwinter = attacks end function BaseHassler:SetAttackDuringSummer(attack) self.attackduringsummer = attack end function BaseHassler:OnSave() if not self.noserial then return { warning = self.warning, timetoattack = self.timetoattack, attackdelay = self.attackdelay, attackrandom = self.attackrandom, } end self.noserial = false end function BaseHassler:OnLoad(data) self.warning = data.warning or false self.timetoattack = data.timetoattack self.attackdelay = data.attackdelay self.attackrandom = data.attackrandom if self.timetoattack then self.inst:StartUpdatingComponent(self) end end function BaseHassler:OnProgress() self.noserial = true end function BaseHassler:GetDebugString() if not self.timetoattack then return "DORMANT" elseif self.timetoattack > 0 then return string.format("%s Deerclops is coming in %2.2f", self.warning and "WARNING" or "WAITING", self.timetoattack) else return string.format("ATTACKING!!!") end end function BaseHassler:OnUpdate(dt) if not self.timetoattack then self:CeaseAttacks() return end self.timetoattack = self.timetoattack - dt if self.timetoattack <= 0 then self.warning = false self:ReleaseHassler() self:CeaseAttacks() else if not self.warning and self.timetoattack < self.warnduration then self.warning = true self.timetonextwarningsound = 0 end end if self.warning then self.timetonextwarningsound = self.timetonextwarningsound - dt if self.timetonextwarningsound <= 0 then self.announcewarningsoundinterval = self.announcewarningsoundinterval - 1 if self.announcewarningsoundinterval <= 0 then self.announcewarningsoundinterval = 10 + math.random(5) self.inst.components.talker:Say(GetString(self.inst.prefab, "ANNOUNCE_DEERCLOPS")) end local inst = CreateEntity() inst.entity:AddTransform() inst.entity:AddSoundEmitter() inst.persists = false local theta = math.random() * 2 * PI local radius = 5 self.timetonextwarningsound = 15 + math.random(4) if self.timetoattack < 30 then self.timetonextwarningsound = 10 + math.random(1) radius = radius elseif self.timetoattack < 60 then radius = radius + 10 elseif self.timetoattack < 90 then radius = radius + 15 else radius = radius + 20 end local offset = Vector3(self.inst.Transform:GetWorldPosition()) + Vector3(radius * math.cos( theta ), 0, -radius * math.sin( theta )) inst.Transform:SetPosition(offset.x,offset.y,offset.z) inst.SoundEmitter:PlaySound(self.warningsound) inst:DoTaskInTime(1.5, function() inst:Remove() end) end end end function BaseHassler:StartAttacks() local timeLeftInSeason = GetSeasonManager():GetDaysLeftInSeason() * TUNING.TOTAL_DAY_TIME if self.attacksperwinter > 0 then if self.attacksperwinter < 1 then --special case: plan attack for NEXT season local summersToSkip = math.floor( (1 / self.attacksperwinter) - 1 ) local wintersToSkip = math.max(0, summersToSkip-1) self.attackdelay = 0.5*timeLeftInSeason + TUNING.TOTAL_DAY_TIME*(summersToSkip*GetSeasonManager().summerlength + wintersToSkip*GetSeasonManager().winterlength) self.attackrandom = 0.25*timeLeftInSeason else self.attackdelay = timeLeftInSeason / self.attacksperwinter self.attackrandom = 0.25*self.attackdelay end self:PlanNextAttack() self.inst:StartUpdatingComponent(self) end end function BaseHassler:PlanNextAttack() if (not GetSeasonManager():IsWinter() and not self.attackduringsummer) or not self.attackdelay then self:CeaseAttacks() return end self.timetoattack = GetRandomWithVariance(self.attackdelay, self.attackrandom or 0) end function BaseHassler:CeaseAttacks() self.timetoattack = nil self.warning = false self.inst:StopUpdatingComponent(self) end function BaseHassler:GetSpawnPoint(pt) local theta = math.random() * 2 * PI local radius = HASSLER_SPAWN_DIST local offset = FindWalkableOffset(pt, theta, radius, 12, true) if offset then return pt+offset end end function BaseHassler:GetWanderAwayPoint(pt) local theta = math.random() * 2 * PI local radius = WANDER_AWAY_DIST local ground = GetWorld() -- Walk the circle trying to find a valid spawn point local steps = 12 for i = 1, 12 do local offset = Vector3(radius * math.cos( theta ), 0, -radius * math.sin( theta )) local wander_point = pt + offset if ground.Map and ground.Map:GetTileAtPoint(wander_point.x, wander_point.y, wander_point.z) ~= GROUND.IMPASSABLE and ground.Pathfinder:IsClear(pt.x, pt.y, pt.z, wander_point.x, wander_point.y, wander_point.z, {ignorewalls = true} ) then return wander_point end theta = theta - (2 * PI / steps) end end function BaseHassler:ReleaseHassler() local pt = Vector3(self.inst.Transform:GetWorldPosition()) local spawn_pt = self:GetSpawnPoint(pt) if spawn_pt then local hassler = TheSim:FindFirstEntityWithTag(self.hasslerprefab) if not hassler then hassler = SpawnPrefab(self.hasslerprefab) end if hassler then hassler.Physics:Teleport(spawn_pt:Get()) local target = GetClosestInstWithTag("structure", self.inst, 40) if target then local targetPos = Vector3(target.Transform:GetWorldPosition() ) hassler.components.knownlocations:RememberLocation("targetbase", targetPos) local wanderAwayPoint = self:GetWanderAwayPoint(targetPos) if wanderAwayPoint then hassler.components.knownlocations:RememberLocation("home", wanderAwayPoint) end else hassler.components.combat:SetTarget(self.inst) end end end end return BaseHassler
Find difference