Split player damage and fallout logic

This commit is contained in:
Wuzzy 2024-10-01 00:47:02 +02:00
parent 51bcb5e9f0
commit 371ce5f979
12 changed files with 134 additions and 117 deletions

View File

@ -67,7 +67,7 @@ All levels by Wuzzy.
- `lzr_menu_speaker_*.png`:
- By MCL <temp1@cubesoftware.xyz>
- License: CC BY 4.0
- `lzr_fallout_damage_screen_*.png`:
- `lzr_damage_screen_*.png`:
- By Wuzzy
- License: CC BY 4.0
- `lzr_laser_bomb_smoke_*.png`:
@ -199,7 +199,7 @@ All levels by Wuzzy.
- `lzr_menu_speaker_turn_off.ogg`:
- by mincedbeats <https://freesound.org/people/mincedbeats/sounds/593996/>
- License: CC0
- `lzr_fallout_damage.ogg`:
- `lzr_damage_damage.ogg`:
- by newagesoup <https://freesound.org/people/newagesoup/sounds/348242/>
- License: CC0
- `lzr_fallout_skull_laugh.ogg`:

105
mods/lzr_damage/init.lua Normal file
View File

@ -0,0 +1,105 @@
lzr_damage = {}
-- Note this game does NOT use regular damage and health, as defined
-- by Minetest, it's disabled. The "damage" here applies only to this mod!
lzr_damage.MAX_DAMAGE = 4
-- Reduce damage when player didn't take damage every HEAL_TIME
-- seconds.
local HEAL_TIME = 3.0
-- Player damage increases roughly every second the player is in danger,
-- and decreases while out of danger
local player_damage = 0
-- Count the time for how many consecutive seconds the player did
-- not take damage yet.
local safe_timer = 0
local damage_screen
local update_damage_screen = function(player)
if player_damage == 0 then
if damage_screen then
player:hud_remove(damage_screen)
damage_screen = nil
end
else
local texture = "lzr_damage_screen_"..player_damage..".png"
if not damage_screen then
damage_screen = player:hud_add({
type = "image",
scale = { x = -100, y = -100 },
text = texture,
alignment = { x = 1, y = 1 },
position = { x = 0, y = 0 },
z_index = 1000,
})
else
player:hud_change(damage_screen, "text", texture)
end
end
end
lzr_damage.reset_player_damage = function(player)
player_damage = 0
update_damage_screen(player)
end
lzr_damage.damage_player = function(player, damage)
safe_timer = 0
player_damage = player_damage + (damage or 1)
if player_damage > lzr_damage.MAX_DAMAGE then
player_damage = lzr_damage.MAX_DAMAGE
end
local gain
if player_damage >= 3 then
gain = 1
elseif player_damage >= 2 then
gain = 0.7
else
gain = 0.4
end
local texture = "lzr_damage_screen_"..player_damage..".png"
update_damage_screen(player)
minetest.sound_play({name="lzr_damage_damage", gain=gain}, {to_player=player:get_player_name()}, true)
end
local undamage_player = function(player)
player_damage = math.max(0, player_damage - 1)
update_damage_screen(player)
end
lzr_damage.get_player_damage = function(player)
return player_damage
end
-- Slowly reduce damage to 0 when player hasnt been
-- damaged for a while.
minetest.register_globalstep(function(dtime)
safe_timer = safe_timer + dtime
if safe_timer < HEAL_TIME then
return
end
safe_timer = 0
local players = minetest.get_connected_players()
local state = lzr_gamestate.get_state()
if state ~= lzr_gamestate.LEVEL and state ~= lzr_gamestate.LEVEL_COMPLETE then
return
end
for p=1, #players do
local player = players[p]
undamage_player(player)
end
end)
-- Reset player damage when entering any state but the level states
lzr_gamestate.register_on_enter_state(function(new_state)
if new_state ~= lzr_gamestate.LEVEL and new_state ~= lzr_gamestate.LEVEL_COMPLETE then
local player = minetest.get_player_by_name("singleplayer")
if player then
lzr_damage.reset_player_damage(player)
end
end
end)

2
mods/lzr_damage/mod.conf Normal file
View File

@ -0,0 +1,2 @@
name = lzr_damage
depends = lzr_gamestate

View File

Before

Width:  |  Height:  |  Size: 8.7 KiB

After

Width:  |  Height:  |  Size: 8.7 KiB

View File

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

View File

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 42 KiB

View File

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 53 KiB

View File

@ -25,8 +25,8 @@
-- by activated cursed ckulls, it's impossible to win, so the
-- level must fail. But there is still a chance the player
-- can fix this by jumping or walking out if not
-- *completely* surrounded, which is why the damage
-- system has been added (see below)
-- *completely* surrounded, which is why this mod uses
-- a damage system via lzr_damage.
local S = minetest.get_translator("lzr_fallout")
@ -41,56 +41,16 @@ local GRACE_PERIOD = 3
-- In a level, players in an invalid position do not immediately
-- fail but first take "damage" as long they are in danger.
-- Only once PLAYER_MAX_DAMAGE was surpassed, the failure is triggered.
-- Note this game does NOT use regular damage and health, as defined
-- by Minetest, it's disabled. The "damage" here applies only to this mod!
local PLAYER_MAX_DAMAGE = 4
-- Player damage increases roughly every second the player is in danger,
-- and decreases while out of danger
local player_damage = 0
-- Count the time for how long the player is being crushed, out of bounds
-- or safe (=not in any danger).
local crush_timer = 0
local out_of_bounds_timer = 0
local safe_timer = 0
-- Counts time for how long we've been in a level.
local level_timer = 0
local level_ready = false
local damage_screen
local update_damage_screen = function(player)
if player_damage == 0 then
if damage_screen then
player:hud_remove(damage_screen)
damage_screen = nil
end
else
local texture = "lzr_fallout_damage_screen_"..player_damage..".png"
if not damage_screen then
damage_screen = player:hud_add({
type = "image",
scale = { x = -100, y = -100 },
text = texture,
alignment = { x = 1, y = 1 },
position = { x = 0, y = 0 },
z_index = 1000,
})
else
player:hud_change(damage_screen, "text", texture)
end
end
end
local reset_player_damage = function(player)
player_damage = 0
update_damage_screen(player)
end
local reset_player = function(player, reset_type)
if reset_type == "water_ship" then
local spawn = vector.add(lzr_globals.MENU_SHIP_POS, lzr_globals.MENU_SHIP_PLAYER_RESPAWN_OFFSET)
@ -102,9 +62,13 @@ local reset_player = function(player, reset_type)
lzr_messages.show_message(player, S("Where yer thinks yar goin, landlubber?"), 6.0, 0xFF0000)
lzr_levels.leave_level(true)
elseif reset_type == "skull_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)
lzr_messages.show_message(player, S("You were skull-crushed!"), 6.0, 0xFF0000)
lzr_levels.leave_level(true)
elseif 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)
lzr_messages.show_message(player, S("You were between a rock and a hard place."), 6.0, 0xFF0000)
lzr_levels.leave_level(true)
else
@ -112,45 +76,7 @@ local reset_player = function(player, reset_type)
end
crush_timer = 0
out_of_bounds_timer = 0
safe_timer = 0
reset_player_damage(player)
end
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
elseif player_damage >= 2 then
gain = 0.7
else
gain = 0.4
end
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)
else
minetest.sound_play({name="lzr_fallout_damage", gain=gain}, {to_player=player:get_player_name()}, true)
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)
end
end
local undamage_player = function(player)
player_damage = math.max(0, player_damage - 1)
update_damage_screen(player)
end
lzr_fallout.add_player_damage = function(player, reset_type, damage)
damage_player(player, reset_type, damage)
lzr_damage.reset_player_damage(player)
end
local step_timer = 0
@ -164,7 +90,7 @@ minetest.register_globalstep(function(dtime)
local players = minetest.get_connected_players()
local state = lzr_gamestate.get_state()
if state == lzr_gamestate.EDITOR or state == lzr_gamestate.DEV or state == lzr_gamestate.SHUTDOWN or state == lzr_gamestate.LEVEL_COMPLETE then
if state == lzr_gamestate.EDITOR or state == lzr_gamestate.DEV or state == lzr_gamestate.SHUTDOWN then
return
end
for p=1, #players do
@ -181,9 +107,8 @@ minetest.register_globalstep(function(dtime)
end
crush_timer = 0
out_of_bounds_timer = 0
safe_timer = 0
level_timer = 0
reset_player_damage(player)
lzr_damage.reset_player_damage(player)
elseif state == lzr_gamestate.LEVEL then
-- Don't do fallout stuff when level is not fully loaded yet
if not level_ready then
@ -227,6 +152,8 @@ minetest.register_globalstep(function(dtime)
end
end
local max_damage = lzr_damage.get_player_damage(player) == lzr_damage.MAX_DAMAGE
-- Being in an invalid place does not immediately trigger
-- a player reset, but first increases an internal damage
-- counter. Only if the damage exceeds a limit will
@ -234,33 +161,30 @@ minetest.register_globalstep(function(dtime)
-- This gives the player a chance to get out of sticky situations.
if out_of_bounds_timer > 1 then
out_of_bounds_timer = 0
safe_timer = 0
damage_player(player, reset_type)
if max_damage then
reset_player(player, reset_type)
else
lzr_damage.damage_player(player)
end
elseif crush_timer > 1 then
crush_timer = 0
safe_timer = 0
damage_player(player, reset_type)
elseif out_of_bounds_timer == 0 and crush_timer == 0 then
safe_timer = safe_timer + ddtime
if safe_timer > 3 then
-- Reduce damage when safe
undamage_player(player)
safe_timer = 0
if max_damage then
reset_player(player, reset_type)
else
lzr_damage.damage_player(player)
end
end
else
crush_timer = 0
out_of_bounds_timer = 0
safe_timer = 0
level_timer = 0
reset_player_damage(player)
lzr_damage.reset_player_damage(player)
end
else
crush_timer = 0
out_of_bounds_timer = 0
safe_timer = 0
level_timer = 0
reset_player_damage(player)
lzr_damage.reset_player_damage(player)
end
end
end)
@ -270,23 +194,9 @@ lzr_levels.register_on_level_start(function()
level_ready = true
crush_timer = 0
out_of_bounds_timer = 0
safe_timer = 0
level_timer = 0
end)
lzr_levels.register_on_level_start_loading(function()
level_ready = false
local player = minetest.get_player_by_name("singleplayer")
if player then
reset_player_damage(player)
end
end)
-- Reset player damage when entering any state but the level
lzr_gamestate.register_on_enter_state(function(new_state)
if new_state ~= lzr_gamestate.LEVEL and new_state ~= lzr_gamestate.LEVEL_COMPLETE then
local player = minetest.get_player_by_name("singleplayer")
if player then
reset_player_damage(player)
end
end
end)

View File

@ -1,2 +1,2 @@
name = lzr_fallout
depends = lzr_globals, lzr_levels, lzr_world
depends = lzr_globals, lzr_levels, lzr_world, lzr_damage

View File

@ -1566,7 +1566,7 @@ local def_bomb_takable_on = {
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_damage.damage_player(objs[o], lzr_damage.MAX_DAMAGE)
lzr_slowdown.slowdown(objs[o], BOMB_SLOWDOWN_TIME)
end
end

View File

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