diff --git a/mods/PLAYER/mcl_playerphysics/README.md b/mods/PLAYER/mcl_playerphysics/README.md new file mode 100644 index 0000000000..909c6fbac9 --- /dev/null +++ b/mods/PLAYER/mcl_playerphysics/README.md @@ -0,0 +1,80 @@ +# Player Physics API. + +This mod simplifies the setting of player physics (speed, jumping height, gravity). + +The problem with `set_physics_override` is that is sets a raw value. +As soon as two independent mods want to mess with player physics, this is a problem. + +This has a different approach in that you add and remove an arbitrary number of factors for each attribute. +The actual player attribute will be the product of all factors which have been added. + +## Preconditions +There is only one precondition to using this mod, but it is important: +Mods *MUST NOT* call `set_physics_override` directly! Instead, to modify player physics, use this API. + +## Functions +### `mcl_playerphysics.add_physics_factor(player, physic, id, value)` +Adds a factor for a player physic and updates the player physics immeiately. + +#### Parameters +* `player`: Player object +* `physic`: Type of player physic to change. Any of the numeric values of `set_physics_override` (e.g. `speed`, `jump`, `gravity`) +* `id`: Unique identifier for this factor. Identifiers are stored on a per-player per-physics type basis +* `value`: The factor to add to the list of products + +### `mcl_playerphysics.remove_physics_factor(player, physic, id)` +Removes the physics factor of the given ID and updates the player's physics. + +#### Parameters +* `player`: Player object +* `physic`: Type of player physic to change. Any of the numeric values of `set_physics_override` (e.g. `speed`, `jump`, `gravity`) +* `id`: Unique identifier for the factor to remove + +## Examples +### Speed changes +Let's assume this mod is used by multiple different mods all trying to change the speed. +Here's what it could look like: + +Potions mod: +``` +mcl_playerphysics.add_physics_factor(player, "speed", "run_potion", 2) +``` + +Exhaustion mod: +``` +mcl_playerphysics.add_physics_factor(player, "jump", "exhausted", 0.75) +``` + +Electrocution mod: +``` +mcl_playerphysics.add_physics_factor(player, "jump", "shocked", 0.9) +``` + +When the 3 mods have done their change, the real player speed is simply the product of all factors, that is: + +2 * 0.75 * 0.9 = 1.35 + +The final player speed is thus 135%. + +### Speed changes, part 2 + +Let's take the example above. +Now if the Electrocution mod is done with shocking the player, it just needs to call: + +``` +mcl_playerphysics.remove_physics_factor(player, "jump", "shocked") +``` + +The effect is now gone, so the new player speed will be: + +2 * 0.75 = 1.5 + +### Sleeping +To simulate sleeping by preventing all player movement, this can be done with this easy trick: + +``` +mcl_playerphysics.add_physics_factor(player, "speed", "sleeping", 0) +mcl_playerphysics.add_physics_factor(player, "jump", "sleeping", 0) +``` + +This works regardless of the other factors because mathematics tell us that the factor 0 forces the product to be 0. diff --git a/mods/PLAYER/mcl_playerphysics/init.lua b/mods/PLAYER/mcl_playerphysics/init.lua new file mode 100644 index 0000000000..b7b7d4512e --- /dev/null +++ b/mods/PLAYER/mcl_playerphysics/init.lua @@ -0,0 +1,43 @@ +mcl_playerphysics = {} + +local function calculate_physic_product(player, physic) + local a = minetest.deserialize(player:get_attribute("mcl_playerphysics:physics")) + local product = 1 + if a == nil or a[physic] == nil then + return product + end + local factors = a[physic] + if type(factors) == "table" then + for id, factor in pairs(factors) do + product = product * factor + end + end + return product +end + +function mcl_playerphysics.add_physics_factor(player, physic, id, value) + local a = minetest.deserialize(player:get_attribute("mcl_playerphysics:physics")) + if a == nil then + a = { [physic] = { [id] = value } } + elseif a[physic] == nil then + a[physic] = { [id] = value } + else + a[physic][id] = value + end + player:set_attribute("mcl_playerphysics:physics", minetest.serialize(a)) + local raw_value = calculate_physic_product(player, physic) + player:set_physics_override({[physic] = raw_value}) +end + +function mcl_playerphysics.remove_physics_factor(player, physic, id) + local a = minetest.deserialize(player:get_attribute("mcl_playerphysics:physics")) + if a == nil or a[physic] == nil then + -- Nothing to remove + return + else + a[physic][id] = nil + end + player:set_attribute("mcl_playerphysics:physics", minetest.serialize(a)) + local raw_value = calculate_physic_product(player, physic) + player:set_physics_override({[physic] = raw_value}) +end diff --git a/mods/PLAYER/mcl_playerphysics/mod.conf b/mods/PLAYER/mcl_playerphysics/mod.conf new file mode 100644 index 0000000000..ff2bed375e --- /dev/null +++ b/mods/PLAYER/mcl_playerphysics/mod.conf @@ -0,0 +1 @@ +name=mcl_playerphysics