Make bomb "damage" player

I.e. add visual effect and temporary slowdown
This commit is contained in:
Wuzzy 2024-09-30 23:19:14 +02:00
parent 37e4181ab5
commit 51bcb5e9f0
10 changed files with 271 additions and 5 deletions

View File

@ -30,6 +30,8 @@
local S = minetest.get_translator("lzr_fallout")
lzr_fallout = {}
-- If the player is in the ship, fallout occurs when below this Y
local SHIP_FALLOUT_Y = lzr_globals.MENU_SHIP_POS.y + lzr_globals.MENU_SHIP_FALLOUT_Y_OFFSET
@ -114,8 +116,9 @@ local reset_player = function(player, reset_type)
reset_player_damage(player)
end
local damage_player = function(player, reset_type)
player_damage = player_damage + 1
local damage_player = function(player, reset_type, damage)
safe_timer = 0
player_damage = player_damage + (damage or 1)
local gain
if player_damage >= 3 then
gain = 1
@ -124,7 +127,7 @@ local damage_player = function(player, reset_type)
else
gain = 0.4
end
if player_damage > PLAYER_MAX_DAMAGE then
if reset_type ~= "no_reset" and player_damage > PLAYER_MAX_DAMAGE then
if reset_type == "skull_crush" or reset_type == "crush" then
-- The skulls laugh at you when you got stuck ;-)
minetest.sound_play({name="lzr_fallout_skull_laugh", gain=0.9}, {to_player=player:get_player_name()}, true)
@ -133,6 +136,9 @@ local damage_player = function(player, reset_type)
end
reset_player(player, reset_type)
else
if player_damage > PLAYER_MAX_DAMAGE then
player_damage = PLAYER_MAX_DAMAGE
end
local texture = "lzr_fallout_damage_screen_"..player_damage..".png"
update_damage_screen(player)
minetest.sound_play({name="lzr_fallout_damage", gain=gain}, {to_player=player:get_player_name()}, true)
@ -143,6 +149,10 @@ local undamage_player = function(player)
update_damage_screen(player)
end
lzr_fallout.add_player_damage = function(player, reset_type, damage)
damage_player(player, reset_type, damage)
end
local step_timer = 0
minetest.register_globalstep(function(dtime)
local ddtime = dtime + step_timer
@ -232,7 +242,7 @@ minetest.register_globalstep(function(dtime)
damage_player(player, reset_type)
elseif out_of_bounds_timer == 0 and crush_timer == 0 then
safe_timer = safe_timer + ddtime
if safe_timer > 1 then
if safe_timer > 3 then
-- Reduce damage when safe
undamage_player(player)
safe_timer = 0

View File

@ -21,6 +21,15 @@ local BARRICADE_BURN_TIME = 1.0
local BOMB_BURN_TIME = 2.0
local BOMB_BURN_TIME_QUICK = 0.2
-- How far away bombs deal "damage" to players
-- (damage is only an animation with no gameplay
-- effect)
local BOMB_DAMAGE_RADIUS = 3
-- How many a player is slowed down
-- when hit by a bomb
local BOMB_SLOWDOWN_TIME = 6.0
local bomb_fuse_sounds = {}
local bomb_fuse_particlespawners = {}
@ -1552,6 +1561,16 @@ local def_bomb_takable_on = {
timer:start(BOMB_BURN_TIME_QUICK)
end
end
-- "damage" players (visual effect + temporary slowdown)
local objs = minetest.get_objects_inside_radius(pos, BOMB_DAMAGE_RADIUS)
for o=1, #objs do
if objs[o]:is_player() then
lzr_fallout.add_player_damage(objs[o], "no_reset", 4)
lzr_slowdown.slowdown(objs[o], BOMB_SLOWDOWN_TIME)
end
end
lzr_laser.full_laser_update_if_needed()
end,
drop = "",

View File

@ -1,2 +1,2 @@
name = lzr_laser
depends = lzr_globals, lzr_gamestate, lzr_sounds, lzr_hook, lzr_util, lzr_triggers
depends = lzr_globals, lzr_gamestate, lzr_sounds, lzr_hook, lzr_util, lzr_triggers, lzr_slowdown

View File

@ -0,0 +1,26 @@
-- Minimal mod to temporarily slow down player
local SLOWDOWN_SPEED_FACTOR = 0.5
local SLOWDOWN_JUMP_FACTOR = 0.5
local slowdown_jobs = {}
lzr_slowdown = {}
-- Slow down player for a few seconds
lzr_slowdown.slowdown = function(player, time)
local name = player:get_player_name()
if slowdown_jobs[name] then
slowdown_jobs[name]:cancel()
end
playerphysics.add_physics_factor(player, "speed", "lzr_slowdown:slowdown", SLOWDOWN_SPEED_FACTOR)
playerphysics.add_physics_factor(player, "jump", "lzr_slowdown:slowdown", SLOWDOWN_JUMP_FACTOR)
slowdown_jobs[name] = minetest.after(time, function(player)
if not player or not player:is_player() then
return
end
playerphysics.remove_physics_factor(player, "speed", "lzr_slowdown:slowdown")
playerphysics.remove_physics_factor(player, "jump", "lzr_slowdown:slowdown")
end, player)
end

View File

@ -0,0 +1 @@
name = lzr_slowdown

110
mods/playerphysics/API.md Normal file
View File

@ -0,0 +1,110 @@
# Player Physics API Documentation
This document explains how to use the Player Physics API as a developer.
## Quick start
Let's say you have a mod `example` and want to double the speed of the player (i.e. multiply it by a factor of 2), but you also don't want to break other mods that might touch the speed.
Previously, you might have written something like this:
`player:set_physics_override({speed=2})`
However, your mod broke down as soon the mod `example2` came along, which wanted to increase the speed by 50%. In the real game, the player speed randomly switched from 50% and 200% which was a very annoying bug.
In your `example` mod, you can replace the code with this:
`playerphysics.add_physics_factor(player, "speed", "my_double_speed", 2)`
Where `"my_double_speed` is an unique ID for your speed factor.
Now your `example` mod is interoperable! And now, of course, the `example2` mod has to be updated in a similar fashion.
## Precondition
There is only one precondition to using this mod, but it is important:
Mods *MUST NOT* call `set_physics_override` directly for numerical values. Instead, to modify player physics, all mods that touch player physics have to use this API.
## Functions
### `playerphysics.add_physics_factor(player, attribute, id, value)`
Adds a factor for a player physic and updates the player physics immediately.
#### Parameters
* `player`: Player object
* `attribute`: Which of the physical attributes 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-attribute type basis
* `value`: The factor to add to the list of products
If a factor for the same player, attribute and `id` already existed, it will be overwritten.
### `playerphysics.remove_physics_factor(player, attribute, id)`
Removes the physics factor of the given ID and updates the player's physics.
#### Parameters
Same as in `playerphysics.add_physics_factor`, except there is no `value` argument.
### `playerphysics.get_physics_factor(player, attribute, id)`
Returns the current physics factor of the given ID, if it exists.
If the ID exists, returns a number. If it does not exist, returns nil.
Note a missing physics factor is mathematically equivalent to a factor of 1.
#### Parameters
Same as in `playerphysics.add_physics_factor`, except there is no `value` argument.
## Examples
### Speed changes
Let's assume this mod is used by 3 different mods all trying to change the speed:
Potions, Exhaustion and Electrocution.
Here's what it could look like:
Potions mod:
```
playerphysics.add_physics_factor(player, "speed", "run_potion", 2)
```
Exhaustion mod:
```
playerphysics.add_physics_factor(player, "jump", "exhausted", 0.75)
```
Electrocution mod:
```
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:
```
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:
```
playerphysics.add_physics_factor(player, "speed", "sleeping", 0)
playerphysics.add_physics_factor(player, "jump", "sleeping", 0)
```
This works regardless of the other factors because 0 times anything equals 0.

View File

@ -0,0 +1,9 @@
The MIT License (MIT)
Copyright © 2024 Wuzzy
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -0,0 +1,31 @@
# Player Physics API
Version: 1.1.0
This mod makes it possible for multiple mods to modify player physics (speed, jumping strength, gravity) without conflict.
## Introduction
### For players
Mods and games in Minetest can set physical attributes of players, such as speed and jump strength. For example, player speed could be set to 200%. But the way this works makes it difficult for multiple mods to *modify* physical attributes without leading to conflicts, problems and hilarious bugs, like speed that changes often to nonsense values.
The Player Physics API aims to resolve this conflict by providing a “common ground” for mods to work together in this regard.
This mod does nothing on its own, you will only need to install it as dependency of other mods.
When you browse for mods that somehow mess with player physics (namely: speed, jump strength or gravity) and want to use more than one of them, check out if they support the Player Physics API. If they don't, it's very likely these mods will break as soon you activate more than one of them, for example, if two mods try to set the player speed. If you found such a “hilarious bug”, please report it to the developers of the mods (or games) and point them to the Player Physics API.
Of course, not all mods need the Player Physics API. Mods that don't touch player physics at all won't need this mod.
The rest of this document is directed at developers.
### For developers
The function `set_physics_override` from the Minetest Lua API allows mod authors to override physical attributes of players, such as speed or jump strength.
This function works fine as long there is only one mod that sets a particular physical attribute at a time. However, as soon as at least two different mods (that do not know each other) try to change the same player physics attribute using only this function, there will be conflicts as each mod will undo the change of the other mod, as the function sets a raw value. A classic race condition occurs. This is the case because the mods fail to communicate with each other.
This mod solves the problem of conflicts. It bans the concept of “setting the raw value directly” and replaces it with the concept of factors that mods can add and remove for each attribute. The real physical player attribute will be the product of all active factors.
See `API.md` for the API documentation.
## License
This mod is free software, released under the MIT License (see `LICENSE.txt`).

View File

@ -0,0 +1,57 @@
playerphysics = {}
local function calculate_attribute_product(player, attribute)
local a = minetest.deserialize(player:get_meta():get_string("playerphysics:physics"), true)
local product = 1
if a == nil or a[attribute] == nil then
return product
end
local factors = a[attribute]
if type(factors) == "table" then
for _, factor in pairs(factors) do
product = product * factor
end
end
return product
end
function playerphysics.add_physics_factor(player, attribute, id, value)
local meta = player:get_meta()
local a = minetest.deserialize(meta:get_string("playerphysics:physics"), true)
if a == nil then
a = { [attribute] = { [id] = value } }
elseif a[attribute] == nil then
a[attribute] = { [id] = value }
else
a[attribute][id] = value
end
meta:set_string("playerphysics:physics", minetest.serialize(a))
local raw_value = calculate_attribute_product(player, attribute)
player:set_physics_override({[attribute] = raw_value})
end
function playerphysics.remove_physics_factor(player, attribute, id)
local meta = player:get_meta()
local a = minetest.deserialize(meta:get_string("playerphysics:physics"), true)
if a == nil or a[attribute] == nil then
-- Nothing to remove
return
else
a[attribute][id] = nil
end
meta:set_string("playerphysics:physics", minetest.serialize(a))
local raw_value = calculate_attribute_product(player, attribute)
player:set_physics_override({[attribute] = raw_value})
end
function playerphysics.get_physics_factor(player, attribute, id)
local meta = player:get_meta()
local a = minetest.deserialize(meta:get_string("playerphysics:physics"), true)
if a == nil then
return nil
elseif a[attribute] == nil then
return nil
else
return a[attribute][id]
end
end

View File

@ -0,0 +1,3 @@
name = playerphysics
title = Player Physics API
description = This mod makes it possible for multiple mods to modify player physics (speed, jumping strength, gravity) without conflict.