Boss fight

This commit is contained in:
Wuzzy 2023-12-21 15:26:43 +01:00
parent 877a06eb21
commit 83005711a0
10 changed files with 126 additions and 50 deletions

View File

@ -6,13 +6,13 @@ local DEFAULT_DURATION = 4000000
local speakers = {
light_orb = { image = "sf_messages_speaker_light_orb.png", sound = {name="sf_messages_speaker_light_orb", gain=0.5} },
wizard = { image = "sf_messages_speaker_wizard.png", sound = {name="sf_messages_speaker_wizard", gain=0.5} },
shadow_orb = { image = "sf_messages_speaker_shadow_orb.png", sound = {name="sf_messages_speaker_shadow_orb", gain=0.5} },
shadow_orb = { image = "sf_messages_speaker_shadow_orb.png", sound = {name="sf_messages_speaker_light_orb", gain=0.6, pitch=0.5} },
meta = { image = "blank.png", sound = {name="sf_messages_speaker_light_orb", gain=0.5} },
}
local orb = speakers.light_orb
local wiz = speakers.wizard
local sha = speakers.boss
local met = speakers.dev
local sha = speakers.shadow_orb
local met = speakers.meta
local dialog_texts = {
["intro"] = { texts = {
@ -34,14 +34,15 @@ local dialog_texts = {
["enemy_hint"] = { texts = {
{ met, S("Use the staff of light to defend yourself."), },
}},
["boss"] = { texts = {
{ sha, S("I am the mighty Shadow Orb! Prepare to die!") },
}},
["outro"] = { texts = {
{ wiz, S("BOOM! Take that, shadow creature!"), },
{ orb, S("Peace, at last."), },
{ orb, S("So will the forest return to normal?"), },
{ wiz, S("Yes. But it will take time to heal …"), },
{ met, S("THANK YOU FOR PLAYING SHADOW FOREST!") },
{ met, S("Game over. You can either exit the game now …") },
{ met, S("… or try to find the remaining vases.") },
}},
["chimneys"] = { texts = {
{ orb, S("What is this?") },
@ -86,9 +87,9 @@ local dialog_texts = {
{ wiz, S("OMENA TENMU GNURF PELMI!"), },
{ orb, S("Oh, THATS what the light crystals are for!"), },
}},
["darkness_warning"] = { texts =
{ orb, S("This place is so dark, not even I can light it up."),
{ orb, S("I sense a great danger …") }
["darkness_warning"] = { texts = {
{ orb, S("This place is so dark, not even I can light it up.") },
{ orb, S("I sense a great danger …") },
}},
["darkness_damage"] = { texts = {
{ orb, S("The shadows are violent! Turn back!") }

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

@ -1,2 +1,2 @@
name = sf_mobs
depends = sf_util, sf_particles, sf_projectiles, sf_upgrade, sf_resources
depends = sf_util, sf_particles, sf_projectiles, sf_upgrade, sf_resources, sf_zones

View File

@ -33,7 +33,7 @@ local SHADOW_ORB_ATTACK_TIMER = 0.5
local SHADOW_ORB_ATTACK_RANGE = 32
local SHADOW_ORB_PROJECTILE_SPEED = 15
local SHADOW_ORB_SPAWN_TIMER = 5
local SHADOW_ORB_SPAWN_CHECK_RANGE = 5
local SHADOW_ORB_SPAWN_CHECK_RANGE = 30
local SHADOW_ORB_SPAWN_COUNT = 4
local SHADOW_ORB_SPAWN_MAX_COUNT = 10
local SHADOW_ORB_FRAGMENTS = 80
@ -450,7 +450,7 @@ minetest.register_entity("sf_mobs:shadow_orb", {
on_activate = function(self)
self.object:set_armor_groups({shadow_physical=100})
end,
on_death = function(self, killer)
on_death = function(self)
local pos = self.object:get_pos()
minetest.add_particlespawner({
amount = 13,
@ -527,6 +527,20 @@ minetest.register_entity("sf_mobs:shadow_orb", {
})
end
end
local boss_arena = sf_zones.get_zone("boss_arena")
sf_util.break_nodes_in_area(boss_arena.pos_min, boss_arena.pos_max, "sf_nodes:weak_concrete", nil)
local player = sf_util.get_closest_player(pos)
if player and player:is_player() then
local pmeta = player:get_meta()
pmeta:set_int("sf_mobs:boss_defeated", 1)
end
minetest.after(3, function(player)
if player and player:is_player() then
sf_dialog.show_dialog(player, "outro", true)
end
end, player)
end,
on_punch = on_punch_default,
on_step = function(self, dtime, moveresult)

View File

@ -31,6 +31,9 @@ local register_mob_spawner = function(id, def)
if EDITOR then
return
end
if def.limit == 0 then
return
end
local objs = minetest.get_objects_inside_radius(pos, math.max(SPAWNER_PREVENT_RANGE, SPAWNER_LIMIT_RANGE))
local mobs_of_same_kind = 0
for o=1, #objs do

View File

@ -339,6 +339,18 @@ minetest.register_node("sf_nodes:concrete", {
})
make_leveled_node("sf_nodes:concrete", S("Leveled Concrete"))
local wconcrete_tiles
if EDITOR then
wconcrete_tiles = { "sf_nodes_concrete.png^sf_nodes_weak_concrete_overlay.png" }
else
wconcrete_tiles = { "sf_nodes_concrete.png" }
end
minetest.register_node("sf_nodes:weak_concrete", {
description = S("Weak Concrete"),
tiles = wconcrete_tiles,
groups = { editor_breakable = 1 },
sounds = sf_sounds.node_sound_stone_defaults(),
})
minetest.register_node("sf_nodes:tree", {
description = S("Tree"),

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 B

View File

@ -1,3 +1,5 @@
local GRAVITY = 9.81
sf_util = {}
sf_util.get_singleplayer = function()
@ -115,3 +117,47 @@ function sf_util.set_xz_nodes(pos, min_y, nodename, leveled_nodename, vmanip_are
end
end
end
sf_util.break_nodes_in_area = function(pos_min, pos_max, nodename, sound)
local nodes = minetest.find_nodes_in_area(pos_min, pos_max, nodename)
local broken = 0
for n=1,#nodes do
local nodepos = nodes[n]
minetest.remove_node(nodepos)
minetest.add_particlespawner({
amount = 16,
time = 0.05,
exptime = {
min = 1,
max = 1.5,
},
pos = {
min = vector.add(nodepos, vector.new(-0.2, -0.2, -0.2)),
max = vector.add(nodepos, vector.new(0.2, 0.2, 0.2)),
},
vel = {
min = vector.new(-2, -2, -2),
max = vector.new(2, 2, 2),
},
size = 2,
drag = vector.new(2, 0, 2),
acc = vector.new(0, -GRAVITY, 0),
collisiondetection = true,
node = {name=nodename},
})
broken = broken + 1
end
if broken > 0 then
local pos = table.copy(pos_min)
-- Get area middle to play sound
pos.x = pos_min.x + (pos_max.x - pos_min.x)/2
pos.y = pos_min.y + (pos_max.y - pos_min.y)/2
pos.z = pos_min.z + (pos_max.z - pos_min.z)/2
if sound then
minetest.sound_play(sound, {pos=pos}, true)
end
minetest.log("action", "[sf_util] "..broken.." node(s) of type '"..nodename.."' broken in area")
end
end

View File

@ -158,45 +158,8 @@ sf_zones.register_zone("chimneys", {
sf_dialog.show_dialog(player, "chimneys", true)
end,
})
local break_weak_spikeplants_in_area = function(pos_min, pos_max)
local bushes = minetest.find_nodes_in_area(pos_min, pos_max, "sf_nodes:spikeplant_weak")
local broken = 0
for b=1,#bushes do
local bush = bushes[b]
minetest.remove_node(bush)
minetest.add_particlespawner({
amount = 16,
time = 0.05,
exptime = {
min = 1,
max = 1.5,
},
pos = {
min = vector.add(bush, vector.new(-0.2, -0.2, -0.2)),
max = vector.add(bush, vector.new(0.2, 0.2, 0.2)),
},
vel = {
min = vector.new(-2, -2, -2),
max = vector.new(2, 2, 2),
},
size = 2,
drag = vector.new(2, 0, 2),
acc = vector.new(0, -GRAVITY, 0),
collisiondetection = true,
node = {name="sf_nodes:spikeplant_weak"},
})
broken = broken + 1
end
if broken > 0 then
local pos = table.copy(pos_min)
-- Get zone middle
pos.x = pos_min.x + (pos_max.x - pos_min.x)/2
pos.y = pos_min.y + (pos_max.y - pos_min.y)/2
pos.z = pos_min.z + (pos_max.z - pos_min.z)/2
minetest.sound_play({name = "sf_zones_spikeplant_break", gain=1.0}, {pos=pos}, true)
minetest.log("action", "[sf_dialog] "..broken.." weak shadow bush(es) broken!")
end
sf_util.break_nodes_in_area(pos_min, pos_max, "sf_nodes:spikeplant_weak", {name = "sf_zones_spikeplant_break", gain=1.0})
end
sf_zones.register_zone("shadow_bush_barrier", {
@ -216,6 +179,43 @@ sf_zones.register_zone("shadow_bush_barrier", {
end,
})
sf_zones.register_zone("boss_arena", {
pos_min = vector.new(52, 12, 20),
pos_max = vector.new(76, 41, 64),
})
sf_zones.register_zone("boss_arena_enter", {
pos_min = vector.new(52, 12, 40),
pos_max = vector.new(76, 30, 64),
on_enter = function(zonename, player)
local zone = sf_zones.get_zone("boss_arena")
local objs = minetest.get_objects_in_area(zone.pos_min, zone.pos_max)
local boss_exists = false
local pmeta = player:get_meta()
if pmeta:get_int("sf_mobs:boss_defeated") == 1 then
minetest.log("action", "[sf_zones] "..player:get_player_name().." entered boss arena but boss already defeated")
return
end
for o=1, #objs do
local lua = objs[o]:get_luaentity()
if lua and lua.name == "sf_mobs:shadow_orb" then
boss_exists = true
break
end
end
if not boss_exists then
local spawners = minetest.find_nodes_in_area(zone.pos_min, zone.pos_max, "sf_mobs:spawner_shadow_orb")
for s=1, #spawners do
minetest.add_entity(spawners[s], "sf_mobs:shadow_orb")
minetest.log("action", "[sf_zones] Shadow orb boss spawed at "..minetest.pos_to_string(spawners[s]))
end
end
sf_dialog.show_dialog(player, "boss", true)
end,
})
-- TODO: The music for the "shrine" zones is kinda hacky, this only
-- works as long these are embedded completely in another zone
sf_zones.register_zone("snow_mountain_shrine", {

View File

@ -1,2 +1,2 @@
name = sf_zones
depends = sf_sky, sf_music, sf_dialog
depends = sf_sky, sf_music, sf_dialog, sf_util