2019-01-04 22:02:55 +02:00
|
|
|
local Task = require 'utils.task'
|
2018-12-02 17:52:55 +02:00
|
|
|
local Global = require 'utils.global'
|
2018-11-29 20:11:12 +02:00
|
|
|
local Token = require 'utils.token'
|
2018-12-02 17:52:55 +02:00
|
|
|
local Command = require 'utils.command'
|
|
|
|
local Event = require 'utils.event'
|
2019-02-14 18:52:23 +02:00
|
|
|
local Ranks = require 'resources.ranks'
|
2018-11-23 23:04:55 +02:00
|
|
|
local random = math.random
|
2018-12-02 17:52:55 +02:00
|
|
|
local ceil = math.ceil
|
|
|
|
local floor = math.floor
|
|
|
|
local format = string.format
|
2018-11-23 23:04:55 +02:00
|
|
|
|
|
|
|
local CreateParticles = {}
|
|
|
|
|
2018-12-02 17:52:55 +02:00
|
|
|
local settings = {
|
2018-12-06 19:17:51 +02:00
|
|
|
faction = 1.0,
|
2018-12-02 17:52:55 +02:00
|
|
|
particles_spawned_buffer = 0,
|
2018-12-06 19:17:51 +02:00
|
|
|
max_particles_per_second = 4000,
|
2018-12-02 17:52:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Global.register({
|
|
|
|
settings = settings,
|
|
|
|
}, function (tbl)
|
|
|
|
settings = tbl.settings
|
|
|
|
end)
|
|
|
|
|
|
|
|
---sets the scale of particles. 1.0 means 100%, 0.5 would mean spawn only 50% of the particles.
|
2018-12-06 19:17:51 +02:00
|
|
|
---@param fraction number
|
|
|
|
function CreateParticles.set_fraction(fraction)
|
|
|
|
if fraction < 0 or fraction > 1 then
|
|
|
|
error(format('Fraction must range from 0 to 1'))
|
2018-12-02 17:52:55 +02:00
|
|
|
end
|
|
|
|
|
2018-12-06 19:17:51 +02:00
|
|
|
settings.faction = fraction
|
2018-12-02 17:52:55 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
---Returns the current scale
|
2018-12-06 19:17:51 +02:00
|
|
|
function CreateParticles.get_fraction()
|
|
|
|
return settings.faction
|
2018-12-02 17:52:55 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
local function get_particle_cap()
|
2018-12-06 19:17:51 +02:00
|
|
|
return settings.max_particles_per_second * (settings.faction + 0.1)
|
2018-12-02 17:52:55 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
---Returns whether or not more particles may be spawned, scale minimum is 0.1
|
|
|
|
local function may_spawn_particles()
|
|
|
|
return settings.particles_spawned_buffer < get_particle_cap()
|
|
|
|
end
|
|
|
|
|
2018-12-06 19:17:51 +02:00
|
|
|
--- resets the amount of particles in the past second so new ones may spawn
|
|
|
|
Event.on_nth_tick(63, function ()
|
2018-12-02 17:52:55 +02:00
|
|
|
settings.particles_spawned_buffer = 0
|
|
|
|
end)
|
|
|
|
|
2018-12-06 19:17:51 +02:00
|
|
|
Command.add('particle-scale', {
|
2019-03-04 00:13:56 +02:00
|
|
|
description = {'command_description.particle_scale'},
|
2018-12-06 19:17:51 +02:00
|
|
|
arguments = {'fraction'},
|
|
|
|
default_values = {fraction = false},
|
2019-01-30 05:52:43 +02:00
|
|
|
required_rank = Ranks.admin,
|
2018-12-02 17:52:55 +02:00
|
|
|
allowed_by_server = true,
|
|
|
|
}, function (arguments, player)
|
2018-12-06 19:17:51 +02:00
|
|
|
local p = player and player.print or print
|
2018-12-02 17:52:55 +02:00
|
|
|
|
2018-12-06 19:17:51 +02:00
|
|
|
local fraction = arguments.fraction
|
2018-12-02 17:52:55 +02:00
|
|
|
|
2018-12-06 19:17:51 +02:00
|
|
|
if fraction ~= false then
|
|
|
|
local scale = tonumber(fraction)
|
|
|
|
if scale == nil or scale < 0 or scale > 1 then
|
|
|
|
p('Scale must be a valid number ranging from 0 to 1')
|
|
|
|
return
|
|
|
|
end
|
|
|
|
CreateParticles.set_fraction(scale)
|
|
|
|
end
|
|
|
|
|
|
|
|
p(format('Particle fraction: %.2f', CreateParticles.get_fraction()))
|
|
|
|
p(format('Particles per second: %d', get_particle_cap()))
|
2018-12-02 17:52:55 +02:00
|
|
|
end)
|
|
|
|
|
|
|
|
---Scales the count to round the fraction up. Always returns at least 1 unless the particle limit is reached.
|
|
|
|
---Useful for particle spawning that influences gameplay for visual indications.
|
|
|
|
---@param count number
|
|
|
|
local function scale_ceil(count)
|
|
|
|
if not may_spawn_particles() then
|
|
|
|
return 0
|
|
|
|
end
|
|
|
|
|
2018-12-06 19:17:51 +02:00
|
|
|
local scale = settings.faction
|
2018-12-02 17:52:55 +02:00
|
|
|
if scale == 0 then
|
|
|
|
return 1
|
|
|
|
end
|
|
|
|
if scale < 1 and count > 1 then
|
|
|
|
count = ceil(count * scale)
|
|
|
|
end
|
|
|
|
|
|
|
|
return count
|
|
|
|
end
|
|
|
|
|
|
|
|
---Scales the count to round the fraction down.
|
|
|
|
---Useful for particle spawning that doesn't influence gameplay.
|
|
|
|
---@param count number
|
|
|
|
local function scale_floor(count)
|
2018-12-06 19:17:51 +02:00
|
|
|
local scale = settings.faction
|
2018-12-02 17:52:55 +02:00
|
|
|
if scale == 0 then
|
|
|
|
return 0
|
|
|
|
end
|
|
|
|
if not may_spawn_particles() then
|
|
|
|
return 0
|
|
|
|
end
|
|
|
|
if scale < 1 then
|
|
|
|
count = floor(count * scale)
|
|
|
|
end
|
|
|
|
|
|
|
|
return count
|
|
|
|
end
|
|
|
|
|
2018-11-29 20:11:12 +02:00
|
|
|
local on_play_particle = Token.register(function (params)
|
|
|
|
params.surface.create_entity(params.prototype)
|
|
|
|
end)
|
|
|
|
|
|
|
|
local function play_particle_sequence(surface, sequences)
|
|
|
|
local create_entity = surface.create_entity
|
|
|
|
for i = 1, #sequences do
|
|
|
|
local sequence = sequences[i]
|
|
|
|
local frame = sequence.frame
|
|
|
|
if frame == 1 then
|
|
|
|
create_entity(sequence.prototype)
|
|
|
|
else
|
|
|
|
Task.set_timeout_in_ticks(frame, on_play_particle, {surface = surface, prototype = sequence.prototype})
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2018-11-23 23:04:55 +02:00
|
|
|
---@param create_entity function a reference to a surface.create_entity
|
|
|
|
---@param particle_count number particle count to spawn
|
|
|
|
---@param position Position
|
|
|
|
function CreateParticles.destroy_rock(create_entity, particle_count, position)
|
2018-12-02 17:52:55 +02:00
|
|
|
for _ = scale_floor(particle_count), 1, -1 do
|
|
|
|
settings.particles_spawned_buffer = settings.particles_spawned_buffer + 1
|
2018-11-23 23:04:55 +02:00
|
|
|
create_entity({
|
|
|
|
position = position,
|
|
|
|
name = 'stone-particle',
|
|
|
|
movement = {random(-5, 5) * 0.01, random(-5, 5) * 0.01},
|
|
|
|
frame_speed = 1,
|
|
|
|
vertical_speed = random(12, 14) * 0.01,
|
|
|
|
height = random(9, 11) * 0.1,
|
|
|
|
})
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2018-12-01 18:32:54 +02:00
|
|
|
---@param create_entity function a reference to a surface.create_entity
|
|
|
|
---@param particle_count number particle count to spawn
|
|
|
|
---@param position Position
|
|
|
|
function CreateParticles.blood_explosion(create_entity, particle_count, position)
|
|
|
|
for _ = particle_count, 1, -1 do
|
|
|
|
create_entity({
|
|
|
|
position = position,
|
|
|
|
name = 'blood-particle',
|
|
|
|
movement = {random(-5, 5) * 0.01, random(-5, 5) * 0.01},
|
|
|
|
frame_speed = 1,
|
|
|
|
vertical_speed = random(10, 12) * 0.01,
|
|
|
|
height = random(5, 15) * 0.1,
|
|
|
|
})
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2018-11-23 23:04:55 +02:00
|
|
|
---@param create_entity function a reference to a surface.create_entity
|
|
|
|
---@param particle_count number particle count to spawn
|
|
|
|
---@param position Position
|
|
|
|
function CreateParticles.mine_rock(create_entity, particle_count, position)
|
2018-12-02 17:52:55 +02:00
|
|
|
for _ = scale_floor(particle_count), 1, -1 do
|
|
|
|
settings.particles_spawned_buffer = settings.particles_spawned_buffer + 1
|
2018-11-23 23:04:55 +02:00
|
|
|
create_entity({
|
|
|
|
position = position,
|
|
|
|
name = 'stone-particle',
|
|
|
|
movement = {random(-5, 5) * 0.01, random(-5, 5) * 0.01},
|
|
|
|
frame_speed = 1,
|
|
|
|
vertical_speed = random(8, 10) * 0.01,
|
|
|
|
height = random(5, 8) * 0.1,
|
|
|
|
})
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2018-11-29 20:11:12 +02:00
|
|
|
|
|
|
|
---Creates a prototype for LuaSurface.create_entity
|
|
|
|
---@param particle string name of the particle
|
|
|
|
---@param x number
|
|
|
|
---@param y number
|
|
|
|
local function create_ceiling_prototype(particle, x, y)
|
|
|
|
return {
|
|
|
|
name = particle,
|
|
|
|
position = {x = x + random(0, 1), y = y + random(0, 1)},
|
|
|
|
movement = {random(-5, 5) * 0.002, random(-5, 5) * 0.002},
|
|
|
|
frame_speed = 1,
|
|
|
|
vertical_speed = 0,
|
|
|
|
height = 3
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
|
|
|
---Creates a crumbling effect from the ceiling
|
|
|
|
---@param surface LuaSurface
|
|
|
|
---@param position table
|
|
|
|
function CreateParticles.ceiling_crumble(surface, position)
|
|
|
|
local sequences = {}
|
|
|
|
local x = position.x
|
|
|
|
local y = position.y
|
2018-12-02 17:52:55 +02:00
|
|
|
local smoke_scale = scale_ceil(2)
|
|
|
|
local stone_scale = scale_floor(4)
|
2018-11-29 20:11:12 +02:00
|
|
|
|
2018-12-02 17:52:55 +02:00
|
|
|
-- pre-calculate how many particles will be spawned. Prevents spawning too many particles over ticks.
|
|
|
|
local particles = settings.particles_spawned_buffer
|
|
|
|
|
|
|
|
for i = 1, smoke_scale do
|
|
|
|
particles = particles + 1
|
2018-11-29 20:11:12 +02:00
|
|
|
sequences[i] = {frame = i*random(1,15), prototype = create_ceiling_prototype('explosion-remnants-particle', x, y)}
|
|
|
|
end
|
2018-12-02 17:52:55 +02:00
|
|
|
for i = smoke_scale + 1, smoke_scale + stone_scale do
|
|
|
|
particles = particles + 1
|
2018-11-29 20:11:12 +02:00
|
|
|
sequences[i] = {frame = i*random(1,15), prototype = create_ceiling_prototype('stone-particle', x, y)}
|
|
|
|
end
|
|
|
|
|
2018-12-02 17:52:55 +02:00
|
|
|
settings.particles_spawned_buffer = particles
|
|
|
|
|
2018-11-29 20:11:12 +02:00
|
|
|
play_particle_sequence(surface, sequences)
|
|
|
|
end
|
|
|
|
|
2018-11-23 23:04:55 +02:00
|
|
|
return CreateParticles
|