2018-11-18 18:05:45 +02:00
|
|
|
-- dependencies
|
|
|
|
local Global = require 'utils.global'
|
|
|
|
local Event = require 'utils.event'
|
|
|
|
local raise_event = script.raise_event
|
2018-11-24 11:45:43 +02:00
|
|
|
local ceil = math.ceil
|
2018-11-18 18:05:45 +02:00
|
|
|
local max = math.max
|
2018-11-25 21:24:37 +02:00
|
|
|
local floor = math.floor
|
|
|
|
local format = string.format
|
2018-11-18 18:05:45 +02:00
|
|
|
|
|
|
|
-- this, things that can be done run-time
|
|
|
|
local ForceControl = {}
|
|
|
|
ForceControl.events = {
|
|
|
|
--- triggered when the force levels up
|
|
|
|
--- uses event = {level_reached = number, force = LuaForce}
|
2018-11-20 12:46:19 +02:00
|
|
|
on_level_up = script.generate_event_name()
|
2018-11-18 18:05:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
-- the builder, can only be accessed through ForceControl.register() and should be avoided used run-time
|
|
|
|
local ForceControlBuilder = {}
|
|
|
|
|
|
|
|
-- all force data being monitored
|
|
|
|
local forces = {}
|
|
|
|
|
2018-11-24 11:45:43 +02:00
|
|
|
-- the function that calculates the experience to next level
|
|
|
|
local calculate_next_level_cap = nil
|
2018-11-18 18:05:45 +02:00
|
|
|
|
2018-11-20 12:46:19 +02:00
|
|
|
Global.register(
|
|
|
|
{
|
|
|
|
forces = forces,
|
|
|
|
},
|
|
|
|
function(tbl)
|
|
|
|
forces = tbl.forces
|
|
|
|
end
|
|
|
|
)
|
2018-11-18 18:05:45 +02:00
|
|
|
|
|
|
|
---Asserts if a given variable is of the expected type using type().
|
|
|
|
---
|
|
|
|
---@param expected_type string
|
|
|
|
---@param given any
|
|
|
|
---@param variable_reference_message string displayed when the expectation is not met
|
|
|
|
local function assert_type(expected_type, given, variable_reference_message)
|
|
|
|
local given_type = type(given)
|
|
|
|
if given_type ~= expected_type then
|
2018-11-20 12:46:19 +02:00
|
|
|
error('Argument ' .. variable_reference_message .. " must be of type '" .. expected_type .. "', given '" .. given_type .. "'")
|
2018-11-18 18:05:45 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
---Returns a valid force based on the lua force or name given.
|
|
|
|
---@param lua_force_or_name LuaForce|string
|
|
|
|
local function get_valid_force(lua_force_or_name)
|
|
|
|
if not lua_force_or_name then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
if type(lua_force_or_name) == 'string' then
|
|
|
|
local force = game.forces[lua_force_or_name]
|
|
|
|
if not force or not force.valid then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
return force
|
|
|
|
end
|
|
|
|
|
|
|
|
if type(lua_force_or_name) ~= 'table' or not lua_force_or_name.valid or nil == lua_force_or_name.evolution_factor then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
return lua_force_or_name
|
|
|
|
end
|
|
|
|
|
|
|
|
---Register a reward that checks if a reward should be given if the level
|
|
|
|
---matches the callback. If so, it will apply the if_level_criteria_matches
|
|
|
|
---callback.
|
|
|
|
---
|
|
|
|
---@param level_matches function function(number level_reached)
|
|
|
|
---@param callback function function(number level_reached, LuaForce force)
|
|
|
|
---@param lua_force_name string|nil only register for this force (optional)
|
|
|
|
function ForceControlBuilder.register(level_matches, callback, lua_force_name)
|
|
|
|
if game then
|
2018-11-20 12:46:19 +02:00
|
|
|
error('You can only register level up callbacks before the game is initialized')
|
2018-11-18 18:05:45 +02:00
|
|
|
end
|
|
|
|
assert_type('function', level_matches, 'level_matches of function ForceControl.register_reward')
|
|
|
|
assert_type('function', callback, 'callback of function ForceControlBuilder.register')
|
|
|
|
|
|
|
|
local function on_level_up(event)
|
|
|
|
local level = event.level_reached
|
|
|
|
if level_matches(level, event.force) then
|
|
|
|
callback(level, event.force)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
if not lua_force_name then
|
|
|
|
Event.add(ForceControl.events.on_level_up, on_level_up)
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
2018-11-20 12:46:19 +02:00
|
|
|
Event.add(
|
|
|
|
ForceControl.events.on_level_up,
|
|
|
|
function(event)
|
|
|
|
local force = get_valid_force(lua_force_name)
|
|
|
|
if not force then
|
|
|
|
error('Can only register a lua force name for ForceControlBuilder.register')
|
|
|
|
end
|
|
|
|
if force ~= event.force then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
on_level_up(event)
|
2018-11-18 18:05:45 +02:00
|
|
|
end
|
2018-11-20 12:46:19 +02:00
|
|
|
)
|
2018-11-18 18:05:45 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
---Register a reward which triggers when the given level is reached.
|
|
|
|
---
|
|
|
|
---@param level number
|
|
|
|
---@param callback function function(number level_reached, LuaForce force)
|
|
|
|
---@param lua_force_name string|nil only register for this force (optional)
|
|
|
|
function ForceControlBuilder.register_on_single_level(level, callback, lua_force_name)
|
|
|
|
assert_type('number', level, 'level of function ForceControl.register_reward_on_single_level')
|
|
|
|
assert_type('function', callback, 'callback of function ForceControlBuilder.register_on_single_level')
|
|
|
|
|
2018-11-20 12:46:19 +02:00
|
|
|
ForceControlBuilder.register(
|
|
|
|
function(level_reached)
|
|
|
|
return level == level_reached
|
|
|
|
end,
|
|
|
|
callback,
|
|
|
|
lua_force_name
|
|
|
|
)
|
2018-11-18 18:05:45 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
---Always returns true
|
|
|
|
local function always_true()
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
|
|
|
|
---Register a reward that triggers for every level.
|
|
|
|
---
|
|
|
|
---@param callback function function(number level_reached, LuaForce force)
|
|
|
|
---@param lua_force_name string|nil only register for this force (optional)
|
|
|
|
function ForceControlBuilder.register_on_every_level(callback, lua_force_name)
|
|
|
|
assert_type('function', callback, 'callback of function ForceControlBuilder.register_on_every_level')
|
|
|
|
|
|
|
|
ForceControlBuilder.register(always_true, callback, lua_force_name)
|
|
|
|
end
|
|
|
|
|
|
|
|
---Register the config and initialize the feature.
|
|
|
|
---@param level_up_formula function
|
|
|
|
function ForceControl.register(level_up_formula)
|
2018-11-24 11:45:43 +02:00
|
|
|
if calculate_next_level_cap then
|
2018-11-18 18:05:45 +02:00
|
|
|
error('Can only register one force control.')
|
|
|
|
end
|
|
|
|
|
2018-11-24 11:45:43 +02:00
|
|
|
calculate_next_level_cap = level_up_formula
|
2018-11-18 18:05:45 +02:00
|
|
|
|
|
|
|
return ForceControlBuilder
|
|
|
|
end
|
|
|
|
|
|
|
|
---Registers a new force to participate.
|
|
|
|
---@param lua_force_or_name LuaForce|string
|
|
|
|
function ForceControl.register_force(lua_force_or_name)
|
2018-11-24 11:45:43 +02:00
|
|
|
if not calculate_next_level_cap then
|
2018-11-18 18:05:45 +02:00
|
|
|
error('Can only register a force when the config has been initialized via ForceControl.register(config_table).')
|
|
|
|
end
|
|
|
|
local force = get_valid_force(lua_force_or_name)
|
|
|
|
if not force then
|
|
|
|
error('Can only register a LuaForce for ForceControl')
|
|
|
|
end
|
|
|
|
|
|
|
|
forces[force.name] = {
|
|
|
|
current_experience = 0,
|
2018-11-24 11:45:43 +02:00
|
|
|
total_experience = 0,
|
2018-11-18 18:05:45 +02:00
|
|
|
current_level = 0,
|
2018-11-24 11:45:43 +02:00
|
|
|
experience_level_up_cap = calculate_next_level_cap(0)
|
2018-11-18 18:05:45 +02:00
|
|
|
}
|
|
|
|
end
|
|
|
|
|
|
|
|
---Returns the ForceControlBuilder.
|
|
|
|
function ForceControl.get_force_control_builder()
|
2018-11-24 11:45:43 +02:00
|
|
|
if not calculate_next_level_cap then
|
2018-11-18 18:05:45 +02:00
|
|
|
error('Can only get the force control builder when the config has been initialized via ForceControl.register(config_table).')
|
|
|
|
end
|
|
|
|
|
|
|
|
return ForceControlBuilder
|
|
|
|
end
|
|
|
|
|
|
|
|
---Removes experience from a force. Won't cause de-level nor go below 0.
|
|
|
|
---@param lua_force_or_name LuaForce|string
|
2018-11-24 11:45:43 +02:00
|
|
|
---@param experience number amount of experience to remove
|
|
|
|
---@return number the experience being removed
|
2018-11-18 18:05:45 +02:00
|
|
|
function ForceControl.remove_experience(lua_force_or_name, experience)
|
|
|
|
assert_type('number', experience, 'Argument experience of function ForceControl.remove_experience')
|
|
|
|
|
|
|
|
if experience < 1 then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
local force = get_valid_force(lua_force_or_name)
|
|
|
|
if not force then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
local force_config = forces[force.name]
|
|
|
|
if not force_config then
|
|
|
|
return
|
|
|
|
end
|
2018-11-24 11:45:43 +02:00
|
|
|
local backup_current_experience = force_config.current_experience
|
2018-11-18 18:05:45 +02:00
|
|
|
force_config.current_experience = max(0, force_config.current_experience - experience)
|
2018-11-24 11:45:43 +02:00
|
|
|
force_config.total_experience = (force_config.current_experience == 0) and force_config.total_experience - backup_current_experience or max(0, force_config.total_experience - experience)
|
|
|
|
return backup_current_experience - force_config.current_experience
|
|
|
|
end
|
|
|
|
|
|
|
|
---Removes experience from a force, based on a percentage of the total obtained experience
|
|
|
|
---@param lua_force_or_name LuaForce|string
|
|
|
|
---@param percentage number percentage of total obtained experience to remove
|
|
|
|
---@param min_experience number minimum amount of experience to remove (optional)
|
|
|
|
---@return number the experience being removed
|
|
|
|
---@see ForceControl.remove_experience
|
|
|
|
function ForceControl.remove_experience_percentage(lua_force_or_name, percentage, min_experience)
|
2018-11-25 13:53:05 +02:00
|
|
|
min_experience = min_experience ~= nil and min_experience or 0
|
2018-11-24 11:45:43 +02:00
|
|
|
local force = get_valid_force(lua_force_or_name)
|
|
|
|
if not force then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
local force_config = forces[force.name]
|
|
|
|
if not force_config then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
local penalty = force_config.total_experience * percentage
|
|
|
|
penalty = (penalty >= min_experience) and ceil(penalty) or ceil(min_experience)
|
|
|
|
return ForceControl.remove_experience(lua_force_or_name, penalty)
|
2018-11-18 18:05:45 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
---Adds experience to a force.
|
|
|
|
---@param lua_force_or_name LuaForce|string
|
|
|
|
---@param experience number amount of experience to add
|
2018-11-24 11:45:43 +02:00
|
|
|
---@param resursive_call boolean whether or not the function is called recursively (optional)
|
|
|
|
function ForceControl.add_experience(lua_force_or_name, experience, recursive_call)
|
2018-11-18 18:05:45 +02:00
|
|
|
assert_type('number', experience, 'Argument experience of function ForceControl.add_experience')
|
|
|
|
|
|
|
|
if experience < 1 then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
local force = get_valid_force(lua_force_or_name)
|
|
|
|
if not force then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
local force_config = forces[force.name]
|
|
|
|
if not force_config then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
local new_experience = force_config.current_experience + experience
|
|
|
|
local experience_level_up_cap = force_config.experience_level_up_cap
|
2018-11-24 11:45:43 +02:00
|
|
|
if not recursive_call then
|
|
|
|
force_config.total_experience = force_config.total_experience + experience
|
|
|
|
end
|
2018-11-18 18:05:45 +02:00
|
|
|
|
|
|
|
if (new_experience < experience_level_up_cap) then
|
|
|
|
force_config.current_experience = new_experience
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
-- level up
|
|
|
|
local new_level = force_config.current_level + 1
|
|
|
|
force_config.current_level = new_level
|
|
|
|
force_config.current_experience = 0
|
2018-11-24 11:45:43 +02:00
|
|
|
force_config.experience_level_up_cap = calculate_next_level_cap(new_level)
|
2018-11-18 18:05:45 +02:00
|
|
|
raise_event(ForceControl.events.on_level_up, {level_reached = new_level, force = force})
|
|
|
|
|
2018-11-24 11:45:43 +02:00
|
|
|
ForceControl.add_experience(force, new_experience - experience_level_up_cap, true)
|
2018-11-18 18:05:45 +02:00
|
|
|
end
|
|
|
|
|
2018-11-25 03:27:41 +02:00
|
|
|
---Adds experience from a force, based on a percentage of the total obtained experience
|
|
|
|
---@param lua_force_or_name LuaForce|string
|
|
|
|
---@param percentage number percentage of total obtained experience to add
|
|
|
|
---@param min_experience number minimum amount of experience to add (optional)
|
|
|
|
---@return number the experience being added
|
|
|
|
---@see ForceControl.add_experience
|
|
|
|
function ForceControl.add_experience_percentage(lua_force_or_name, percentage, min_experience)
|
2018-11-25 13:53:05 +02:00
|
|
|
min_experience = min_experience ~= nil and min_experience or 0
|
2018-11-25 03:27:41 +02:00
|
|
|
local force = get_valid_force(lua_force_or_name)
|
|
|
|
if not force then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
local force_config = forces[force.name]
|
|
|
|
if not force_config then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
local reward = force_config.total_experience * percentage
|
|
|
|
reward = (reward >= min_experience) and ceil(reward) or ceil(min_experience)
|
|
|
|
ForceControl.add_experience(lua_force_or_name, reward)
|
|
|
|
return reward
|
|
|
|
end
|
|
|
|
|
2018-11-18 18:05:45 +02:00
|
|
|
---Return the force data as {
|
|
|
|
--- current_experience = number,
|
|
|
|
--- current_level = number,
|
|
|
|
--- experience_level_up_cap = number,
|
|
|
|
--- experience_percentage = number,
|
|
|
|
---}
|
|
|
|
---@param lua_force_or_name LuaForce|string
|
|
|
|
function ForceControl.get_force_data(lua_force_or_name)
|
|
|
|
local force = get_valid_force(lua_force_or_name)
|
|
|
|
if not force then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
local force_config = forces[force.name]
|
|
|
|
if not force_config then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
return {
|
|
|
|
current_experience = force_config.current_experience,
|
2018-11-24 11:45:43 +02:00
|
|
|
total_experience = force_config.total_experience,
|
2018-11-18 18:05:45 +02:00
|
|
|
current_level = force_config.current_level,
|
|
|
|
experience_level_up_cap = force_config.experience_level_up_cap,
|
2018-11-20 12:46:19 +02:00
|
|
|
experience_percentage = (force_config.current_experience / force_config.experience_level_up_cap) * 100
|
2018-11-18 18:05:45 +02:00
|
|
|
}
|
|
|
|
end
|
|
|
|
|
2018-11-24 11:45:43 +02:00
|
|
|
function ForceControl.get_formatted_force_data(lua_force_or_name)
|
|
|
|
local force_config = ForceControl.get_force_data(lua_force_or_name)
|
|
|
|
if not force_config then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
2018-11-25 21:24:37 +02:00
|
|
|
return format(
|
|
|
|
'Current experience: %d Total experience: %d Current level: %d Next level at: %d Percentage to level up: %d%%',
|
|
|
|
force_config.current_experience,
|
|
|
|
force_config.total_experience,
|
|
|
|
force_config.current_level,
|
|
|
|
force_config.experience_level_up_cap,
|
|
|
|
floor(force_config.experience_percentage * 100) * 0.01
|
|
|
|
)
|
2018-11-24 11:45:43 +02:00
|
|
|
end
|
|
|
|
|
2018-11-18 18:05:45 +02:00
|
|
|
return ForceControl
|