|
DefineClass.ComponentLight = { |
|
__parents = { "CObject" }, |
|
flags = { cfLight = true, cofComponentLight = true, } |
|
} |
|
|
|
for name, func in pairs(ComponentLightFunctions) do |
|
ComponentLight[name] = func |
|
end |
|
|
|
local lightmodel_lights = {"A", "B", "C", "D"} |
|
DefineClass.Light = { |
|
__parents = { "Object", "InvisibleObject", "ComponentAttach", "ComponentLight" }, |
|
flags = { cfConstructible = false, gofRealTimeAnim = true, efShadow = false, efSunShadow = false, |
|
gofDetailClass0 = true, gofDetailClass1 = true, |
|
}, |
|
|
|
|
|
properties = { |
|
{ id = "DetailClass", name = "Detail Class", editor = "dropdownlist", |
|
items = {"Default", "Essential", "Optional", "Eye Candy"}, default = "Eye Candy", |
|
}, |
|
{ category = "Visuals", id = "Color", editor = "color", autoattach_prop = true, dont_save = function(obj) |
|
if not IsValid(obj) then return false end |
|
if obj:GetLightmodelColorIndexNumber() ~= 0 then return true end |
|
return false |
|
end, |
|
read_only = function(obj) |
|
if not IsValid(obj) then return false end |
|
if obj:GetLightmodelColorIndexNumber() ~= 0 then return true end |
|
return false |
|
end, |
|
}, |
|
{ category = "Visuals", id = "LightmodelColorIndex", editor = "set", items = lightmodel_lights, max_items_in_set = 1, default = {}, autoattach_prop = true,}, |
|
{ category = "Visuals", id = "OriginalColor", editor = "color", default = RGB(255, 255, 255), no_edit = true, dont_save = true }, |
|
{ category = "Visuals", id = "Intensity", editor = "number", min = 0, max = 255, slider = true, autoattach_prop = true, }, |
|
{ category = "Visuals", id = "Exterior", editor = "bool", autoattach_prop = true, }, |
|
{ category = "Visuals", id = "Interior", editor = "bool", autoattach_prop = true, }, |
|
{ category = "Visuals", id = "InteriorAndExteriorWhenHasShadowmap", editor = "bool", autoattach_prop = true, }, |
|
{ category = "Visuals", id = "Volume", helper = "volume", editor = "object", default = false, base_class = "Volume" }, |
|
{ category = "Visuals", id = "ConstantIntensity", editor = "number", default = 0, autoattach_prop = true, slider = true, max = 127, min = -128 }, |
|
{ category = "Visuals", id = "AttenuationShape", editor = "number", default = 0, autoattach_prop = true, slider = true, max = 255, min = 0 }, |
|
{ category = "Visuals", id = "CastShadows", editor = "bool", autoattach_prop = true }, |
|
{ category = "Visuals", id = "DetailedShadows", editor = "bool", autoattach_prop = true }, |
|
{ id = "ColorModifier", editor = false }, |
|
{ id = "Occludes", editor = false }, |
|
{ id = "Walkable", editor = false }, |
|
{ id = "ApplyToGrids", editor = false }, |
|
{ id = "Collision", editor = false }, |
|
{ id = "Color1", editor = false }, |
|
{ id = "ParentSIModulation", editor = "number", default = 100, min = 0, max = 255, slider = true, autoattach_prop = true, no_edit = function(o) |
|
return IsKindOf(o, "CObject") |
|
end, help = "To be used by the AutoAttach system."}, |
|
}, |
|
|
|
Color = RGB(255,255,255), |
|
Intensity = 100, |
|
Interior = true, |
|
Exterior = true, |
|
InteriorAndExteriorWhenHasShadowmap = true, |
|
CastShadows = false, |
|
DetailedShadows = false, |
|
|
|
Init = function(self) |
|
self:SetColor(self.Color) |
|
self:SetIntensity(self.Intensity) |
|
self:SetInterior(self.Interior) |
|
self:SetExterior(self.Exterior) |
|
self:SetInteriorAndExteriorWhenHasShadowmap(self.InteriorAndExteriorWhenHasShadowmap) |
|
self:SetConstantIntensity(0) |
|
self:SetAttenuationShape(0) |
|
self:SetLightmodelColorIndex(empty_table) |
|
self:SetCastShadows(self.CastShadows) |
|
self:SetDetailedShadows(self.DetailedShadows) |
|
end, |
|
|
|
GetCastShadows = function(self) return self:GetLightFlags(const.elfCastShadows) end, |
|
SetCastShadows = function(self, value) |
|
self.CastShadows = value |
|
if value then |
|
self:SetLightFlags(const.elfCastShadows) |
|
else |
|
self:ClearLightFlags(const.elfCastShadows) |
|
end |
|
end, |
|
|
|
GetDetailedShadows = function(self) return self:GetLightFlags(const.elfDetailedShadows) end, |
|
SetDetailedShadows = function(self, value) |
|
self.DetailedShadows = value |
|
if value then |
|
self:SetLightFlags(const.elfDetailedShadows) |
|
else |
|
self:ClearLightFlags(const.elfDetailedShadows) |
|
end |
|
end, |
|
|
|
GetColor = function(self) |
|
local index = self:GetLightmodelColorIndexNumber() |
|
if index ~= 0 then return GetSceneParamColor("LightColor" .. index) end |
|
return self:GetColor0() |
|
end, |
|
SetColor = function(self, rgb) self:SetColor0(rgb) self:SetColor1(rgb) end, |
|
GetColor0 = function(self) return self:GetColorAtIndex(0) end, |
|
GetColor1 = function(self) return self:GetColorAtIndex(1) end, |
|
SetColor0 = function(self, rgb) self:SetColorAtIndex(0, rgb) self:SetColorModifier(rgb or 0) end, |
|
SetColor1 = function(self, rgb) self:SetColorAtIndex(1, rgb) end, |
|
|
|
GetExterior = function(self) |
|
return self:GetLightFlags(const.elfExterior) |
|
end, |
|
|
|
SetExterior = function(self, value) |
|
self.Exterior = value |
|
if value then |
|
self:SetLightFlags(const.elfExterior) |
|
else |
|
self:ClearLightFlags(const.elfExterior) |
|
end |
|
end, |
|
|
|
GetInterior = function(self) |
|
return self:GetLightFlags(const.elfInterior) |
|
end, |
|
|
|
SetInterior = function(self, value) |
|
self.Interior = value |
|
if value then |
|
self:SetLightFlags(const.elfInterior) |
|
else |
|
self:ClearLightFlags(const.elfInterior) |
|
end |
|
end, |
|
|
|
GetInteriorAndExteriorWhenHasShadowmap = function(self) |
|
return self:GetLightFlags(const.elfInteriorAndExteriorWhenHasShadowmap) |
|
end, |
|
|
|
SetInteriorAndExteriorWhenHasShadowmap = function(self, value) |
|
self.InteriorAndExteriorWhenHasShadowmap = value |
|
if value then |
|
self:SetLightFlags(const.elfInteriorAndExteriorWhenHasShadowmap) |
|
else |
|
self:ClearLightFlags(const.elfInteriorAndExteriorWhenHasShadowmap) |
|
end |
|
end, |
|
|
|
SetLightmodelColorIndex = function(self, val) |
|
local index = 0 |
|
local activated_key = false |
|
for key, value in pairs(val or empty_table) do |
|
if value then activated_key = key end |
|
end |
|
if activated_key then |
|
index = table.find(lightmodel_lights, activated_key) |
|
end |
|
assert(index >= 0 and index <= 4) |
|
|
|
|
|
self:ClearLightFlags(const.elfColorIndexMask) |
|
self:SetLightFlags(index << const.elfColorIndexShift) |
|
end, |
|
|
|
GetLightmodelColorIndex = function(self) |
|
local index = self:GetLightmodelColorIndexNumber() |
|
if index == 0 then return {} end |
|
return { [lightmodel_lights[index]] = true } |
|
end, |
|
|
|
SetIntensity = function(self, value) self:SetIntensityAtIndex(0, value) self:SetIntensityAtIndex(1, value) end, |
|
SetIntensity0 = function(self, value) self:SetIntensityAtIndex(0, value) end, |
|
SetIntensity1 = function(self, value) self:SetIntensityAtIndex(1, value) end, |
|
GetIntensity0 = function(self, value) return self:GetIntensityAtIndex(0) end, |
|
GetIntensity1 = function(self, value) return self:GetIntensityAtIndex(1) end, |
|
GetIntensity = function(self, value) return self:GetIntensityAtIndex(0), self:GetIntensityAtIndex(1) end, |
|
|
|
GetAlwaysRenderable = function(self) return self:GetGameFlags(const.gofAlwaysRenderable) end, |
|
SetAlwaysRenderable = function(self, value) |
|
if value == true then |
|
self:SetGameFlags(const.gofAlwaysRenderable) |
|
else |
|
self:ClearGameFlags(const.gofAlwaysRenderable) |
|
end |
|
end, |
|
|
|
SetBehavior = function(self, b) |
|
if b == "flicker" then |
|
self:SetLightFlags(const.elfFlicker) |
|
else |
|
self:ClearLightFlags(const.elfFlicker) |
|
end |
|
end, |
|
|
|
CurrTime = function(self) |
|
if self:GetGameFlags( const.gofRealTimeAnim ) > 0 then |
|
return RealTime() |
|
end |
|
return GameTime() |
|
end, |
|
|
|
Fade = function(self, color, intensity, time) |
|
self:SetBehavior("fade") |
|
self:SetTimes(self:CurrTime(), self:CurrTime() + time) |
|
self:SetColor0(self:GetColor1()) |
|
self:SetColor1(color) |
|
self:SetIntensity0(self:GetIntensity1()) |
|
self:SetIntensity1(intensity) |
|
end, |
|
|
|
Flicker = function(self, color, intensity, period, phase) |
|
self:SetBehavior("flicker") |
|
phase = self:CurrTime() - (phase or AsyncRand(period)) |
|
self:SetTimes(phase, phase + period * 300) |
|
self:SetColor(color) |
|
self:SetIntensity0(0) |
|
self:SetIntensity1(intensity) |
|
end, |
|
|
|
Steady = function(self, color, intensity) |
|
self:SetColor(color) |
|
self:SetBehavior("fade") |
|
self:SetTimes(-1,-1) |
|
self:SetIntensity(intensity) |
|
end, |
|
|
|
SetParentSIModulation = function(self, value) |
|
local parent = self:GetParent() |
|
if parent then |
|
parent:SetSIModulation(value) |
|
end |
|
end, |
|
GetParentSIModulation = function(self) |
|
local parent = self:GetParent() |
|
if parent then |
|
return parent:GetSIModulation() |
|
end |
|
return 100 |
|
end, |
|
|
|
SetVolume = function(self, volume_obj) |
|
self:SetTargetVolumeId(volume_obj and volume_obj.handle or 0) |
|
end, |
|
|
|
GetVolume = function(self) |
|
local handle = self:GetTargetVolumeId() |
|
if not handle or handle == 0 then return false end |
|
return HandleToObject[handle] |
|
end, |
|
|
|
SetContourOuterID = empty_func, |
|
} |
|
|
|
function Light:OnEditorSetProperty(prop_id) |
|
if prop_id == "DetailClass" then |
|
self:DestroyRenderObj() |
|
end |
|
end |
|
|
|
const.ShadowDirsComboItems = { |
|
[LastSetBit(const.eLightDirX) + 1] = { name = "+X" }, |
|
[LastSetBit(const.eLightDirNegX) + 1] = { name = "-X" }, |
|
[LastSetBit(const.eLightDirY) + 1] = { name = "+Y" }, |
|
[LastSetBit(const.eLightDirNegY) + 1] = { name = "-Y" }, |
|
[LastSetBit(const.eLightDirZ) + 1] = { name = "+Z" }, |
|
[LastSetBit(const.eLightDirNegZ) + 1] = { name = "-Z" }, |
|
} |
|
local shadowDirsDefault = 0 |
|
|
|
DefineClass.PointLight = { |
|
__parents = { "Light" }, |
|
entity = "PointLight", |
|
|
|
properties = { |
|
{ category = "Visuals", id = "SourceRadius", name = "Source Radius (cm)", editor = "number", min = guic, max=20*guim, default = 10*guic, scale = guic, slider = true, |
|
helper = "sradius", color = RGB(200, 200, 0), autoattach_prop = true, }, |
|
{ category = "Visuals", id = "AttenuationRadius", name = "Attenuation Radius", editor = "number", min = 0*guim, max=500*guim, default = 10*guim, scale = "m", slider = true, |
|
helper = "sradius", color = RGB(255, 0, 0), autoattach_prop = true, }, |
|
{ category = "Visuals", id = "ShadowDirs", name = "Shadow Dirs (To disable)", editor = "flags", items = const.ShadowDirsComboItems, default = shadowDirsDefault, size = 6, |
|
autoattach_prop = true, }, |
|
}, |
|
|
|
ShadowDirsDefault = shadowDirsDefault, |
|
SourceRadius = 1*guic, |
|
AttenuationRadius = 10*guim, |
|
|
|
Init = function(self) |
|
self:SetSourceRadius(self.SourceRadius) |
|
self:SetAttenuationRadius(self.AttenuationRadius) |
|
self:SetLightType(const.eLightTypePoint) |
|
self:SetShadowDirs(shadowDirsDefault) |
|
end, |
|
} |
|
|
|
DefineClass.LightFlicker = { |
|
__parents = {"InitDone"}, |
|
entity = "PointLight", |
|
properties = { |
|
{ id = "Color", editor = false }, |
|
{ id = "Intensity", editor = false }, |
|
{ category = "Visuals", id = "Color0", editor = "color", default = RGB(255,255,255), autoattach_prop = true, }, |
|
{ category = "Visuals", id = "Intensity0", editor = "number", default = 0, min = 0, max = 255, slider = true, autoattach_prop = true, }, |
|
{ category = "Visuals", id = "Color1", editor = "color", default = RGB(255,255,255), autoattach_prop = true, }, |
|
{ category = "Visuals", id = "Intensity1", editor = "number", default = 100, min = 0, max = 255, slider = true, autoattach_prop = true, }, |
|
{ category = "Visuals", id = "Period", editor = "number", default = 500, min = 0, max = 100000, scale = 1000, slider = true, autoattach_prop = true, }, |
|
}, |
|
|
|
|
|
Period = 40000, |
|
} |
|
|
|
function LightFlicker:Init() |
|
self:SetBehavior("flicker") |
|
self:SetColor(self.Color) |
|
self:SetIntensity0(0) |
|
self:SetIntensity1(self.Intensity) |
|
self:SetPeriod(self.Period) |
|
end |
|
|
|
function LightFlicker:GetPeriod() |
|
local t0,t1 = self:GetTimes() |
|
return t1 - t0 |
|
end |
|
|
|
function LightFlicker:SetPeriod(period) |
|
period = Max(period, 1) |
|
local phase = AsyncRand(period) |
|
local time = self:CurrTime() |
|
if self:CurrTime() < phase then |
|
self:SetTimes(0, period) |
|
else |
|
self:SetTimes(time - phase, time - phase + period) |
|
end |
|
end |
|
|
|
DefineClass.PointLightFlicker = { |
|
__parents = { "PointLight", "LightFlicker" }, |
|
} |
|
|
|
DefineClass.SpotLightFlicker = { |
|
__parents = { "SpotLight", "LightFlicker" }, |
|
} |
|
|
|
DefineClass.MaskedLight = { |
|
__parents = { "Light" }, |
|
properties = { |
|
{ category = "Visuals", id = "Mask", editor = "browse", folder = "Textures/Misc/LightMasks", help = "Specifies the texture that is going to be applied to modify the light appearance" }, |
|
{ category = "Visuals", id = "AnimX", editor = "number", min = 1, max = 16, help = "How many cuts on the X axis are specified in the mask texture. The animation is traversed left to right." }, |
|
{ category = "Visuals", id = "AnimY", editor = "number", min = 1, max = 16, help = "How many cuts on the Y axis are specified in the mask texture. The animation is traversed top to bottom." }, |
|
{ category = "Visuals", id = "AnimPeriod", editor = "number", min = 0, max = 256, scale = 10, help = "The period of the animation. If zero is specified, the animation is not applied." }, |
|
{ category = "Visuals", id = "ScaleMask", editor = "bool", default = false, }, |
|
}, |
|
|
|
|
|
Mask = "Textures/Misc/LightMasks/angle-attn.tga", |
|
ScaleMask = false, |
|
AnimX = 1, |
|
AnimY = 1, |
|
AnimPeriod = 256, |
|
|
|
Init = function(self) |
|
self:SetMask(self.Mask) |
|
self:SetScaleMask(self.ScaleMask) |
|
self:SetAnimX(self.AnimX) |
|
self:SetAnimY(self.AnimY) |
|
self:SetAnimPeriod(self.AnimPeriod) |
|
end, |
|
|
|
GetScaleMask = function(self) return self:GetLightFlags(const.elfScaleMask) end, |
|
SetScaleMask = function(self, scale) |
|
if scale then |
|
self:SetLightFlags(const.elfScaleMask) |
|
else |
|
self:ClearLightFlags(const.elfScaleMask) |
|
end |
|
end, |
|
|
|
GetAnim = function(self, nshift) |
|
local flags = self:GetAnimParams() |
|
local anim_size = band(shift(flags, -nshift), const.elAnimMask) + 1 |
|
return anim_size |
|
end, |
|
|
|
SetAnim = function(self, nshift, num) |
|
local flags = self:GetAnimParams() |
|
local new_data = maskset(flags, shift(const.elAnimMask, nshift), shift(num-1, nshift)) |
|
self:SetAnimParams(new_data) |
|
end, |
|
|
|
GetAnimX = function(self) return self:GetAnim(const.elAnimXShift) end, |
|
SetAnimX = function(self, num) self:SetAnim(const.elAnimXShift, num) end, |
|
|
|
GetAnimY = function(self) return self:GetAnim(const.elAnimYShift) end, |
|
SetAnimY = function(self, num) self:SetAnim(const.elAnimYShift, num) end, |
|
|
|
GetMask = _GetCustomString, |
|
SetMask = _SetCustomString, |
|
|
|
GetAnimPeriod = function(self) |
|
return shift(band(self:GetAnimParams(), const.elAnimPeriodMask), -const.elAnimPeriodShift) |
|
end, |
|
SetAnimPeriod = function(self, period) |
|
local params = self:GetAnimParams() |
|
local new_params = maskset(params, const.elAnimPeriodMask, shift(period, const.elAnimPeriodShift)) |
|
self:SetAnimParams(new_params ) |
|
end, |
|
} |
|
|
|
DefineClass.BoxLight = { |
|
__parents = { "MaskedLight" }, |
|
entity = "PointLight", |
|
|
|
properties = { |
|
{ category = "Visuals", id = "BoxWidth", editor = "number", min = guim/10, max = 50*guim, slider = true, helper = "box3" }, |
|
{ category = "Visuals", id = "BoxHeight", editor = "number", min = guim/10, max = 50*guim, slider = true, helper = "box3" }, |
|
{ category = "Visuals", id = "BoxDepth", editor = "number", min = guim/10, max = 50*guim, slider = true, helper = "box3" }, |
|
}, |
|
|
|
|
|
BoxWidth = 5 * guim, |
|
BoxHeight = 5 * guim, |
|
BoxDepth = 5 * guim, |
|
|
|
Init = function(self) |
|
self:SetBoxWidth(self.BoxWidth) |
|
self:SetBoxHeight(self.BoxHeight) |
|
self:SetBoxDepth(self.BoxDepth) |
|
self:SetLightType(const.eLightTypeBox) |
|
end, |
|
} |
|
|
|
DefineClass.SpotLight = { |
|
__parents = { "PointLight", "MaskedLight" }, |
|
entity = "PointLight", |
|
|
|
properties = { |
|
{ category = "Visuals", id = "ConeInnerAngle", editor = "number", min = 5, max = (180 - 5), default = 45, slider = true, helper = "spotlighthelper", autoattach_prop = true, }, |
|
{ category = "Visuals", id = "ConeOuterAngle", editor = "number", min = 5, max = (180 - 5), default = 90, slider = true, helper = "spotlighthelper", autoattach_prop = true, }, |
|
}, |
|
|
|
|
|
ConeInnerAngle = 45, |
|
ConeOuterAngle = 90, |
|
|
|
target_helper = false, |
|
|
|
Init = function(self) |
|
self:SetConeInnerAngle(self.ConeInnerAngle) |
|
self:SetConeOuterAngle(self.ConeOuterAngle) |
|
self:SetLightType(const.eLightTypeSpot) |
|
end, |
|
|
|
GetConeInnerAngle = function(self) return self:GetInnerAngle() end, |
|
GetConeOuterAngle = function(self) return self:GetOuterAngle() end, |
|
} |
|
|
|
if Platform.developer then |
|
function SpotLight:SetConeInnerAngle(v) |
|
self:SetInnerAngle(v) |
|
if (v > self:GetOuterAngle()) then |
|
self:SetOuterAngle(v) |
|
end |
|
end |
|
function SpotLight:SetConeOuterAngle(v) |
|
self:SetOuterAngle(v) |
|
if (v < self:GetInnerAngle()) then |
|
self:SetInnerAngle(v) |
|
end |
|
end |
|
else |
|
function SpotLight:SetConeInnerAngle(v) self:SetInnerAngle(v) end |
|
function SpotLight:SetConeOuterAngle(v) self:SetOuterAngle(v) end |
|
end |
|
|
|
function SpotLight:OnEditorSetProperty(...) |
|
Light.OnEditorSetProperty(self, ...) |
|
PropertyHelpers_UpdateAllHelpers(self) |
|
end |
|
|
|
function SpotLight:ConfigureTargetHelper() |
|
if not self.target_helper or not IsValid(self.target_helper) then |
|
self.target_helper = PlaceObject("SpotHelper") |
|
self.target_helper.obj = self |
|
end |
|
|
|
local axis = self:GetOrientation() |
|
local pos = self:GetVisualPos() |
|
local o, closest, normal = IntersectSegmentWithClosestObj(pos, pos - axis * guim) |
|
if closest and normal and o ~= self.target_helper then |
|
self.target_helper:SetPos(closest) |
|
else |
|
local newPos = terrain.IntersectRay(pos, pos + axis) |
|
if newPos then |
|
self.target_helper:SetPos(newPos:SetZ(const.InvalidZ)) |
|
end |
|
end |
|
end |
|
|
|
function OnMsg.EditorSelectionChanged(objs) |
|
local isSpotLight = false |
|
for _, obj in ipairs(objs) do |
|
if obj.class == "SpotLight" then |
|
isSpotLight = true |
|
obj:ConfigureTargetHelper() |
|
elseif obj.class == "SpotHelper" then |
|
isSpotLight = true |
|
end |
|
end |
|
if not isSpotLight then |
|
MapForEach(true, "SpotHelper", function(spot_helper) |
|
DoneObject(spot_helper) |
|
end) |
|
end |
|
end |
|
|
|
function OnMsg.EditorCallback(id, objects, ...) |
|
if id == "EditorCallbackMove" or id == "EditorCallbackRotate" or id == "EditorCallbackPlace" then |
|
for _, obj in ipairs(objects) do |
|
if obj.class == "SpotLight" then |
|
obj:ConfigureTargetHelper() |
|
end |
|
end |
|
if id == "EditorCallbackMove" then |
|
for _, obj in ipairs(objects) do |
|
if obj.class == "SpotHelper" and obj.obj.class == "SpotLight" then |
|
obj.obj:SetOrientation(Normalize(obj.obj:GetVisualPos() - obj:GetVisualPos()), 0) |
|
end |
|
end |
|
end |
|
elseif id == "EditorCallbackDelete" then |
|
for _, obj in ipairs(objects) do |
|
if obj.class == "SpotLight" then |
|
DoneObject(obj.target_helper) |
|
obj.target_helper = false |
|
end |
|
end |
|
end |
|
end |
|
|
|
if Platform.developer and false then |
|
function OnMsg.NewMapLoaded() |
|
|
|
local masks = {} |
|
MapForEach("map", "Light", function(light) if light:HasMember("GetMask") then masks[light:GetMask()] = true end end) |
|
for mask, _ in pairs(masks) do |
|
local id = ResourceManager.GetResourceID(mask) |
|
if id == const.InvalidResourceID then |
|
printf("once", "Light mask texture '%s' is not present", mask) |
|
end |
|
end |
|
end |
|
end |
|
|
|
function PointLight:ConfigureInvisibleObjectHelper(helper) |
|
if not helper then return end |
|
local important = self:GetDetailClass() == "Essential" |
|
helper:SetScale(important and 100 or 60) |
|
if important then |
|
helper:SetColorModifier(self:GetCastShadows() and RGB(100, 10, 10) or RGB(20, 80, 100)) |
|
else |
|
helper:SetColorModifier(self:GetCastShadows() and RGB(100, 30, 30) or RGB(40, 80, 100)) |
|
end |
|
end |
|
|
|
DefineClass.AttachLightPropertyObject = { |
|
__parents = {"PropertyObject"}, |
|
|
|
properties = { |
|
{category = "Lights", id = "AttachLight", name = "Attach Light", editor = "bool", default = true}, |
|
}, |
|
} |
|
|
|
local detail_class_weight = {["Essential"] = 1, ["Optional"] = 2, ["Eye Candy"] = 3} |
|
|
|
function GetLights(filter) |
|
if GetMap() == "" then return end |
|
|
|
local lights = MapGet("map", "Light", const.efVisible, filter) or empty_table |
|
table.sort(lights, function(light1, light2) |
|
local weight1 = detail_class_weight[light1:GetDetailClass()] or 4 |
|
local weight2 = detail_class_weight[light2:GetDetailClass()] or 4 |
|
if weight1 == weight2 then |
|
return light1.handle < light2.handle |
|
else |
|
return weight1 < weight2 |
|
end |
|
end) |
|
|
|
return lights |
|
end |
|
|