local module = {} local dens = game.Workspace.AirDensity * -game.Workspace.CompensateDensity.Value local bias = 0.2 local propeller_power_mod = 0.1 local propeller_cut_mod = 5/2 local propeller_reaction_mod = 0.05 game.Workspace.CompensateDensity.Changed:Connect(function() dens = game.Workspace.AirDensity * -game.Workspace.CompensateDensity.Value end) _G.Events.Command.Event:Connect(function(message) local value = message:match("setprop%((.-)%)") if not value then return end if tonumber(value) then game.Workspace.CompensateDensity = tonumber(value) _G.Events.Notification:Fire("Set Prop Density","PropBias.Value = "..value) else _G.Events.Notification:Fire("Set Prop Density","Invalid number.") end end) local function setup(this,propeller,context) local angle = _G.GetValue(propeller,"Trim",30) for _,child in pairs(propeller:GetChildren()) do if child.Name == "Blade" then local welds = child:GetJoints() local joint = child:FindFirstChild("Weld") if not child:FindFirstChild("Weld") then local c0 = propeller.PrimaryPart.CFrame:ToObjectSpace(child.CFrame) joint = Instance.new("Motor6D") joint.Name = "Weld" joint.Parent = child joint.Part0 = propeller.PrimaryPart joint.Part1 = child joint.C0 = c0 end local flip = 0 if angle < 0 then flip = 180 end local axis = (propeller:GetAttribute("Axis") or Vector3.new(0,0,1)) * (math.rad(-angle+flip)) local rotation = CFrame.Angles(axis.X,axis.Y,axis.Z) joint.C1 = rotation for _,weld in pairs(welds) do if weld:IsA("WeldConstraint") then weld:Destroy() end end end end end function module.new(this,propeller,context) local size = propeller:GetExtentsSize() this.scale = size.X * size.Z * 1.5 this.length = size.X this.power = _G.GetValue(propeller,"Force",1000) * this.scale * 0.01 this.direction = _G.GetValue(propeller,"Direction",CFrame.identity) this.rotor = propeller:FindFirstChild("Spin") or propeller:FindFirstChild("Hinge") this.trim = _G.GetValue(propeller,"Trim",30) this.blur = propeller:FindFirstChild("Blur") if not this.rotor then error("Missing rotor") end this.force = _G.GetInstance(propeller,"VectorForce") this.sound = _G.GetInstance(this.rotor,"PropSound") this.sound:Play() setup(this,propeller,context) return this end function module.update(this,propeller,context) print("upd") setup(this,propeller,context) end function module.idle(this,engine) return true end local a = 300 local function limit(f) return math.tanh(f/a)*a end local begin = tick() module.run = _G.Protect(function(this,propeller,context) local angular_velocity = ((this.rotor.CFrame.Rotation * this.direction):PointToObjectSpace(this.rotor.AssemblyAngularVelocity)).X local linear_velocity = angular_velocity * math.sin(math.rad(this.trim)) local air_velocity = this.rotor.CFrame.Rotation:PointToObjectSpace(this.rotor.AssemblyLinearVelocity).X local real_velocity = limit((linear_velocity * propeller_cut_mod * this.length) - air_velocity) local rpm = (angular_velocity/(math.pi*2))*60 local multiplier = (this.sound:GetAttribute("Multiplier") or 1) * 0.01 this.force.Force = Vector3.new(0,0,-real_velocity*this.power*propeller_power_mod*dens) this.rotor:ApplyAngularImpulse( (this.rotor.CFrame.Rotation * this.direction).RightVector * -angular_velocity * math.cos(math.rad(this.trim)) * propeller_reaction_mod) context.replicate(this,propeller,module,math.abs(rpm*dens*multiplier)) return true end) module.replication_delta = 0.1 function module.replicate(this,propeller,context,value) this.sound.PlaybackSpeed = math.clamp(value,0.1,1.5) this.sound.Volume = math.clamp(value,0,this.sound:GetAttribute("Max") or 1) if this.blur then this.blur.Transparency = math.clamp(1-value,0.3,1) end for _,blade in pairs(propeller:GetChildren()) do if blade.Name == "Blade" then blade.Transparency = math.clamp(value,0,0.7) end end end module.messages = { trim = function(this,object,context,value) end } module.messages.default = module.messages.trim module.manifest = { "Propeller", "Turbine", "LargePropeller", "BiPropeller", "Jet" } return module