Split player damage and fallout logic
@ -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
@ -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 hasn’t 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
@ -0,0 +1,2 @@
|
||||
name = lzr_damage
|
||||
depends = lzr_gamestate
|
Before Width: | Height: | Size: 8.7 KiB After Width: | Height: | Size: 8.7 KiB |
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 42 KiB |
Before Width: | Height: | Size: 53 KiB After Width: | Height: | Size: 53 KiB |
@ -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)
|
||||
|
@ -1,2 +1,2 @@
|
||||
name = lzr_fallout
|
||||
depends = lzr_globals, lzr_levels, lzr_world
|
||||
depends = lzr_globals, lzr_levels, lzr_world, lzr_damage
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|