Split player damage and fallout logic
@ -67,7 +67,7 @@ All levels by Wuzzy.
|
|||||||
- `lzr_menu_speaker_*.png`:
|
- `lzr_menu_speaker_*.png`:
|
||||||
- By MCL <temp1@cubesoftware.xyz>
|
- By MCL <temp1@cubesoftware.xyz>
|
||||||
- License: CC BY 4.0
|
- License: CC BY 4.0
|
||||||
- `lzr_fallout_damage_screen_*.png`:
|
- `lzr_damage_screen_*.png`:
|
||||||
- By Wuzzy
|
- By Wuzzy
|
||||||
- License: CC BY 4.0
|
- License: CC BY 4.0
|
||||||
- `lzr_laser_bomb_smoke_*.png`:
|
- `lzr_laser_bomb_smoke_*.png`:
|
||||||
@ -199,7 +199,7 @@ All levels by Wuzzy.
|
|||||||
- `lzr_menu_speaker_turn_off.ogg`:
|
- `lzr_menu_speaker_turn_off.ogg`:
|
||||||
- by mincedbeats <https://freesound.org/people/mincedbeats/sounds/593996/>
|
- by mincedbeats <https://freesound.org/people/mincedbeats/sounds/593996/>
|
||||||
- License: CC0
|
- License: CC0
|
||||||
- `lzr_fallout_damage.ogg`:
|
- `lzr_damage_damage.ogg`:
|
||||||
- by newagesoup <https://freesound.org/people/newagesoup/sounds/348242/>
|
- by newagesoup <https://freesound.org/people/newagesoup/sounds/348242/>
|
||||||
- License: CC0
|
- License: CC0
|
||||||
- `lzr_fallout_skull_laugh.ogg`:
|
- `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
|
-- by activated cursed ckulls, it's impossible to win, so the
|
||||||
-- level must fail. But there is still a chance the player
|
-- level must fail. But there is still a chance the player
|
||||||
-- can fix this by jumping or walking out if not
|
-- can fix this by jumping or walking out if not
|
||||||
-- *completely* surrounded, which is why the damage
|
-- *completely* surrounded, which is why this mod uses
|
||||||
-- system has been added (see below)
|
-- a damage system via lzr_damage.
|
||||||
|
|
||||||
local S = minetest.get_translator("lzr_fallout")
|
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
|
-- In a level, players in an invalid position do not immediately
|
||||||
-- fail but first take "damage" as long they are in danger.
|
-- 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
|
-- Count the time for how long the player is being crushed, out of bounds
|
||||||
-- or safe (=not in any danger).
|
-- or safe (=not in any danger).
|
||||||
local crush_timer = 0
|
local crush_timer = 0
|
||||||
local out_of_bounds_timer = 0
|
local out_of_bounds_timer = 0
|
||||||
local safe_timer = 0
|
|
||||||
|
|
||||||
-- Counts time for how long we've been in a level.
|
-- Counts time for how long we've been in a level.
|
||||||
local level_timer = 0
|
local level_timer = 0
|
||||||
local level_ready = false
|
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)
|
local reset_player = function(player, reset_type)
|
||||||
if reset_type == "water_ship" then
|
if reset_type == "water_ship" then
|
||||||
local spawn = vector.add(lzr_globals.MENU_SHIP_POS, lzr_globals.MENU_SHIP_PLAYER_RESPAWN_OFFSET)
|
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_messages.show_message(player, S("Where yer thinks yar goin’, landlubber?"), 6.0, 0xFF0000)
|
||||||
lzr_levels.leave_level(true)
|
lzr_levels.leave_level(true)
|
||||||
elseif reset_type == "skull_crush" then
|
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_messages.show_message(player, S("You were skull-crushed!"), 6.0, 0xFF0000)
|
||||||
lzr_levels.leave_level(true)
|
lzr_levels.leave_level(true)
|
||||||
elseif reset_type == "crush" then
|
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_messages.show_message(player, S("You were between a rock and a hard place."), 6.0, 0xFF0000)
|
||||||
lzr_levels.leave_level(true)
|
lzr_levels.leave_level(true)
|
||||||
else
|
else
|
||||||
@ -112,45 +76,7 @@ local reset_player = function(player, reset_type)
|
|||||||
end
|
end
|
||||||
crush_timer = 0
|
crush_timer = 0
|
||||||
out_of_bounds_timer = 0
|
out_of_bounds_timer = 0
|
||||||
safe_timer = 0
|
lzr_damage.reset_player_damage(player)
|
||||||
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)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local step_timer = 0
|
local step_timer = 0
|
||||||
@ -164,7 +90,7 @@ minetest.register_globalstep(function(dtime)
|
|||||||
|
|
||||||
local players = minetest.get_connected_players()
|
local players = minetest.get_connected_players()
|
||||||
local state = lzr_gamestate.get_state()
|
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
|
return
|
||||||
end
|
end
|
||||||
for p=1, #players do
|
for p=1, #players do
|
||||||
@ -181,9 +107,8 @@ minetest.register_globalstep(function(dtime)
|
|||||||
end
|
end
|
||||||
crush_timer = 0
|
crush_timer = 0
|
||||||
out_of_bounds_timer = 0
|
out_of_bounds_timer = 0
|
||||||
safe_timer = 0
|
|
||||||
level_timer = 0
|
level_timer = 0
|
||||||
reset_player_damage(player)
|
lzr_damage.reset_player_damage(player)
|
||||||
elseif state == lzr_gamestate.LEVEL then
|
elseif state == lzr_gamestate.LEVEL then
|
||||||
-- Don't do fallout stuff when level is not fully loaded yet
|
-- Don't do fallout stuff when level is not fully loaded yet
|
||||||
if not level_ready then
|
if not level_ready then
|
||||||
@ -227,6 +152,8 @@ minetest.register_globalstep(function(dtime)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local max_damage = lzr_damage.get_player_damage(player) == lzr_damage.MAX_DAMAGE
|
||||||
|
|
||||||
-- Being in an invalid place does not immediately trigger
|
-- Being in an invalid place does not immediately trigger
|
||||||
-- a player reset, but first increases an internal damage
|
-- a player reset, but first increases an internal damage
|
||||||
-- counter. Only if the damage exceeds a limit will
|
-- 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.
|
-- This gives the player a chance to get out of sticky situations.
|
||||||
if out_of_bounds_timer > 1 then
|
if out_of_bounds_timer > 1 then
|
||||||
out_of_bounds_timer = 0
|
out_of_bounds_timer = 0
|
||||||
safe_timer = 0
|
if max_damage then
|
||||||
damage_player(player, reset_type)
|
reset_player(player, reset_type)
|
||||||
|
else
|
||||||
|
lzr_damage.damage_player(player)
|
||||||
|
end
|
||||||
elseif crush_timer > 1 then
|
elseif crush_timer > 1 then
|
||||||
crush_timer = 0
|
crush_timer = 0
|
||||||
safe_timer = 0
|
if max_damage then
|
||||||
damage_player(player, reset_type)
|
reset_player(player, reset_type)
|
||||||
elseif out_of_bounds_timer == 0 and crush_timer == 0 then
|
else
|
||||||
safe_timer = safe_timer + ddtime
|
lzr_damage.damage_player(player)
|
||||||
if safe_timer > 3 then
|
|
||||||
-- Reduce damage when safe
|
|
||||||
undamage_player(player)
|
|
||||||
safe_timer = 0
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
crush_timer = 0
|
crush_timer = 0
|
||||||
out_of_bounds_timer = 0
|
out_of_bounds_timer = 0
|
||||||
safe_timer = 0
|
|
||||||
level_timer = 0
|
level_timer = 0
|
||||||
reset_player_damage(player)
|
lzr_damage.reset_player_damage(player)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
crush_timer = 0
|
crush_timer = 0
|
||||||
out_of_bounds_timer = 0
|
out_of_bounds_timer = 0
|
||||||
safe_timer = 0
|
|
||||||
level_timer = 0
|
level_timer = 0
|
||||||
reset_player_damage(player)
|
lzr_damage.reset_player_damage(player)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
@ -270,23 +194,9 @@ lzr_levels.register_on_level_start(function()
|
|||||||
level_ready = true
|
level_ready = true
|
||||||
crush_timer = 0
|
crush_timer = 0
|
||||||
out_of_bounds_timer = 0
|
out_of_bounds_timer = 0
|
||||||
safe_timer = 0
|
|
||||||
level_timer = 0
|
level_timer = 0
|
||||||
end)
|
end)
|
||||||
lzr_levels.register_on_level_start_loading(function()
|
lzr_levels.register_on_level_start_loading(function()
|
||||||
level_ready = false
|
level_ready = false
|
||||||
local player = minetest.get_player_by_name("singleplayer")
|
|
||||||
if player then
|
|
||||||
reset_player_damage(player)
|
|
||||||
end
|
|
||||||
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
|
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)
|
local objs = minetest.get_objects_inside_radius(pos, BOMB_DAMAGE_RADIUS)
|
||||||
for o=1, #objs do
|
for o=1, #objs do
|
||||||
if objs[o]:is_player() then
|
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)
|
lzr_slowdown.slowdown(objs[o], BOMB_SLOWDOWN_TIME)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
name = lzr_laser
|
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
|
||||||
|