Roblox · Усиления
Выпил — на время прыгаешь в 2,5 раза выше и бегаешь немного быстрее (голубые и жёлтые искры). Повторный приём продлевает действие. Замедление и заморозка от оружия продолжают работать поверх.
Синим — что нужно создать.
StarterPack — или копии на карте для подбора └─ EnergyDrink (Tool) ├─ Handle (Part) — банка; Anchored и CanCollide выкл. │ └─ Use (Sound) — звук глотка ├─ Configuration (Configuration) │ ├─ JumpFactor (NumberValue) — во сколько раз выше прыжок, 2.5 │ ├─ SpeedFactor (NumberValue) — во сколько раз быстрее, 1.3 (1 — без ускорения) │ ├─ Duration (NumberValue) — секунд действия, 10 │ ├─ Uses (NumberValue) — 1 │ └─ Cooldown (NumberValue) — 1 ├─ Animation (Animation) — AnimationId (можно пусто) └─ EnergyDrinkServer (Script) ServerScriptService └─ WeaponEffects (ModuleScript) — общий модуль эффектов (версия с Heal и Boost)
Где: StarterPack → EnergyDrink · Script
Зачем: Усиливает прыжок и бег через Effects.Boost, считает использования, исчезает.
-- энергетик (Tool)
local tool = script.Parent
-- модель
local handle = tool:WaitForChild("Handle")
-- настройки
local config = tool:WaitForChild("Configuration")
-- звук использования
local useSound = handle:WaitForChild("Use")
-- анимация использования
local anim = tool:WaitForChild("Animation")
-- общий модуль эффектов (страница «Эффекты оружия»)
local Effects = require(game:GetService("ServerScriptService"):WaitForChild("WeaponEffects"))
-- время прошлого использования
local lastUse = 0
-- сколько раз ещё можно использовать
local uses = config.Uses.Value
-- подсказка на панели предметов
tool.ToolTip = "Энергетик: " .. uses
-- клик (или тап), пока предмет в руках; событие приходит и на сервер
tool.Activated:Connect(function()
-- Humanoid того, кто держит
local humanoid = tool.Parent:FindFirstChildOfClass("Humanoid")
-- нет персонажа или он мёртв
if not humanoid or humanoid.Health <= 0 then return end
-- время
local now = os.clock()
-- откат ещё не прошёл
if now - lastUse < config.Cooldown.Value then return end
-- запоминаем
lastUse = now
-- анимация задана
if anim.AnimationId ~= "" then
-- проигрываем
humanoid:LoadAnimation(anim):Play()
-- конец проверки
end
-- звук
useSound:Play()
-- прыжок выше в JumpFactor раз на Duration секунд
Effects.Boost(humanoid, "Jump", config.JumpFactor.Value, config.Duration.Value)
-- ускорение включено
if config.SpeedFactor.Value ~= 1 then
-- быстрее в SpeedFactor раз
Effects.Boost(humanoid, "Speed", config.SpeedFactor.Value, config.Duration.Value)
-- конец проверки
end
-- минус одно использование
uses -= 1
-- обновляем подсказку
tool.ToolTip = "Энергетик: " .. uses
-- использования кончились
if uses <= 0 then
-- убираем из рук; здесь скрипт продолжит работать — таймеры эффектов доиграют
tool.Parent = game:GetService("ServerScriptService")
-- минута на все таймеры (удали предмет сразу — эффект не выключится)
task.wait(60)
-- теперь удаляем совсем
tool:Destroy()
-- конец проверки
end
-- конец обработчика
end)Где: ServerScriptService · ModuleScript
Зачем: Общий модуль эффектов — один на всю игру: оружие, усиления и бег вызывают его. Уже есть в игре — второй не нужен.
-- удаление по таймеру
local Debris = game:GetService("Debris")
-- игроки — для ослепления
local Players = game:GetService("Players")
-- норма скорости и прыжка игрока
local StarterPlayer = game:GetService("StarterPlayer")
-- изменения каждой цели; исчезнувшие цели забываются сами
local mods = setmetatable({}, {__mode = "k"})
-- во сколько раз сильнее урон по цели с меткой
local MARK_BONUS = 1.5
-- таблица модуля
local Effects = {}
-- читает настройку; нет такой — значит 0 (эффект выключен)
local function Get(config, name)
-- ищем контейнер
local v = config:FindFirstChild(name)
-- есть — его значение
if v then return v.Value end
-- нет — ноль
return 0
-- конец функции
end
-- норма характеристики: к ней всё возвращается, когда эффекты кончились
local function Base(humanoid, stat)
-- уже знаем норму этой цели?
local saved = humanoid:GetAttribute("Base" .. stat)
-- знаем — её и берём (можно задать вручную атрибутом)
if saved then return saved end
-- NPC: его собственное значение (у быстрого врага — своё)
local value = humanoid[stat]
-- это игрок?
local player = Players:GetPlayerFromCharacter(humanoid.Parent)
-- скорость игрока
if player and stat == "WalkSpeed" then
-- норма из StarterPlayer — по умолчанию 16
value = StarterPlayer.CharacterWalkSpeed
-- прыжок игрока
elseif player and stat == "JumpHeight" then
-- норма из StarterPlayer — по умолчанию 7.2
value = StarterPlayer.CharacterJumpHeight
-- конец выбора
end
-- запоминаем норму на цели
humanoid:SetAttribute("Base" .. stat, value)
-- норма
return value
-- конец функции
end
-- пересчитывает характеристику: норма + все действующие изменения
local function Recalc(humanoid, stat)
-- сумма прибавок, произведение множителей и делителей, «установить»
local add, mul, div, set = 0, 1, 1, nil
-- текущее время
local now = os.clock()
-- все изменения этой цели
for _, m in pairs(mods[humanoid] or {}) do
-- та же характеристика и ещё действует
if m.stat == stat and (m.untilTime == nil or now < m.untilTime) then
-- прибавить
if m.op == "add" then add += m.value
-- умножить
elseif m.op == "mul" then mul *= m.value
-- разделить
elseif m.op == "div" then div *= m.value
-- установить — важнее всего
elseif m.op == "set" then set = m.value end
-- конец проверки
end
-- конец перебора
end
-- формула: (норма + прибавки) × множители ÷ делители
local value = (Base(humanoid, stat) + add) * mul / div
-- «установить» перекрывает всё (заморозка = 0)
if set then value = set end
-- не меньше нуля
value = math.max(value, 0)
-- прыжок
if stat == "JumpHeight" then
-- высота прыжка
humanoid.JumpHeight = value
-- та же высота через силу прыжка — работает при любой настройке игры
humanoid.JumpPower = math.sqrt(2 * workspace.Gravity * value)
-- скорость или здоровье
else
-- записываем
humanoid[stat] = value
-- конец выбора
end
-- конец функции
end
-- изменение: id — имя, stat — WalkSpeed / JumpHeight / MaxHealth, op — add / mul / div / set
function Effects.Modify(humanoid, id, stat, op, value, seconds)
-- на ноль не делим
if op == "div" and value == 0 then return end
-- список изменений цели
mods[humanoid] = mods[humanoid] or {}
-- он
local list = mods[humanoid]
-- без seconds — действует, пока не уберут
local untilTime = nil
-- изменение на время
if seconds and seconds > 0 then
-- до какого момента
untilTime = os.clock() + seconds
-- такое же изменение уже есть?
local old = list[id]
-- и оно кончится позже
if old and old.untilTime and old.untilTime > untilTime then
-- не укорачиваем
untilTime = old.untilTime
-- конец проверки
end
-- время конца — для видимых эффектов
humanoid:SetAttribute(id .. "Until", untilTime)
-- когда время выйдет
task.delay(seconds + 0.05, function()
-- это изменение
local m = list[id]
-- не продлили — кончилось
if m and m.untilTime and os.clock() >= m.untilTime then
-- убираем
list[id] = nil
-- конец проверки
end
-- пересчитываем: без эффектов — снова норма
Recalc(humanoid, stat)
-- конец отложенной функции
end)
-- конец проверки
end
-- записываем изменение (то же имя — заменяет старое)
list[id] = {stat = stat, op = op, value = value, untilTime = untilTime}
-- пересчитываем сразу
Recalc(humanoid, stat)
-- конец функции
end
-- убирает изменение по имени (например, отпустили Shift)
function Effects.Remove(humanoid, id)
-- изменения цели
local list = mods[humanoid]
-- такого нет
if not list or not list[id] then return end
-- какую характеристику оно меняло
local stat = list[id].stat
-- убираем
list[id] = nil
-- пересчитываем
Recalc(humanoid, stat)
-- конец функции
end
-- видимый эффект, пока действует attr; второй такой же не создаём
local function Show(humanoid, attr, name, make)
-- уже показан — время уже продлили
if humanoid.Parent:FindFirstChild(name, true) then return end
-- создаём эффект и узнаём, куда его положить
local visual, parent = make()
-- имя — чтобы найти его в следующий раз
visual.Name = name
-- показываем
visual.Parent = parent
-- отдельный поток — следит за временем
task.spawn(function()
-- пока цель жива и время не вышло
while humanoid.Parent and humanoid.Health > 0 and os.clock() < (humanoid:GetAttribute(attr) or 0) do
-- ждём
task.wait(0.1)
-- конец цикла
end
-- убираем эффект
visual:Destroy()
-- конец потока
end)
-- конец функции
end
-- урон каждую секунду: огонь, яд, кровотечение
local function Dot(humanoid, attr, name, seconds, damage, make, movingBonus)
-- продлеваем
humanoid:SetAttribute(attr, math.max(humanoid:GetAttribute(attr) or 0, os.clock() + seconds))
-- уже действует — хватит продления
if humanoid.Parent:FindFirstChild(name, true) then return end
-- видимый эффект
local visual, parent = make()
-- имя
visual.Name = name
-- показываем
visual.Parent = parent
-- центр цели — по нему видно, бежит ли она
local root = humanoid.Parent:FindFirstChild("HumanoidRootPart")
-- отдельный поток
task.spawn(function()
-- пока цель жива и время не вышло
while humanoid.Health > 0 and os.clock() < humanoid:GetAttribute(attr) do
-- раз в секунду
task.wait(1)
-- цель бежит?
local moving = root and root.AssemblyLinearVelocity.Magnitude > 2
-- кровотечение у бегущей цели
if movingBonus and moving then
-- вдвое сильнее
humanoid:TakeDamage(damage * 2)
-- иначе
else
-- обычный урон
humanoid:TakeDamage(damage)
-- конец выбора
end
-- конец цикла
end
-- эффект закончился
visual:Destroy()
-- конец потока
end)
-- конец функции
end
-- отбрасывает цель от стрелка или от центра взрыва
local function Knockback(root, attacker, origin, power)
-- центр взрыва, если он есть
local from = origin
-- это не взрыв
if not from then
-- центр атакующего
local attackerRoot = attacker and attacker:FindFirstChild("HumanoidRootPart")
-- не знаем, откуда толкать
if not attackerRoot then return end
-- толкаем от атакующего
from = attackerRoot.Position
-- конец проверки
end
-- направление по земле
local flat = (root.Position - from) * Vector3.new(1, 0, 1)
-- стоят в одной точке — направления нет
if flat.Magnitude < 0.1 then return end
-- точка приложения
local attachment = Instance.new("Attachment")
-- в центр цели
attachment.Parent = root
-- толчок; работает и на игроках — их физику считает их компьютер
local push = Instance.new("LinearVelocity")
-- куда приложен
push.Attachment0 = attachment
-- без ограничения силы
push.MaxForce = math.huge
-- назад и немного вверх
push.VectorVelocity = flat.Unit * power + Vector3.new(0, power * 0.4, 0)
-- толкаем
push.Parent = root
-- 0,2 секунды
Debris:AddItem(push, 0.2)
-- убираем и точку
Debris:AddItem(attachment, 0.2)
-- конец функции
end
-- молния между двумя точками
local function Beam(a, b)
-- парт-луч
local beam = Instance.new("Part")
-- не падает
beam.Anchored = true
-- ни с чем не сталкивается
beam.CanCollide = false
-- не мешает поиску целей
beam.CanQuery = false
-- светится
beam.Material = Enum.Material.Neon
-- фиолетовый
beam.Color = Color3.fromRGB(150, 120, 255)
-- длина — от точки до точки
beam.Size = Vector3.new(0.2, 0.2, (b - a).Magnitude)
-- между точками
beam.CFrame = CFrame.new(a, b) * CFrame.new(0, 0, -(b - a).Magnitude / 2)
-- показываем
beam.Parent = workspace
-- вспышка 0,2 секунды
Debris:AddItem(beam, 0.2)
-- конец функции
end
-- цепная молния: перескакивает на ближайших
local function Chain(attacker, first, config)
-- сколько прыжков
local count = Get(config, "ChainCount")
-- 0 — выключена
if count <= 0 then return end
-- дальность прыжка
local range = Get(config, "ChainRange")
-- не задана — 12
if range <= 0 then range = 12 end
-- первую цель уже ударили
local hit = {[first] = true}
-- откуда прыгает
local from = first.Parent:FindFirstChild("HumanoidRootPart")
-- настройки поиска
local params = OverlapParams.new()
-- не замечать из списка
params.FilterType = Enum.RaycastFilterType.Exclude
-- атакующего не бьём
params.FilterDescendantsInstances = {attacker}
-- прыжок за прыжком
for i = 1, count do
-- прыгать неоткуда
if not from then return end
-- ближайшая новая цель
local best, bestRoot, bestDist = nil, nil, range
-- всё вокруг
for _, part in pairs(workspace:GetPartBoundsInRadius(from.Position, range, params)) do
-- модель детали
local model = part:FindFirstAncestorOfClass("Model")
-- живая?
local target = model and model:FindFirstChildOfClass("Humanoid")
-- её центр
local targetRoot = model and model:FindFirstChild("HumanoidRootPart")
-- живая и ещё не ударена
if target and targetRoot and target.Health > 0 and not hit[target] then
-- расстояние
local dist = (targetRoot.Position - from.Position).Magnitude
-- ближе найденной
if dist < bestDist then
-- запоминаем
best, bestRoot, bestDist = target, targetRoot, dist
-- конец проверки
end
-- конец проверки
end
-- конец перебора
end
-- рядом никого — молния гаснет
if not best then return end
-- запоминаем
hit[best] = true
-- рисуем молнию
Beam(from.Position, bestRoot.Position)
-- урон молнии
best:TakeDamage(Get(config, "ChainDamage"))
-- следующий прыжок — отсюда
from = bestRoot
-- следующий прыжок
end
-- конец функции
end
-- белый экран у задетого игрока
local function Blind(humanoid, seconds)
-- это игрок?
local player = Players:GetPlayerFromCharacter(humanoid.Parent)
-- NPC не ослепить — у него нет экрана
if not player then return end
-- продлеваем
humanoid:SetAttribute("BlindUntil", math.max(humanoid:GetAttribute("BlindUntil") or 0, os.clock() + seconds))
-- экран игрока
local playerGui = player:FindFirstChild("PlayerGui")
-- уже ослеплён — хватит продления
if not playerGui or playerGui:FindFirstChild("BlindEffect") then return end
-- слой поверх экрана
local gui = Instance.new("ScreenGui")
-- имя
gui.Name = "BlindEffect"
-- на весь экран, включая верхнюю панель
gui.IgnoreGuiInset = true
-- белая заливка
local flash = Instance.new("Frame")
-- во весь экран
flash.Size = UDim2.fromScale(1, 1)
-- белая
flash.BackgroundColor3 = Color3.new(1, 1, 1)
-- почти непрозрачная
flash.BackgroundTransparency = 0.05
-- в слой
flash.Parent = gui
-- на экран игрока
gui.Parent = playerGui
-- следим за временем
task.spawn(function()
-- пока не вышло
while gui.Parent and os.clock() < humanoid:GetAttribute("BlindUntil") do
-- ждём
task.wait(0.1)
-- конец цикла
end
-- снова видно
gui:Destroy()
-- конец потока
end)
-- конец функции
end
-- попадание: урон и все эффекты из Configuration
function Effects.Hit(attacker, humanoid, config, origin)
-- цель уже мертва
if humanoid.Health <= 0 then return end
-- модель цели
local character = humanoid.Parent
-- её центр
local root = character:FindFirstChild("HumanoidRootPart")
-- урон
local damage = Get(config, "Damage")
-- на цели метка
if os.clock() < (humanoid:GetAttribute("MarkedUntil") or 0) then
-- урон ×1,5
damage = damage * MARK_BONUS
-- конец проверки
end
-- наносим урон
humanoid:TakeDamage(damage)
-- замедление
if Get(config, "SlowTime") > 0 then
-- скорость × SlowFactor на SlowTime секунд
Effects.Modify(humanoid, "Slow", "WalkSpeed", "mul", Get(config, "SlowFactor"), Get(config, "SlowTime"))
-- конец
end
-- заморозка
if Get(config, "FreezeTime") > 0 then
-- стоит
Effects.Modify(humanoid, "Freeze", "WalkSpeed", "set", 0, Get(config, "FreezeTime"))
-- не прыгает
Effects.Modify(humanoid, "FreezeJump", "JumpHeight", "set", 0, Get(config, "FreezeTime"))
-- ледяная подсветка
Show(humanoid, "FreezeUntil", "FreezeEffect", function()
-- подсветка всей модели
local ice = Instance.new("Highlight")
-- голубой лёд
ice.FillColor = Color3.fromRGB(150, 220, 255)
-- плотный
ice.FillTransparency = 0.3
-- белый контур
ice.OutlineColor = Color3.new(1, 1, 1)
-- на модель цели
return ice, character
-- конец функции
end)
-- конец
end
-- огонь, яд или ничего
local effect = config:FindFirstChild("Effect") and config.Effect.Value or "None"
-- огонь или яд
if root and (effect == "Fire" or effect == "Poison") and Get(config, "EffectTime") > 0 then
-- урон каждую секунду
Dot(humanoid, "EffectUntil", "WeaponEffect", Get(config, "EffectTime"), Get(config, "EffectDamage"), function()
-- огонь
if effect == "Fire" then
-- пламя на цели
return Instance.new("Fire"), root
-- конец
end
-- яд — облако
local smoke = Instance.new("Smoke")
-- ядовито-зелёное
smoke.Color = Color3.fromRGB(90, 220, 60)
-- полупрозрачное
smoke.Opacity = 0.5
-- на цели
return smoke, root
-- бонуса за бег нет
end, false)
-- конец
end
-- кровотечение
if root and Get(config, "BleedTime") > 0 then
-- урон каждую секунду
Dot(humanoid, "BleedUntil", "BleedEffect", Get(config, "BleedTime"), Get(config, "BleedDamage"), function()
-- капли
local drops = Instance.new("ParticleEmitter")
-- тёмно-красные
drops.Color = ColorSequence.new(Color3.fromRGB(170, 0, 0))
-- мелкие
drops.Size = NumberSequence.new(0.2)
-- живут полсекунды
drops.Lifetime = NumberRange.new(0.5)
-- 15 капель в секунду
drops.Rate = 15
-- падают вниз
drops.Acceleration = Vector3.new(0, -30, 0)
-- из центра цели
return drops, root
-- у бегущей цели — вдвое сильнее
end, true)
-- конец
end
-- отбрасывание
if root and Get(config, "Knockback") > 0 then
-- толкаем
Knockback(root, attacker, origin, Get(config, "Knockback"))
-- конец
end
-- вампиризм: доля урона в лечение
local steal = Get(config, "Lifesteal")
-- Humanoid атакующего
local attackerHumanoid = attacker and attacker:FindFirstChildOfClass("Humanoid")
-- вампиризм включён, атакующий жив
if steal > 0 and attackerHumanoid and attackerHumanoid.Health > 0 then
-- лечим, но не выше максимума
attackerHumanoid.Health = math.min(attackerHumanoid.MaxHealth, attackerHumanoid.Health + damage * steal)
-- конец
end
-- цепная молния, если ChainCount > 0
Chain(attacker, humanoid, config)
-- ослепление
if Get(config, "BlindTime") > 0 then
-- белый экран у игрока
Blind(humanoid, Get(config, "BlindTime"))
-- конец
end
-- метка
if Get(config, "MarkTime") > 0 then
-- продлеваем
humanoid:SetAttribute("MarkedUntil", math.max(humanoid:GetAttribute("MarkedUntil") or 0, os.clock() + Get(config, "MarkTime")))
-- красный контур
Show(humanoid, "MarkedUntil", "MarkEffect", function()
-- подсветка
local mark = Instance.new("Highlight")
-- без заливки
mark.FillTransparency = 1
-- красный контур — видно сквозь стены
mark.OutlineColor = Color3.fromRGB(255, 40, 40)
-- на модель цели
return mark, character
-- конец функции
end)
-- конец
end
-- конец функции
end
-- усиление: kind = "Speed" (скорость) или "Jump" (прыжок)
function Effects.Boost(humanoid, kind, factor, seconds)
-- мёртвым не помогает
if humanoid.Health <= 0 then return end
-- скорость
local stat = "WalkSpeed"
-- или прыжок
if kind == "Jump" then stat = "JumpHeight" end
-- × factor на seconds секунд; повторный приём продлевает
Effects.Modify(humanoid, "Boost" .. kind, stat, "mul", factor, seconds)
-- искры, пока действует
Show(humanoid, "Boost" .. kind .. "Until", "Boost" .. kind .. "Effect", function()
-- искры
local sparkles = Instance.new("Sparkles")
-- прыжок
if kind == "Jump" then
-- голубые
sparkles.SparkleColor = Color3.fromRGB(80, 200, 255)
-- скорость
else
-- жёлтые
sparkles.SparkleColor = Color3.fromRGB(255, 220, 60)
-- конец выбора
end
-- на центр персонажа
return sparkles, humanoid.Parent:FindFirstChild("HumanoidRootPart")
-- конец функции
end)
-- конец функции
end
-- лечение: сразу amount, потом regen в секунду seconds секунд
function Effects.Heal(humanoid, amount, regen, seconds)
-- мёртвых не лечим
if humanoid.Health <= 0 then return end
-- сразу, не выше максимума
humanoid.Health = math.min(humanoid.MaxHealth, humanoid.Health + amount)
-- восстановление выключено
if regen <= 0 or seconds <= 0 then return end
-- сколько в секунду
humanoid:SetAttribute("RegenRate", regen)
-- до какого времени
humanoid:SetAttribute("RegenUntil", math.max(humanoid:GetAttribute("RegenUntil") or 0, os.clock() + seconds))
-- уже восстанавливается — хватит продления
if humanoid.Parent:FindFirstChild("RegenEffect", true) then return end
-- зелёные искры, пока лечит
Show(humanoid, "RegenUntil", "RegenEffect", function()
-- искры
local sparkles = Instance.new("Sparkles")
-- зелёные
sparkles.SparkleColor = Color3.fromRGB(80, 255, 120)
-- на центр персонажа
return sparkles, humanoid.Parent:FindFirstChild("HumanoidRootPart")
-- конец функции
end)
-- отдельный поток
task.spawn(function()
-- пока жив и время не вышло
while humanoid.Health > 0 and os.clock() < humanoid:GetAttribute("RegenUntil") do
-- раз в секунду
task.wait(1)
-- прибавляем здоровье
humanoid.Health = math.min(humanoid.MaxHealth, humanoid.Health + humanoid:GetAttribute("RegenRate"))
-- конец цикла
end
-- конец потока
end)
-- конец функции
end
-- отдаём модуль
return EffectsЗапусти Play (или Run) и убедись: