Download CommonLua/Libs/Volumes/Classes/Debris.lua from sirnii/myspace: direct link, hf CLI and curl.
- Browser
- Download file 8.43 kB
-
https://huggingface.co/spaces/sirnii/myspace/resolve/main/CommonLua/Libs/Volumes/Classes/Debris.lua
- Command line
-
hf download hf://spaces/sirnii/myspace/CommonLua/Libs/Volumes/Classes/Debris.lua
-
curl -L -o Debris.lua https://huggingface.co/spaces/sirnii/myspace/resolve/main/CommonLua/Libs/Volumes/Classes/Debris.lua
8.43 kB
| g_DefaultMinDebris = 5 | |
| g_DefaultMaxDebris = 20 | |
| function dbgTestSP() | |
| Setpieces["FlagHillExplosion"]:Test() | |
| end | |
| DefineClass.Debris = { | |
| __parents = {"Object"}, | |
| flags = { efCollision = false, efApplyToGrids = false }, | |
| -- no persist required | |
| thread = false, | |
| time_fade_away_start = 0, | |
| -- persist required | |
| opacity = 100, | |
| time_disappear = 0, | |
| time_fade_away = 0, | |
| spawning_obj = false, | |
| } | |
| function Debris:Done() | |
| self:DestroyThread() | |
| end | |
| function Debris:DestroyThread() | |
| if self.thread ~= CurrentThread() then | |
| DeleteThread(self.thread) | |
| end | |
| end | |
| function Debris:StartPhase(phase, ...) | |
| self:DestroyThread() | |
| self.thread = CreateGameTimeThread(function(...) | |
| self[phase](...) | |
| end, self, ...) | |
| end | |
| function Debris.enum_obj(obj, x, y, z, nx, ny, nz) | |
| if IsKindOfClasses(obj, "Object") then | |
| return true | |
| end | |
| end | |
| local saneBox = box(-const.SanePosMaxXY, -const.SanePosMaxXY, const.SanePosMaxXY - 1, const.SanePosMaxXY - 1) | |
| local saneZ = const.SanePosMaxZ | |
| function MakeDebrisPosSane(pos) | |
| return ClampPoint(pos, saneBox):SetZ(Clamp(pos:z(), -saneZ + 1, saneZ - 1)) | |
| end | |
| local hundredSeventy = 170*60 | |
| function Debris:RotatingTravel(pos, time, rpm) | |
| if not rpm then | |
| local rpm_min, rpm_max = 20, 80 | |
| rpm = rpm_min * 360 + self:Random(rpm_max * 360) | |
| end | |
| local angle = MulDivTrunc(rpm, time, 1000) | |
| local clamped_pos = MakeDebrisPosSane(pos) | |
| self:SetPos(clamped_pos, time) | |
| local ticks = 1 + angle / hundredSeventy | |
| local dt = time / ticks | |
| local tt = 0 | |
| while tt < time do | |
| local dtt = Min(dt, time - tt) | |
| self:SetAngle(self:GetAngle() + angle * dtt / time, dtt) | |
| tt = tt + dt | |
| Sleep(dtt) | |
| end | |
| return rpm | |
| end | |
| local s_ExplodeDeviationSin = sin(const.DebrisExplodeDeviationAngle / 2) | |
| local s_ExplodeDeviationCos = cos(const.DebrisExplodeDeviationAngle / 2) | |
| local s_AxisX, s_AxisY, s_AxisZ = point(4096, 0, 0), point(0, 4096, 0), point(0, 0, 4096) | |
| local s_SlabSizeZ = const.SlabSizeZ | |
| local s_MinRadius = 5 * guic | |
| function Debris:GetRandomDirInCone(dir, radius) | |
| local cone_height = dir:Len() | |
| local cone_radius = MulDivTrunc(cone_height, s_ExplodeDeviationSin, s_ExplodeDeviationCos) | |
| local cone_base_len = Max(self:Random(cone_radius), s_MinRadius) | |
| local cone_base_pt = Rotate(point(cone_base_len, 0), self:Random(360 * 60)):SetZ(0) | |
| local dx, dy, dz = dir:xyz() | |
| if dx == 0 and dx == 0 and dz ~= 0 then | |
| cone_base_pt = (dz < 0) and -cone_base_pt or cone_base_pt | |
| else | |
| local axis = Cross(dir, s_AxisX) | |
| local angle = CalcAngleBetween(dir, s_AxisX) | |
| cone_base_pt = RotateAxis(cone_base_pt, axis, angle) | |
| end | |
| return SetLen(dir + cone_base_pt, Max(self:Random(radius), s_MinRadius)) | |
| end | |
| local min_vec_len = 500 | |
| function Debris:GetRandomInSphere(radius) | |
| local axis_z_rotated = RotateAxis(point(4096, 0, 0), s_AxisZ, self:Random(360 * 60)) | |
| local axis_y_rotated = RotateAxis(axis_z_rotated, s_AxisY, self:Random(360 * 60)) | |
| local axis_x_rotated = RotateAxis(axis_y_rotated, s_AxisY, self:Random(360 * 60)) | |
| local min = Min(min_vec_len, radius) | |
| return SetLen(axis_x_rotated, self:Random(radius - min) + min) | |
| end | |
| local explode_z_offset = const.SlabSizeZ / 2 | |
| local flags_enum = const.efVisible | |
| local flags_game_ignore = const.gofSolidShadow | |
| local slab_delay = const.DebrisExplodeSlabDelay | |
| function Debris:Explode(slab_pos, radius, origin_of_destruction) | |
| origin_of_destruction = origin_of_destruction or slab_pos | |
| local z_offset = -explode_z_offset + self:Random(2 * explode_z_offset) | |
| local has_origin = origin_of_destruction and slab_pos ~= origin_of_destruction | |
| local explode_dir = has_origin and SetLen(slab_pos - origin_of_destruction, 4096) or axis_z | |
| local cone_dir = has_origin and self:GetRandomDirInCone(explode_dir, radius) or self:GetRandomInSphere(radius) | |
| local fly_dir = origin_of_destruction and cone_dir or SetLen(cone_dir, Max(cone_dir:Len() + z_offset, s_MinRadius)) | |
| local slabs_dist = has_origin and origin_of_destruction:Dist(slab_pos) / s_SlabSizeZ or 0 | |
| if slabs_dist > 0 then | |
| local delay = (slabs_dist - 1) * slab_delay + self:Random(slab_delay) | |
| Sleep(delay) | |
| end | |
| local pos = slab_pos + fly_dir | |
| local time_explode = 20 + self:Random(200) + 100 * fly_dir:Len() / guim | |
| self:SetPos(slab_pos) | |
| local rpm = self:RotatingTravel(pos, time_explode) | |
| self:StartPhase("FallDown", rpm) | |
| end | |
| function Debris:FallDown(rpm) | |
| local src = self:GetPos() | |
| local dest = src:SetZ(terrain.GetHeight(src)) - axis_z | |
| local obj, pos, norm = GetClosestRayObj(src, dest, flags_enum, flags_game_ignore, Debris.enum_obj) | |
| if not pos then | |
| DoneObject(self) | |
| return | |
| end | |
| self:SetGravity() | |
| while true do | |
| local fall_time = self:GetGravityFallTime(pos) | |
| if CalcAngleBetween(norm, axis_z) > 30 * 60 and -norm ~= self:GetAxis() then -- -norm == self:GetAxis() makes setaxis assert | |
| -- too steep - orient to lay on the surface | |
| self:SetAxis(norm, fall_time) | |
| end | |
| self:RotatingTravel(pos, fall_time, rpm) | |
| local new_pos | |
| obj, new_pos, norm = GetClosestRayObj(pos, dest, flags_enum, flags_game_ignore, Debris.enum_obj) | |
| if not new_pos then | |
| DoneObject(self) | |
| return | |
| end | |
| if new_pos:Dist(pos) < s_SlabSizeZ / 2 then | |
| break | |
| end | |
| pos = new_pos | |
| end | |
| self:SetGravity(0) | |
| PlayFX("Debris", "hit", self) | |
| local disappear_time = const.DebrisDisappearTime | |
| local fade_away_time = const.DebrisFadeAwayTime- disappear_time + self:Random(2 * disappear_time) | |
| self:StartPhase("FadeAway", fade_away_time, disappear_time) | |
| end | |
| function Debris:ShouldBeVisibileWhileFading() | |
| return true | |
| end | |
| function Debris:FadeAway(time_fade_away, time_disappear) | |
| if not self:ShouldBeVisibileWhileFading() then | |
| DoneObject(self) | |
| return | |
| end | |
| self.time_fade_away = time_fade_away | |
| self.time_disappear = time_disappear | |
| self.time_fade_away_start = GameTime() | |
| self:SetOpacity(self.opacity) | |
| Sleep(self.time_fade_away) | |
| self:SetOpacity(0, self.time_disappear) | |
| Sleep(self.time_disappear) | |
| DoneObject(self) | |
| end | |
| function Debris:IsFadingAway() | |
| return self.time_fade_away ~= 0 or self.time_disappear ~= 0 | |
| end | |
| DefineClass.DebrisWeight = { | |
| __parents = {"PropertyObject"}, | |
| properties = { | |
| {id = "DebrisClass", name = "Debris Class", editor = "choice", items = ClassDescendantsCombo("Debris"), default = "" }, | |
| {id = "Weight", name = "Weight", editor = "number", default = 10 }, | |
| }, | |
| EditorView = Untranslated("<DebrisClass> (Weight: <Weight>)"), | |
| } | |
| local s_DebrisInfoCache = {} | |
| function GetDebrisInfo(entity) | |
| local cached = s_DebrisInfoCache[entity] | |
| if cached then | |
| return cached.classes, cached.debris_min, cached.debris_max | |
| end | |
| local entity_data = EntityData[entity] | |
| if not entity_data then | |
| return | |
| end | |
| local entity_data = entity_data.entity | |
| local classes = entity_data.debris_classes | |
| if classes then | |
| local new_classes, total_weight = {}, 0 | |
| for idx, entry in ipairs(classes) do | |
| total_weight = total_weight + entry.Weight | |
| new_classes[idx] = {class = entry.DebrisClass, weight = total_weight} | |
| end | |
| classes = new_classes | |
| classes.total_weight = total_weight | |
| end | |
| local min, max = entity_data.debris_min, entity_data.debris_max | |
| min = entity_data.debris_min or g_DefaultMinDebris | |
| max = entity_data.debris_max or g_DefaultMaxDebris | |
| -- store to the cache | |
| s_DebrisInfoCache[entity] = {classes = classes, debris_min = min, debris_max = max} | |
| return classes, min, max | |
| end | |
| if Platform.developer and Platform.pc and config.RunUnpacked and not Platform.ged then | |
| AppendClass.EntitySpecProperties = { | |
| properties = { | |
| -- Debris | |
| { category = "Debris", id = "debris_min", name = "Debris min" , editor = "number", default = g_DefaultMinDebris, min = 0, max = 20, | |
| no_edit = function(self) return not self.debris_classes or #self.debris_classes == 0 end, entitydata = true, | |
| }, | |
| { category = "Debris", id = "debris_max", name = "Debris max" , editor = "number", default = g_DefaultMaxDebris, min = 0, max = 50, | |
| no_edit = function(self) return not self.debris_classes or #self.debris_classes == 0 end, entitydata = true, | |
| }, | |
| { category = "Debris", id = "debris_list", name = "Debris list" , editor = "dropdownlist", default = "", | |
| items = PresetGroupCombo("DebrisList", "Default"), | |
| }, | |
| { category = "Debris", id = "debris_classes", name = "Debris classes", editor = "nested_list", default = false, | |
| base_class = "DebrisWeight", | |
| entitydata = function(prop_meta, self) | |
| return table.map(self.debris_classes, function(entry) | |
| return { DebrisClass = entry.DebrisClass, Weight = entry.Weight } | |
| end) | |
| end, | |
| }, | |
| }, | |
| } | |
| end | |