Compare commits

...

15 Commits

Author SHA1 Message Date
cora a0c83e72b9 Add hero of the village achievement 2022-10-25 01:20:09 +02:00
cora ad6326271e raids: properly integrate potions api
supports "level" now, bad omen > 1 means extra wave additionally
the playername is saved in the event object now for later access
and events can be made exclusive to a certain radius now.
2022-10-25 00:30:14 +02:00
cora bf50fd4bef Remove dependency on mcl_potions 2022-10-24 23:23:08 +02:00
cora 4b0da270d5 Check for actual raid conditions and positions 2022-10-24 17:37:30 +02:00
cora 952e88bdef Make debug output an opt-in setting 2022-10-24 17:37:11 +02:00
cora 62ba054906 fix closure style function declarations
its BANNED in CONTRIB.md
2022-10-24 17:17:22 +02:00
cora 1e2ae7e006 Integrate raids with mcl_events 2022-10-24 17:06:08 +02:00
cora 771192d2f9 start at effective stage 1 2022-10-24 17:06:08 +02:00
cora d22aad03f5 Add bossbar support 2022-10-24 17:06:08 +02:00
cora 9ec4f7847b Finish at max_stage not max_stage + 1 2022-10-24 17:06:08 +02:00
cora 2c3aeb3b4d Add event api
prototype state, test with chatcommand /infest (debug priv)
2022-10-24 17:06:08 +02:00
PrairieWind 250bb0fe22 Village Finder Tweaks 2022-10-24 17:06:08 +02:00
PrairieWind 2fdda8ca30 Add Village Checks 2022-10-24 17:06:08 +02:00
PrairieWind a57da30742 Add Bad Omen Effect 2022-10-24 17:06:08 +02:00
PrairieAstronomer 007c238e4f Add mcl_raids 2022-10-24 17:05:09 +02:00
9 changed files with 427 additions and 4 deletions

View File

@ -0,0 +1,190 @@
mcl_events = {}
mcl_events.registered_events = {}
local DBG = minetest.settings:get_bool("mcl_logging_event_api",false)
local active_events = {}
local tpl_eventdef = {
stage = 0,
max_stage = 1,
percent = 100,
bars = {},
--pos = vector.zero(),
--time_start = 0,
completed = false,
cond_start = function(event) end, --return table of positions
on_step = function(event) end,
on_start = function(event) end,
on_stage_begin = function(event) end,
cond_progress = function(event) end, --return next stage
cond_complete = function(event) end, --return success
}
local function mcl_log(m,l)
if DBG then
if not l then l = "action" end
minetest.log(l,"[mcl_events] "..m)
end
end
function mcl_events.register_event(name,def)
mcl_events.registered_events[name] = {}
--setmetatable(mcl_events.registered_events[name],tpl_eventdef)
mcl_events.registered_events[name] = def
mcl_events.registered_events[name].name = name
end
local function addbars(self)
for _,player in pairs(minetest.get_connected_players()) do
if vector.distance(self.pos,player:get_pos()) < 75 then
local bar = mcl_bossbars.add_bar(player, {color = "red", text = self.name .. " stage "..self.stage.." / "..self.max_stage, percentage = self.percent }, true,1)
table.insert(self.bars,bar)
end
end
end
local function update_bars(self)
for _,b in pairs(self.bars) do
mcl_bossbars.update_bar(b,{text = self.name .. " stage "..self.stage,percentage=self.percent})
end
end
local function start_event(p,e)
mcl_log("event started: "..e.name.." at "..minetest.pos_to_string(vector.round(p.pos)))
local idx = #active_events + 1
active_events[idx] = table.copy(e)
setmetatable(active_events[idx],e)
for k,v in pairs(p) do active_events[idx][k] = v end
active_events[idx].stage = 0
active_events[idx].percent = 100
active_events[idx].bars = {}
active_events[idx].time_start = os.time()
active_events[idx]:on_start(p.pos)
addbars(active_events[idx])
end
local function finish_event(self,idx)
mcl_log("Finished: "..self.name.." at "..minetest.pos_to_string(vector.round(self.pos)))
if self.on_complete then self:on_complete() end
for _,b in pairs(self.bars) do
mcl_bossbars.remove_bar(b)
end
table.remove(active_events,idx)
end
local etime = 0
function check_events(dtime)
for idx,ae in pairs(active_events) do
if ae.cond_complete and ae:cond_complete() then
ae.finished = true
finish_event(ae,idx)
elseif not ae.cond_complete and ae.max_stage and ae.max_stage <= ae.stage then
ae.finished = true
finish_event(ae,idx)
elseif not ae.finished and ae.cond_progress then
local p = ae:cond_progress()
if p == true then
ae.stage = ae.stage + 1
ae:on_stage_begin()
elseif tonumber(p) then
ae.stage = tonumber(p) or ae.stage + 1
ae:on_stage_begin()
end
elseif not ae.finished and ae.on_step then
ae:on_step()
end
addbars(ae)
--update_bars(ae)
end
etime = etime - dtime
if etime > 0 then return end
etime = 10
for _,e in pairs(mcl_events.registered_events) do
local pp = e.cond_start()
if pp then
for _,p in pairs(pp) do
local start = true
if e.exclusive_to_area then
for _,ae in pairs(active_events) do
if e.name == ae.name and vector.distance(p.pos,ae.pos) < e.exclusive_to_area then start = false end
end
end
if start then
start_event(p,e)
elseif DBG then
mcl_log("event "..e.name.." already active at "..minetest.pos_to_string(vector.round(p.pos)))
end
end
end
end
end
minetest.register_globalstep(check_events)
mcl_events.register_event("infestation",{
max_stage = 5,
health = 1,
health_max = 1,
cond_start = function(self)
local r = {}
for _,p in pairs(minetest.get_connected_players()) do
if p:get_meta():get_string("infestation-omen") == "yes" then
p:get_meta():set_string("infestation-omen","")
table.insert(r,p:get_pos())
end
end
if #r > 0 then return r end
end,
on_start = function(self)
self.mobs = {}
self.health_max = 1
self.health = 0
end,
cond_progress = function(self)
local m = {}
local h = 0
for k,o in pairs(self.mobs) do
if o and o:get_pos() then
local l = o:get_luaentity()
h = h + l.health
table.insert(m,o)
end
end
self.mobs = m
self.health = h
self.percent = math.max(0,(self.health / self.health_max ) * 100)
if #m < 1 then
return true end
end,
on_stage_begin = function(self)
self.health_max = 0
for i=1,15 * self.stage do
local m = mcl_mobs.spawn(vector.add(self.pos,vector.new(math.random(20)-10,0,math.random(20)-10)),"mobs_mc:silverfish")
local l = m:get_luaentity()
if l then
self.health_max = self.health_max + l.health
table.insert(self.mobs,m)
end
end
end,
cond_complete = function(self)
local m = {}
for k,o in pairs(self.mobs) do
if o and o:get_pos() then
local l = o:get_luaentity()
table.insert(m,o)
end
end
return self.stage >= self.max_stage and #m < 1
end,
on_complete = function(self)
mcl_log("INFESTATION complete")
end,
})
minetest.register_chatcommand("infest",{
privs = {debug = true},
func = function(n,param)
local p = minetest.get_player_by_name(n)
p:get_meta():set_string("infestation-omen","yes")
end,
})

View File

@ -0,0 +1,3 @@
name = mcl_events
author = cora
depends = mcl_mobs,mcl_bossbars

View File

@ -0,0 +1,166 @@
-- mcl_raids
mcl_raids = {}
-- Define the amount of illagers to spawn each wave.
local waves = {
{
["mobs_mc:pillager"] = 5,
["mobs_mc:vindicator"] = 1,
},
{
["mobs_mc:pillager"] = 4,
["mobs_mc:vindicator"] = 3,
},
{
["mobs_mc:pillager"] = 4,
["mobs_mc:vindicator"] = 1,
["mobs_mc:witch"] = 1,
--["mobs_mc:ravager"] = 1,
},
{
["mobs_mc:pillager"] = 5,
["mobs_mc:vindicator"] = 2,
["mobs_mc:witch"] = 3,
},
{
["mobs_mc:pillager"] = 5,
["mobs_mc:vindicator"] = 5,
["mobs_mc:witch"] = 1,
["mobs_mc:evoker"] = 1,
},
}
local extra_wave = {
["mobs_mc:pillager"] = 5,
["mobs_mc:vindicator"] = 5,
["mobs_mc:witch"] = 1,
["mobs_mc:evoker"] = 1,
--["mobs_mc:ravager"] = 2,
}
function mcl_raids.spawn_raid(event)
local pos = event.pos
local wave = event.stage
local illager_count = 0
local spawnable = false
local r = 32
local n = 12
local i = math.random(1, n)
local raid_pos = vector.offset(pos,r * math.cos(((i-1)/n) * (2*math.pi)),0, r * math.sin(((i-1)/n) * (2*math.pi)))
local sn = minetest.find_nodes_in_area_under_air(vector.offset(raid_pos,-5,-50,-5), vector.offset(raid_pos,5,50,5), {"group:grass_block", "group:grass_block_snow", "group:snow_cover", "group:sand"})
mcl_bells.ring_once(pos)
if sn and #sn > 0 then
local spawn_pos = sn[math.random(#sn)]
if spawn_pos then
minetest.log("action", "[mcl_raids] Raid Spawn Position chosen at " .. minetest.pos_to_string(spawn_pos) .. ".")
event.health_max = 0
local w
if event.stage <= #waves then
w= waves[event.stage]
else
w = extra_wave
end
for m,c in pairs(w) do
for i=1,c do
local mob = mcl_mobs.spawn(spawn_pos,m)
local l = mob:get_luaentity()
if l then
event.health_max = event.health_max + l.health
table.insert(event.mobs,mob)
end
end
end
minetest.log("action", "[mcl_raids] Raid Spawned. Illager Count: " .. #event.mobs .. ".")
else
minetest.log("action", "[mcl_raids] Raid Spawn Postion not chosen.")
end
elseif not sn then
minetest.log("action", "[mcl_raids] Raid Spawn Position error, no appropriate site found.")
end
end
function mcl_raids.find_villager(pos)
local obj = minetest.get_objects_inside_radius(pos, 8)
for _, objects in ipairs(obj) do
local object = objects:get_luaentity()
if object then
if object.name ~= "mobs_mc:villager" then
return
elseif object.name == "mobs_mc:villager" then
minetest.log("action", "[mcl_raids] Villager Found.")
return true
else
minetest.log("action", "[mcl_raids] No Villager Found.")
return false
end
end
end
end
function mcl_raids.find_bed(pos)
return minetest.find_node_near(pos,128,{"mcl_beds:bed_red_bottom"})
end
function mcl_raids.find_village(pos)
local bed = mcl_raids.find_bed(pos)
if bed and mcl_raids.find_villager(bed) then
return bed
end
end
mcl_events.register_event("raid",{
max_stage = 5,
health = 1,
health_max = 1,
exclusive_to_area = 128,
cond_start = function(self)
local r = {}
for _,p in pairs(minetest.get_connected_players()) do
if mcl_potions.player_has_effect(p,"bad_omen") then
local raid_pos = mcl_raids.find_village(p:get_pos())
if raid_pos then
table.insert(r,{ player = p:get_player_name(), pos = raid_pos })
end
end
end
if #r > 0 then return r end
end,
on_start = function(self)
self.mobs = {}
self.health_max = 1
self.health = 0
local lv = mcl_potions.player_get_effect(minetest.get_player_by_name(self.player), "bad_omen").factor
if lv and lv > 1 then self.max_stage = 6 end
end,
cond_progress = function(self)
local m = {}
local h = 0
for k,o in pairs(self.mobs) do
if o and o:get_pos() then
local l = o:get_luaentity()
h = h + l.health
table.insert(m,o)
end
end
self.mobs = m
self.health = h
self.percent = math.max(0,(self.health / self.health_max ) * 100)
if #m < 1 then
return true end
end,
on_stage_begin = mcl_raids.spawn_raid,
cond_complete = function(self)
local m = {}
for k,o in pairs(self.mobs) do
if o and o:get_pos() then
local l = o:get_luaentity()
table.insert(m,o)
end
end
return self.stage >= self.max_stage and #m < 1
end,
on_complete = function(self)
--minetest.log("RAID complete")
awards.unlock(self.player,"mcl:hero_of_the_village")
end,
})

View File

@ -0,0 +1,3 @@
name = mcl_raids
author = PrairieWind
depends = mcl_events, mcl_mobs, mcl_potions, mcl_bells, mcl_achievements

View File

@ -487,3 +487,11 @@ awards.register_achievement("mcl:obsidian", {
type = "Advancement",
group = "Overworld",
})
awards.register_achievement("mcl:hero_of_the_village", {
title = S("Hero of the village"),
description = S("Successfully defend a village from a raid"),
icon = "mcl_raids_hero_of_the_village_icon.png",
type = "Advancement",
group = "Overworld",
})

View File

@ -19,6 +19,7 @@ get_chat_function["water_breathing"] = mcl_potions.water_breathing_func
get_chat_function["leaping"] = mcl_potions.leaping_func
get_chat_function["swiftness"] = mcl_potions.swiftness_func
get_chat_function["heal"] = mcl_potions.healing_func
get_chat_function["bad_omen"] = mcl_potions.bad_omen_func
minetest.register_chatcommand("effect",{
params = S("<effect> <duration> [<factor>]"),

View File

@ -9,6 +9,7 @@ EF.leaping = {}
EF.swift = {} -- for swiftness AND slowness
EF.night_vision = {}
EF.fire_proof = {}
EF.bad_omen = {}
local EFFECT_TYPES = 0
for _,_ in pairs(EF) do
@ -350,6 +351,26 @@ minetest.register_globalstep(function(dtime)
end
-- Check for Bad Omen
for player, vals in pairs(EF.bad_omen) do
is_player = player:is_player()
EF.bad_omen[player].timer = EF.bad_omen[player].timer + dtime
if player:get_pos() then mcl_potions._add_spawner(player, "#0b6138") end
if EF.bad_omen[player] and EF.bad_omen[player].timer >= EF.bad_omen[player].dur then
EF.bad_omen[player] = nil
if is_player then
meta = player:get_meta()
meta:set_string("_has_bad_omen", minetest.serialize(EF.bad_omen[player]))
potions_set_hud(player)
end
end
end
end)
-- Prevent damage to player with Fire Resistance enabled
@ -386,7 +407,8 @@ function mcl_potions._clear_cached_player_data(player)
EF.swift[player] = nil
EF.night_vision[player] = nil
EF.fire_proof[player] = nil
EF.bad_omen[player] = nil
meta = player:get_meta()
meta:set_int("night_vision", 0)
end
@ -400,9 +422,9 @@ function mcl_potions._reset_player_effects(player, set_hud)
mcl_potions.make_invisible(player, false)
playerphysics.remove_physics_factor(player, "jump", "mcl_potions:leaping")
playerphysics.remove_physics_factor(player, "speed", "mcl_potions:swiftness")
mcl_weather.skycolor.update_sky_color({player})
mcl_potions._clear_cached_player_data(player)
@ -429,6 +451,7 @@ function mcl_potions._save_player_effects(player)
meta:set_string("_is_swift", minetest.serialize(EF.swift[player]))
meta:set_string("_is_cat", minetest.serialize(EF.night_vision[player]))
meta:set_string("_is_fire_proof", minetest.serialize(EF.fire_proof[player]))
meta:set_string("_has_bad_omen", minetest.serialize(EF.bad_omen[player]))
end
@ -480,6 +503,10 @@ function mcl_potions._load_player_effects(player)
EF.fire_proof[player] = minetest.deserialize(meta:get_string("_is_fire_proof"))
end
if minetest.deserialize(meta:get_string("_has_bad_omen")) then
EF.bad_omen[player] = minetest.deserialize(meta:get_string("_has_bad_omen"))
end
end
-- Returns true if player has given effect
@ -490,6 +517,13 @@ function mcl_potions.player_has_effect(player, effect_name)
return EF[effect_name][player] ~= nil
end
function mcl_potions.player_get_effect(player, effect_name)
if not EF[effect_name] or not EF[effect_name][player] then
return false
end
return EF[effect_name][player]
end
minetest.register_on_leaveplayer( function(player)
mcl_potions._save_player_effects(player)
mcl_potions._clear_cached_player_data(player) -- clearout the buffer to prevent looking for a player not there
@ -966,3 +1000,18 @@ function mcl_potions._extinguish_nearby_fire(pos, radius)
end
return exting
end
function mcl_potions.bad_omen_func(player, factor, duration)
if not EF.bad_omen[player] then
EF.bad_omen[player] = {dur = duration, timer = 0, factor = factor}
else
local victim = EF.bad_omen[player]
victim.dur = math.max(duration, victim.dur - victim.timer)
victim.timer = 0
victim.factor = factor
end
if player:is_player() then
potions_set_icons(player)
end
end

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

View File

@ -221,4 +221,7 @@ mcl_logging_mapgen (Chunk generation logging) bool false
mcl_logging_structures (Structure generation logging) bool true
#Complete debug logging for mcl_signs events. Use this if you have issues with signs.
mcl_logging_mcl_signs (Complete debug logging for mcl_signs) bool true
mcl_logging_mcl_signs (Complete debug logging for mcl_signs) bool false
#Debug logging for mcl_events.
mcl_logging_event_api (Debug logging for mcl_events) bool false