Compare commits
4 commits
5ec98f1bbc
...
ec30bad0a9
Author | SHA1 | Date | |
---|---|---|---|
ec30bad0a9 | |||
287cf8f9b8 | |||
bd85d77cc8 | |||
6beb86428d |
410
mods/ENTITIES/mobs_mc/creeper.lua
Normal file
|
@ -0,0 +1,410 @@
|
|||
--License for code WTFPL and otherwise stated in readmes
|
||||
|
||||
local S = minetest.get_translator("mobs_mc")
|
||||
|
||||
--###################
|
||||
--################### CREEPER
|
||||
--###################
|
||||
|
||||
|
||||
|
||||
|
||||
mcl_mobs:register_mob("mobs_mc:creeper", {
|
||||
type = "monster",
|
||||
spawn_class = "hostile",
|
||||
spawn_in_group = 1,
|
||||
hp_min = 20,
|
||||
hp_max = 20,
|
||||
xp_min = 5,
|
||||
xp_max = 5,
|
||||
collisionbox = {-0.3, -0.01, -0.3, 0.3, 1.69, 0.3},
|
||||
pathfinding = 1,
|
||||
visual = "mesh",
|
||||
mesh = "mobs_mc_creeper.b3d",
|
||||
head_swivel = "Head_Control",
|
||||
bone_eye_height = 2.35,
|
||||
curiosity = 2,
|
||||
textures = {
|
||||
{"mobs_mc_creeper.png",
|
||||
"mobs_mc_empty.png"},
|
||||
},
|
||||
visual_size = {x=3, y=3},
|
||||
sounds = {
|
||||
attack = "tnt_ignite",
|
||||
death = "mobs_mc_creeper_death",
|
||||
damage = "mobs_mc_creeper_hurt",
|
||||
fuse = "tnt_ignite",
|
||||
explode = "tnt_explode",
|
||||
distance = 16,
|
||||
},
|
||||
makes_footstep_sound = true,
|
||||
walk_velocity = 1.05,
|
||||
run_velocity = 2.1,
|
||||
runaway_from = { "mobs_mc:ocelot", "mobs_mc:cat" },
|
||||
attack_type = "explode",
|
||||
|
||||
--hssssssssssss
|
||||
|
||||
explosion_strength = 3,
|
||||
explosion_radius = 3.5,
|
||||
explosion_damage_radius = 3.5,
|
||||
explosiontimer_reset_radius = 6,
|
||||
reach = 3,
|
||||
explosion_timer = 5,
|
||||
allow_fuse_reset = true,
|
||||
stop_to_explode = true,
|
||||
|
||||
-- Force-ignite creeper with flint and steel and explode after 1.5 seconds.
|
||||
-- TODO: Make creeper flash after doing this as well.
|
||||
-- TODO: Test and debug this code.
|
||||
on_rightclick = function(self, clicker)
|
||||
if self._forced_explosion_countdown_timer ~= nil then
|
||||
return
|
||||
end
|
||||
local item = clicker:get_wielded_item()
|
||||
if item:get_name() == "mcl_fire:flint_and_steel" then
|
||||
if not minetest.is_creative_enabled(clicker:get_player_name()) then
|
||||
-- Wear tool
|
||||
local wdef = item:get_definition()
|
||||
item:add_wear(1000)
|
||||
-- Tool break sound
|
||||
if item:get_count() == 0 and wdef.sound and wdef.sound.breaks then
|
||||
minetest.sound_play(wdef.sound.breaks, {pos = clicker:get_pos(), gain = 0.5}, true)
|
||||
end
|
||||
clicker:set_wielded_item(item)
|
||||
end
|
||||
self._forced_explosion_countdown_timer = self.explosion_timer
|
||||
minetest.sound_play(self.sounds.attack, {pos = self.object:get_pos(), gain = 1, max_hear_distance = 16}, true)
|
||||
end
|
||||
end,
|
||||
do_custom = function(self, dtime)
|
||||
if self._forced_explosion_countdown_timer ~= nil then
|
||||
self._forced_explosion_countdown_timer = self._forced_explosion_countdown_timer - dtime
|
||||
if self._forced_explosion_countdown_timer <= 0 then
|
||||
mcl_mobs:boom(self, mcl_util.get_object_center(self.object), self.explosion_strength)
|
||||
end
|
||||
end
|
||||
end,
|
||||
on_die = function(self, pos, cmi_cause)
|
||||
-- Drop a random music disc when killed by skeleton or stray
|
||||
if cmi_cause and cmi_cause.type == "punch" then
|
||||
local luaentity = cmi_cause.puncher and cmi_cause.puncher:get_luaentity()
|
||||
if luaentity and luaentity.name:find("arrow") then
|
||||
local shooter_luaentity = luaentity._shooter and luaentity._shooter:get_luaentity()
|
||||
if shooter_luaentity and (shooter_luaentity.name == "mobs_mc:skeleton" or shooter_luaentity.name == "mobs_mc:stray") then
|
||||
minetest.add_item({x=pos.x, y=pos.y+1, z=pos.z}, "mcl_jukebox:record_" .. math.random(9))
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
maxdrops = 2,
|
||||
drops = {
|
||||
{name = "mcl_mobitems:gunpowder",
|
||||
chance = 1,
|
||||
min = 0,
|
||||
max = 2,
|
||||
looting = "common",},
|
||||
|
||||
-- Head
|
||||
-- TODO: Only drop if killed by charged creeper
|
||||
{name = "mcl_heads:creeper",
|
||||
chance = 200, -- 0.5%
|
||||
min = 1,
|
||||
max = 1,},
|
||||
},
|
||||
animation = {
|
||||
speed_normal = 24,
|
||||
speed_run = 48,
|
||||
stand_start = 0,
|
||||
stand_end = 23,
|
||||
walk_start = 24,
|
||||
walk_end = 49,
|
||||
run_start = 24,
|
||||
run_end = 49,
|
||||
hurt_start = 110,
|
||||
hurt_end = 139,
|
||||
death_start = 140,
|
||||
death_end = 189,
|
||||
look_start = 50,
|
||||
look_end = 108,
|
||||
},
|
||||
floats = 1,
|
||||
fear_height = 4,
|
||||
view_range = 16,
|
||||
})
|
||||
|
||||
mcl_mobs:register_mob("mobs_mc:creeper_charged", {
|
||||
description = S("Creeper"),
|
||||
type = "monster",
|
||||
spawn_class = "hostile",
|
||||
hp_min = 20,
|
||||
hp_max = 20,
|
||||
xp_min = 5,
|
||||
xp_max = 5,
|
||||
collisionbox = {-0.3, -0.01, -0.3, 0.3, 1.69, 0.3},
|
||||
pathfinding = 1,
|
||||
visual = "mesh",
|
||||
mesh = "mobs_mc_creeper.b3d",
|
||||
|
||||
--BOOM
|
||||
|
||||
textures = {
|
||||
{"mobs_mc_creeper.png",
|
||||
"mobs_mc_creeper_charge.png"},
|
||||
},
|
||||
visual_size = {x=3, y=3},
|
||||
sounds = {
|
||||
attack = "tnt_ignite",
|
||||
death = "mobs_mc_creeper_death",
|
||||
damage = "mobs_mc_creeper_hurt",
|
||||
fuse = "tnt_ignite",
|
||||
explode = "tnt_explode",
|
||||
distance = 16,
|
||||
},
|
||||
makes_footstep_sound = true,
|
||||
walk_velocity = 1.05,
|
||||
run_velocity = 2.1,
|
||||
runaway_from = { "mobs_mc:ocelot", "mobs_mc:cat" },
|
||||
attack_type = "explode",
|
||||
|
||||
explosion_strength = 6,
|
||||
explosion_radius = 8,
|
||||
explosion_damage_radius = 8,
|
||||
explosiontimer_reset_radius = 6,
|
||||
reach = 3,
|
||||
explosion_timer = 1.5,
|
||||
allow_fuse_reset = true,
|
||||
stop_to_explode = true,
|
||||
|
||||
-- Force-ignite creeper with flint and steel and explode after 1.5 seconds.
|
||||
-- TODO: Make creeper flash after doing this as well.
|
||||
-- TODO: Test and debug this code.
|
||||
on_rightclick = function(self, clicker)
|
||||
if self._forced_explosion_countdown_timer ~= nil then
|
||||
return
|
||||
end
|
||||
local item = clicker:get_wielded_item()
|
||||
if item:get_name() == "mcl_fire:flint_and_steel" then
|
||||
if not minetest.is_creative_enabled(clicker:get_player_name()) then
|
||||
-- Wear tool
|
||||
local wdef = item:get_definition()
|
||||
item:add_wear(1000)
|
||||
-- Tool break sound
|
||||
if item:get_count() == 0 and wdef.sound and wdef.sound.breaks then
|
||||
minetest.sound_play(wdef.sound.breaks, {pos = clicker:get_pos(), gain = 0.5}, true)
|
||||
end
|
||||
clicker:set_wielded_item(item)
|
||||
end
|
||||
self._forced_explosion_countdown_timer = self.explosion_timer
|
||||
minetest.sound_play(self.sounds.attack, {pos = self.object:get_pos(), gain = 1, max_hear_distance = 16}, true)
|
||||
end
|
||||
end,
|
||||
do_custom = function(self, dtime)
|
||||
if self._forced_explosion_countdown_timer ~= nil then
|
||||
self._forced_explosion_countdown_timer = self._forced_explosion_countdown_timer - dtime
|
||||
if self._forced_explosion_countdown_timer <= 0 then
|
||||
mcl_mobs:boom(self, mcl_util.get_object_center(self.object), self.explosion_strength)
|
||||
end
|
||||
end
|
||||
end,
|
||||
on_die = function(self, pos, cmi_cause)
|
||||
-- Drop a random music disc when killed by skeleton or stray
|
||||
if cmi_cause and cmi_cause.type == "punch" then
|
||||
local luaentity = cmi_cause.puncher and cmi_cause.puncher:get_luaentity()
|
||||
if luaentity and luaentity.name:find("arrow") then
|
||||
local shooter_luaentity = luaentity._shooter and luaentity._shooter:get_luaentity()
|
||||
if shooter_luaentity and (shooter_luaentity.name == "mobs_mc:skeleton" or shooter_luaentity.name == "mobs_mc:stray") then
|
||||
minetest.add_item({x=pos.x, y=pos.y+1, z=pos.z}, "mcl_jukebox:record_" .. math.random(9))
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
maxdrops = 2,
|
||||
drops = {
|
||||
{name = "mcl_mobitems:gunpowder",
|
||||
chance = 1,
|
||||
min = 0,
|
||||
max = 2,
|
||||
looting = "common",},
|
||||
|
||||
-- Head
|
||||
-- TODO: Only drop if killed by charged creeper
|
||||
{name = "mcl_heads:creeper",
|
||||
chance = 200, -- 0.5%
|
||||
min = 1,
|
||||
max = 1,},
|
||||
},
|
||||
animation = {
|
||||
speed_normal = 24,
|
||||
speed_run = 48,
|
||||
stand_start = 0,
|
||||
stand_end = 23,
|
||||
walk_start = 24,
|
||||
walk_end = 49,
|
||||
run_start = 24,
|
||||
run_end = 49,
|
||||
hurt_start = 110,
|
||||
hurt_end = 139,
|
||||
death_start = 140,
|
||||
death_end = 189,
|
||||
look_start = 50,
|
||||
look_end = 108,
|
||||
},
|
||||
floats = 1,
|
||||
fear_height = 4,
|
||||
view_range = 16,
|
||||
--Having trouble when fire is placed with lightning
|
||||
fire_resistant = true,
|
||||
glow = 3,
|
||||
})
|
||||
|
||||
mcl_mobs:spawn_specific(
|
||||
"mobs_mc:creeper",
|
||||
"overworld",
|
||||
"ground",
|
||||
{
|
||||
"Mesa",
|
||||
"FlowerForest",
|
||||
"Swampland",
|
||||
"Taiga",
|
||||
"ExtremeHills",
|
||||
"Jungle",
|
||||
"Savanna",
|
||||
"BirchForest",
|
||||
"MegaSpruceTaiga",
|
||||
"MegaTaiga",
|
||||
"ExtremeHills+",
|
||||
"Forest",
|
||||
"Plains",
|
||||
"Desert",
|
||||
"ColdTaiga",
|
||||
"IcePlainsSpikes",
|
||||
"SunflowerPlains",
|
||||
"IcePlains",
|
||||
"RoofedForest",
|
||||
"ExtremeHills+_snowtop",
|
||||
"MesaPlateauFM_grasstop",
|
||||
"JungleEdgeM",
|
||||
"ExtremeHillsM",
|
||||
"JungleM",
|
||||
"BirchForestM",
|
||||
"MesaPlateauF",
|
||||
"MesaPlateauFM",
|
||||
"MesaPlateauF_grasstop",
|
||||
"MesaBryce",
|
||||
"JungleEdge",
|
||||
"SavannaM",
|
||||
"FlowerForest_beach",
|
||||
"Forest_beach",
|
||||
"StoneBeach",
|
||||
"ColdTaiga_beach_water",
|
||||
"Taiga_beach",
|
||||
"Savanna_beach",
|
||||
"Plains_beach",
|
||||
"ExtremeHills_beach",
|
||||
"ColdTaiga_beach",
|
||||
"Swampland_shore",
|
||||
"JungleM_shore",
|
||||
"Jungle_shore",
|
||||
"MesaPlateauFM_sandlevel",
|
||||
"MesaPlateauF_sandlevel",
|
||||
"MesaBryce_sandlevel",
|
||||
"Mesa_sandlevel",
|
||||
"RoofedForest_ocean",
|
||||
"JungleEdgeM_ocean",
|
||||
"BirchForestM_ocean",
|
||||
"BirchForest_ocean",
|
||||
"IcePlains_deep_ocean",
|
||||
"Jungle_deep_ocean",
|
||||
"Savanna_ocean",
|
||||
"MesaPlateauF_ocean",
|
||||
"ExtremeHillsM_deep_ocean",
|
||||
"Savanna_deep_ocean",
|
||||
"SunflowerPlains_ocean",
|
||||
"Swampland_deep_ocean",
|
||||
"Swampland_ocean",
|
||||
"MegaSpruceTaiga_deep_ocean",
|
||||
"ExtremeHillsM_ocean",
|
||||
"JungleEdgeM_deep_ocean",
|
||||
"SunflowerPlains_deep_ocean",
|
||||
"BirchForest_deep_ocean",
|
||||
"IcePlainsSpikes_ocean",
|
||||
"Mesa_ocean",
|
||||
"StoneBeach_ocean",
|
||||
"Plains_deep_ocean",
|
||||
"JungleEdge_deep_ocean",
|
||||
"SavannaM_deep_ocean",
|
||||
"Desert_deep_ocean",
|
||||
"Mesa_deep_ocean",
|
||||
"ColdTaiga_deep_ocean",
|
||||
"Plains_ocean",
|
||||
"MesaPlateauFM_ocean",
|
||||
"Forest_deep_ocean",
|
||||
"JungleM_deep_ocean",
|
||||
"FlowerForest_deep_ocean",
|
||||
"MegaTaiga_ocean",
|
||||
"StoneBeach_deep_ocean",
|
||||
"IcePlainsSpikes_deep_ocean",
|
||||
"ColdTaiga_ocean",
|
||||
"SavannaM_ocean",
|
||||
"MesaPlateauF_deep_ocean",
|
||||
"MesaBryce_deep_ocean",
|
||||
"ExtremeHills+_deep_ocean",
|
||||
"ExtremeHills_ocean",
|
||||
"Forest_ocean",
|
||||
"MegaTaiga_deep_ocean",
|
||||
"JungleEdge_ocean",
|
||||
"MesaBryce_ocean",
|
||||
"MegaSpruceTaiga_ocean",
|
||||
"ExtremeHills+_ocean",
|
||||
"Jungle_ocean",
|
||||
"RoofedForest_deep_ocean",
|
||||
"IcePlains_ocean",
|
||||
"FlowerForest_ocean",
|
||||
"ExtremeHills_deep_ocean",
|
||||
"MesaPlateauFM_deep_ocean",
|
||||
"Desert_ocean",
|
||||
"Taiga_ocean",
|
||||
"BirchForestM_deep_ocean",
|
||||
"Taiga_deep_ocean",
|
||||
"JungleM_ocean",
|
||||
"FlowerForest_underground",
|
||||
"JungleEdge_underground",
|
||||
"StoneBeach_underground",
|
||||
"MesaBryce_underground",
|
||||
"Mesa_underground",
|
||||
"RoofedForest_underground",
|
||||
"Jungle_underground",
|
||||
"Swampland_underground",
|
||||
"BirchForest_underground",
|
||||
"Plains_underground",
|
||||
"MesaPlateauF_underground",
|
||||
"ExtremeHills_underground",
|
||||
"MegaSpruceTaiga_underground",
|
||||
"BirchForestM_underground",
|
||||
"SavannaM_underground",
|
||||
"MesaPlateauFM_underground",
|
||||
"Desert_underground",
|
||||
"Savanna_underground",
|
||||
"Forest_underground",
|
||||
"SunflowerPlains_underground",
|
||||
"ColdTaiga_underground",
|
||||
"IcePlains_underground",
|
||||
"IcePlainsSpikes_underground",
|
||||
"MegaTaiga_underground",
|
||||
"Taiga_underground",
|
||||
"ExtremeHills+_underground",
|
||||
"JungleM_underground",
|
||||
"ExtremeHillsM_underground",
|
||||
"JungleEdgeM_underground",
|
||||
},
|
||||
0,
|
||||
7,
|
||||
20,
|
||||
16500,
|
||||
2,
|
||||
mcl_vars.mg_overworld_min,
|
||||
mcl_vars.mg_overworld_max)
|
||||
|
||||
-- spawn eggs
|
||||
mcl_mobs:register_egg("mobs_mc:creeper", S("Creeper"), "#0da70a", "#000000", 0)
|
BIN
mods/ENTITIES/mobs_mc/sounds/mobs_mc_creeper_hurt.ogg
Normal file
317
mods/ENVIRONMENT/mcl_weather/rain.lua
Normal file
|
@ -0,0 +1,317 @@
|
|||
local PARTICLES_COUNT_RAIN = tonumber(minetest.settings:get("mcl_weather_rain_particles")) or 500
|
||||
local PARTICLES_COUNT_THUNDER = tonumber(minetest.settings:get("mcl_weather_thunder_particles")) or 900
|
||||
|
||||
local get_connected_players = minetest.get_connected_players
|
||||
local mgname = minetest.get_mapgen_setting("mg_name")
|
||||
|
||||
mcl_weather.rain = {
|
||||
-- max rain particles created at time
|
||||
particles_count = PARTICLES_COUNT_RAIN,
|
||||
|
||||
-- flag to turn on/off extinguish fire for rain
|
||||
extinguish_fire = true,
|
||||
|
||||
-- flag useful when mixing weathers
|
||||
raining = false,
|
||||
|
||||
-- keeping last timeofday value (rounded).
|
||||
-- Defaulted to non-existing value for initial comparing.
|
||||
sky_last_update = -1,
|
||||
|
||||
init_done = false,
|
||||
}
|
||||
local update_sound={}
|
||||
|
||||
local psdef= {
|
||||
amount = mcl_weather.rain.particles_count,
|
||||
time=0,
|
||||
minpos = vector.new(-15,20,-15),
|
||||
maxpos = vector.new(15,25,15),
|
||||
minvel = vector.new(-2,-17,-2),
|
||||
maxvel = vector.new(2,-8,2),
|
||||
minacc = vector.new(0,0,0),
|
||||
maxacc = vector.new(0,-0.5,0),
|
||||
minexptime = 1,
|
||||
maxexptime = 4,
|
||||
minsize = 4,
|
||||
maxsize= 8,
|
||||
collisiondetection = true,
|
||||
collision_removal = true,
|
||||
vertical = true,
|
||||
}
|
||||
|
||||
local textures = {"weather_pack_rain_raindrop_1.png", "weather_pack_rain_raindrop_2.png"}
|
||||
|
||||
function mcl_weather.has_rain(pos)
|
||||
if not mcl_worlds.has_weather(pos) then return false end
|
||||
if mgname == "singlenode" or mgname == "v6" then return true end
|
||||
local bd = minetest.registered_biomes[minetest.get_biome_name(minetest.get_biome_data(pos).biome)]
|
||||
if bd and bd._mcl_biome_type == "hot" then return false end
|
||||
return true
|
||||
end
|
||||
|
||||
function mcl_weather.rain.sound_handler(player, fade)
|
||||
local fadeSpeed = 0
|
||||
if fade then
|
||||
fadeSpeed = 0.5
|
||||
end
|
||||
local player_meta = mcl_weather.players[player:get_player_name()]
|
||||
if mcl_weather.is_outdoor(player:get_pos()) then
|
||||
player_meta.outdoor = true
|
||||
return minetest.sound_play("weather_rain", {
|
||||
to_player = player:get_player_name(),
|
||||
loop = true,
|
||||
fade = fadeSpeed
|
||||
})
|
||||
else
|
||||
player_meta.outdoor = false
|
||||
return minetest.sound_play("weather_rain_damp", {
|
||||
to_player = player:get_player_name(),
|
||||
loop = true,
|
||||
fade = fadeSpeed
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
-- set skybox based on time (uses skycolor api)
|
||||
function mcl_weather.rain.set_sky_box()
|
||||
if mcl_weather.state == "rain" then
|
||||
mcl_weather.skycolor.add_layer(
|
||||
"weather-pack-rain-sky",
|
||||
{{r=0, g=0, b=0},
|
||||
{r=85, g=86, b=98},
|
||||
{r=135, g=135, b=151},
|
||||
{r=85, g=86, b=98},
|
||||
{r=0, g=0, b=0}})
|
||||
mcl_weather.skycolor.active = true
|
||||
for _, player in pairs(get_connected_players()) do
|
||||
player:set_clouds({color="#5D5D5FE8"})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- no no no NO NO f*.. no. no manual particle creatin' PLS!! this sends EVERY particle over the net.
|
||||
function mcl_weather.rain.add_rain_particles(player)
|
||||
mcl_weather.rain.last_rp_count = mcl_weather.rain.particles_count
|
||||
local l = false
|
||||
for k,v in pairs(textures) do
|
||||
psdef.texture=v
|
||||
l = l or mcl_weather.add_spawner_player(player,"rain"..k,psdef)
|
||||
end
|
||||
if l then
|
||||
update_sound[player:get_player_name()]=true
|
||||
end
|
||||
end
|
||||
|
||||
-- register player for rain weather.
|
||||
-- basically needs for origin sky reference and rain sound controls.
|
||||
function mcl_weather.rain.add_player(player)
|
||||
if mcl_weather.players[player:get_player_name()] == nil then
|
||||
local player_meta = {}
|
||||
player_meta.origin_sky = {player:get_sky(true)}
|
||||
mcl_weather.players[player:get_player_name()] = player_meta
|
||||
update_sound[player:get_player_name()]=true
|
||||
end
|
||||
end
|
||||
|
||||
-- remove player from player list effected by rain.
|
||||
-- be sure to remove sound before removing player otherwise soundhandler reference will be lost.
|
||||
function mcl_weather.rain.remove_player(player)
|
||||
local player_meta = mcl_weather.players[player:get_player_name()]
|
||||
if player_meta and player_meta.origin_sky then
|
||||
player:set_clouds({color="#FFF0F0E5"})
|
||||
mcl_weather.players[player:get_player_name()] = nil
|
||||
update_sound[player:get_player_name()]=true
|
||||
end
|
||||
end
|
||||
|
||||
-- adds and removes rain sound depending how much rain particles around player currently exist.
|
||||
-- have few seconds delay before each check to avoid on/off sound too often
|
||||
-- when player stay on 'edge' where sound should play and stop depending from random raindrop appearance.
|
||||
function mcl_weather.rain.update_sound(player)
|
||||
if not update_sound[player:get_player_name()] then return end
|
||||
local player_meta = mcl_weather.players[player:get_player_name()]
|
||||
if player_meta then
|
||||
|
||||
if player_meta.outdoor ~= mcl_weather.is_outdoor(player:get_pos()) then
|
||||
mcl_weather.rain.remove_sound(player)
|
||||
player_meta.sound_handler = mcl_weather.rain.sound_handler(player)
|
||||
end
|
||||
|
||||
if player_meta.sound_updated and player_meta.sound_updated + 5 > minetest.get_gametime() then
|
||||
return false
|
||||
end
|
||||
|
||||
local isInaudible = not mcl_weather.is_outdoor(player:get_pos()) and player:get_pos().y < -10
|
||||
|
||||
if player_meta.sound_handler then
|
||||
if mcl_weather.rain.last_rp_count == 0 or isInaudible then
|
||||
minetest.sound_fade(player_meta.sound_handler, -0.5, 0.0)
|
||||
player_meta.sound_handler = nil
|
||||
end
|
||||
elseif mcl_weather.rain.last_rp_count > 0 and not isInaudible then
|
||||
player_meta.sound_handler = mcl_weather.rain.sound_handler(player, true)
|
||||
end
|
||||
|
||||
player_meta.sound_updated = minetest.get_gametime()
|
||||
end
|
||||
update_sound[player:get_player_name()]=false
|
||||
end
|
||||
|
||||
-- rain sound removed from player.
|
||||
function mcl_weather.rain.remove_sound(player)
|
||||
local player_meta = mcl_weather.players[player:get_player_name()]
|
||||
if player_meta and player_meta.sound_handler then
|
||||
minetest.sound_fade(player_meta.sound_handler, -0.5, 0.0)
|
||||
player_meta.sound_handler = nil
|
||||
player_meta.sound_updated = nil
|
||||
player_meta.outdoor = nil
|
||||
end
|
||||
end
|
||||
|
||||
-- callback function for removing rain
|
||||
function mcl_weather.rain.clear()
|
||||
mcl_weather.rain.raining = false
|
||||
mcl_weather.rain.sky_last_update = -1
|
||||
mcl_weather.rain.init_done = false
|
||||
mcl_weather.rain.set_particles_mode("rain")
|
||||
mcl_weather.skycolor.remove_layer("weather-pack-rain-sky")
|
||||
for _, player in pairs(get_connected_players()) do
|
||||
mcl_weather.rain.remove_sound(player)
|
||||
mcl_weather.rain.remove_player(player)
|
||||
mcl_weather.remove_spawners_player(player)
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_globalstep(function(dtime)
|
||||
if mcl_weather.state ~= "rain" then
|
||||
return false
|
||||
end
|
||||
mcl_weather.rain.make_weather()
|
||||
end)
|
||||
|
||||
function mcl_weather.rain.make_weather()
|
||||
if mcl_weather.rain.init_done == false then
|
||||
mcl_weather.rain.raining = true
|
||||
mcl_weather.rain.set_sky_box()
|
||||
mcl_weather.rain.set_particles_mode(mcl_weather.mode)
|
||||
mcl_weather.rain.init_done = true
|
||||
end
|
||||
|
||||
for _, player in pairs(get_connected_players()) do
|
||||
local pos=player:get_pos()
|
||||
if mcl_weather.is_underwater(player) or not mcl_weather.has_rain(pos) then
|
||||
mcl_weather.rain.remove_sound(player)
|
||||
mcl_weather.remove_spawners_player(player)
|
||||
if mcl_worlds.has_weather(pos) then
|
||||
mcl_weather.set_sky_box_clear(player)
|
||||
end
|
||||
else
|
||||
if mcl_weather.has_snow(pos) then
|
||||
mcl_weather.rain.remove_sound(player)
|
||||
mcl_weather.snow.add_player(player)
|
||||
mcl_weather.snow.set_sky_box()
|
||||
else
|
||||
mcl_weather.rain.add_player(player)
|
||||
mcl_weather.rain.add_rain_particles(player)
|
||||
mcl_weather.rain.update_sound(player)
|
||||
mcl_weather.rain.set_sky_box()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Switch the number of raindrops: "thunder" for many raindrops, otherwise for normal raindrops
|
||||
function mcl_weather.rain.set_particles_mode(mode)
|
||||
if mode == "thunder" then
|
||||
psdef.amount=PARTICLES_COUNT_THUNDER
|
||||
mcl_weather.rain.particles_count = PARTICLES_COUNT_THUNDER
|
||||
else
|
||||
psdef.amount=PARTICLES_COUNT_RAIN
|
||||
mcl_weather.rain.particles_count = PARTICLES_COUNT_RAIN
|
||||
end
|
||||
end
|
||||
|
||||
if mcl_weather.allow_abm then
|
||||
-- ABM for extinguish fire
|
||||
minetest.register_abm({
|
||||
label = "Rain extinguishes fire",
|
||||
nodenames = {"mcl_fire:fire"},
|
||||
interval = 2.0,
|
||||
chance = 2,
|
||||
action = function(pos, node, active_object_count, active_object_count_wider)
|
||||
-- Fire is extinguished if in rain or one of 4 neighbors is in rain
|
||||
if mcl_weather.rain.raining and mcl_weather.rain.extinguish_fire then
|
||||
local around = {
|
||||
{ x = 0, y = 0, z = 0 },
|
||||
{ x = -1, y = 0, z = 0 },
|
||||
{ x = 1, y = 0, z = 0 },
|
||||
{ x = 0, y = 0, z = -1 },
|
||||
{ x = 0, y = 0, z = 1 },
|
||||
}
|
||||
for a=1, #around do
|
||||
local apos = vector.add(pos, around[a])
|
||||
if mcl_weather.is_outdoor(apos) then
|
||||
minetest.remove_node(pos)
|
||||
minetest.sound_play("fire_extinguish_flame", {pos = pos, max_hear_distance = 8, gain = 0.1}, true)
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
-- Slowly fill up cauldrons
|
||||
minetest.register_abm({
|
||||
label = "Rain fills cauldrons with water",
|
||||
nodenames = {"mcl_cauldrons:cauldron", "mcl_cauldrons:cauldron_1", "mcl_cauldrons:cauldron_2"},
|
||||
interval = 56.0,
|
||||
chance = 1,
|
||||
action = function(pos, node, active_object_count, active_object_count_wider)
|
||||
-- Rain is equivalent to a water bottle
|
||||
if mcl_weather.rain.raining and mcl_weather.is_outdoor(pos) then
|
||||
if node.name == "mcl_cauldrons:cauldron" then
|
||||
minetest.set_node(pos, {name="mcl_cauldrons:cauldron_1"})
|
||||
elseif node.name == "mcl_cauldrons:cauldron_1" then
|
||||
minetest.set_node(pos, {name="mcl_cauldrons:cauldron_2"})
|
||||
elseif node.name == "mcl_cauldrons:cauldron_2" then
|
||||
minetest.set_node(pos, {name="mcl_cauldrons:cauldron_3"})
|
||||
elseif node.name == "mcl_cauldrons:cauldron_1r" then
|
||||
minetest.set_node(pos, {name="mcl_cauldrons:cauldron_2r"})
|
||||
elseif node.name == "mcl_cauldrons:cauldron_2r" then
|
||||
minetest.set_node(pos, {name="mcl_cauldrons:cauldron_3r"})
|
||||
end
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
-- Wetten the soil
|
||||
minetest.register_abm({
|
||||
label = "Rain hydrates farmland",
|
||||
nodenames = {"mcl_farming:soil"},
|
||||
interval = 22.0,
|
||||
chance = 3,
|
||||
action = function(pos, node, active_object_count, active_object_count_wider)
|
||||
if mcl_weather.rain.raining and mcl_weather.is_outdoor(pos) then
|
||||
if node.name == "mcl_farming:soil" then
|
||||
minetest.set_node(pos, {name="mcl_farming:soil_wet"})
|
||||
end
|
||||
end
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
if mcl_weather.reg_weathers.rain == nil then
|
||||
mcl_weather.reg_weathers.rain = {
|
||||
clear = mcl_weather.rain.clear,
|
||||
light_factor = 0.6,
|
||||
-- 10min - 20min
|
||||
min_duration = 600,
|
||||
max_duration = 1200,
|
||||
transitions = {
|
||||
[65] = "none",
|
||||
[70] = "snow",
|
||||
[100] = "thunder",
|
||||
}
|
||||
}
|
||||
end
|
BIN
mods/ENVIRONMENT/mcl_weather/sounds/weather_rain_damp.ogg
Normal file
60
mods/ITEMS/mcl_colorbricks/init.lua
Normal file
|
@ -0,0 +1,60 @@
|
|||
local S = minetest.get_translator(minetest.get_current_modname())
|
||||
local mod_doc = minetest.get_modpath("doc")
|
||||
|
||||
local brick = {}
|
||||
-- This uses a trick: you can first define the recipes using all of the base
|
||||
-- colors, and then some recipes using more specific colors for a few non-base
|
||||
-- colors available. When crafting, the last recipes will be checked first.
|
||||
brick.dyes = {
|
||||
-- name, texture, colorbrick desc., dye, color_group
|
||||
{"white", "mcl_colorbricks_white", "White Brick", "white", "unicolor_white"},
|
||||
{"grey", "mcl_colorbricks_dark_grey", "Grey Brick", "dark_grey", "unicolor_darkgrey"},
|
||||
{"silver", "mcl_colorbricks_grey", "Light Grey Brick", "grey", "unicolor_grey"},
|
||||
{"black", "mcl_colorbricks_black", "Black Brick", "black", "unicolor_black"},
|
||||
{"yellow", "mcl_colorbricks_yellow", "Yellow Brick", "yellow", "unicolor_yellow"},
|
||||
{"green", "mcl_colorbricks_dark_green", "Green Brick", "dark_green", "unicolor_dark_green"},
|
||||
{"cyan", "mcl_colorbricks_cyan", "Cyan Brick", "cyan", "unicolor_cyan"},
|
||||
{"blue", "mcl_colorbricks_blue", "Blue Brick", "blue", "unicolor_blue"},
|
||||
{"magenta", "mcl_colorbricks_magenta", "Magenta Brick", "magenta", "unicolor_red_violet"},
|
||||
{"orange", "mcl_colorbricks_orange", "Orange Brick", "orange", "unicolor_orange"},
|
||||
{"purple", "mcl_colorbricks_violet", "Purple Brick", "violet", "unicolor_violet"},
|
||||
{"brown", "mcl_colorbricks_brown", "Brown Brick", "brown", "unicolor_dark_orange"},
|
||||
{"pink", "mcl_colorbricks_pink", "Pink Brick", "pink", "unicolor_light_red"},
|
||||
{"lime", "mcl_colorbricks_lime", "Lime Brick", "green", "unicolor_green"},
|
||||
{"light_blue", "mcl_colorbricks_light_blue", "Light Blue Brick", "lightblue", "unicolor_light_blue"},
|
||||
}
|
||||
|
||||
for _, row in ipairs(brick.dyes) do
|
||||
local name = row[1]
|
||||
local texture = row[2]
|
||||
local desc_brick = row[3]
|
||||
local dye = row[4]
|
||||
local color_group = row[5]
|
||||
|
||||
-- Node Definition
|
||||
minetest.register_node("mcl_colorbricks:colorbrick_"..name, {
|
||||
description = S(desc_brick),
|
||||
stack_max = 64,
|
||||
is_ground_content = false,
|
||||
tiles = {texture..".png"},
|
||||
groups = {pickaxey=1, building_block=1, material_stone=1, [color_group]=1},
|
||||
sounds = mcl_sounds.node_sound_stone_defaults(),
|
||||
_mcl_blast_resistance = 6,
|
||||
_mcl_hardness = 2,
|
||||
})
|
||||
|
||||
if mod_doc and not is_canonical then
|
||||
doc.add_entry_alias("nodes", "mcl_core:brick_block", "nodes", "mcl_colorbricks:colorbrick_"..name)
|
||||
end
|
||||
|
||||
mcl_stairs.register_stair_and_slab_simple("colorbrick_"..name, "mcl_colorbricks:colorbrick_"..name, S(desc_brick.." Stairs"), S(desc_brick.." Slab"), S("Double "..desc_brick.." Slab"))
|
||||
|
||||
if dye then
|
||||
-- Crafting from dye and white wool
|
||||
minetest.register_craft({
|
||||
type = "shapeless",
|
||||
output = "mcl_colorbricks:colorbrick_"..name,
|
||||
recipe = {"mcl_dye:"..dye, "mcl_core:brick_block"},
|
||||
})
|
||||
end
|
||||
end
|
3
mods/ITEMS/mcl_colorbricks/mod.conf
Normal file
|
@ -0,0 +1,3 @@
|
|||
name = mcl_colorbricks
|
||||
depends = mcl_colors, mcl_stairs, mclx_stairs
|
||||
optional_depends = mcl_sounds, mcl_core, doc, mcl_dye
|
BIN
mods/ITEMS/mcl_colorbricks/textures/mcl_colorbricks_black.png
Normal file
After Width: | Height: | Size: 5.2 KiB |
BIN
mods/ITEMS/mcl_colorbricks/textures/mcl_colorbricks_blue.png
Normal file
After Width: | Height: | Size: 5.5 KiB |
BIN
mods/ITEMS/mcl_colorbricks/textures/mcl_colorbricks_brown.png
Normal file
After Width: | Height: | Size: 5.4 KiB |
BIN
mods/ITEMS/mcl_colorbricks/textures/mcl_colorbricks_cyan.png
Normal file
After Width: | Height: | Size: 5.5 KiB |
After Width: | Height: | Size: 5.4 KiB |
After Width: | Height: | Size: 5.2 KiB |
BIN
mods/ITEMS/mcl_colorbricks/textures/mcl_colorbricks_grey.png
Normal file
After Width: | Height: | Size: 5.3 KiB |
After Width: | Height: | Size: 5.5 KiB |
BIN
mods/ITEMS/mcl_colorbricks/textures/mcl_colorbricks_lime.png
Normal file
After Width: | Height: | Size: 5.5 KiB |
BIN
mods/ITEMS/mcl_colorbricks/textures/mcl_colorbricks_magenta.png
Normal file
After Width: | Height: | Size: 5.5 KiB |
BIN
mods/ITEMS/mcl_colorbricks/textures/mcl_colorbricks_orange.png
Normal file
After Width: | Height: | Size: 5.6 KiB |
BIN
mods/ITEMS/mcl_colorbricks/textures/mcl_colorbricks_pink.png
Normal file
After Width: | Height: | Size: 5.5 KiB |
BIN
mods/ITEMS/mcl_colorbricks/textures/mcl_colorbricks_violet.png
Normal file
After Width: | Height: | Size: 5.5 KiB |
BIN
mods/ITEMS/mcl_colorbricks/textures/mcl_colorbricks_white.png
Normal file
After Width: | Height: | Size: 5.2 KiB |
BIN
mods/ITEMS/mcl_colorbricks/textures/mcl_colorbricks_yellow.png
Normal file
After Width: | Height: | Size: 5.5 KiB |
3
mods/ITEMS/mcl_prideflags/README.txt
Normal file
|
@ -0,0 +1,3 @@
|
|||
License of code: WTFPL
|
||||
|
||||
License of textures: See README.md in top directory of MineClone 2.
|
198
mods/ITEMS/mcl_prideflags/init.lua
Normal file
|
@ -0,0 +1,198 @@
|
|||
local modname = minetest.get_current_modname()
|
||||
local modpath = minetest.get_modpath(modname)
|
||||
local S = minetest.get_translator(modname)
|
||||
local N = function(s) return s end
|
||||
|
||||
local mod_mcl_core = minetest.get_modpath("mcl_core")
|
||||
local mod_mcl_banners = minetest.get_modpath("mcl_banners")
|
||||
local mod_mcl_dye = minetest.get_modpath("mcl_wool")
|
||||
local mod_mcl_dye = minetest.get_modpath("mcl_dye")
|
||||
local mod_doc = minetest.get_modpath("doc")
|
||||
|
||||
local standing_banner_entity_offset = { x=0, y=-0.499, z=0 }
|
||||
local hanging_banner_entity_offset = { x=0, y=-1.7, z=0 }
|
||||
|
||||
local inv
|
||||
local base
|
||||
local finished_banner
|
||||
|
||||
base = "mcl_banners_item_base.png^mcl_prideflags_item_overlay.png^[resize:32x32"
|
||||
finished_banner = base
|
||||
|
||||
inv = finished_banner
|
||||
groups = { banner = 1, deco_block = 1, flammable = -1 }
|
||||
|
||||
-- Helper function
|
||||
local function round(num, idp)
|
||||
local mult = 10^(idp or 0)
|
||||
return math.floor(num * mult + 0.5) / mult
|
||||
end
|
||||
|
||||
local function rotation_level_to_yaw(rotation_level)
|
||||
return (rotation_level * (math.pi/8)) + math.pi
|
||||
end
|
||||
|
||||
local function spawn_banner_entity(pos, hanging, itemstack)
|
||||
local banner
|
||||
if hanging then
|
||||
banner = minetest.add_entity(pos, "mcl_banners:hanging_banner")
|
||||
else
|
||||
banner = minetest.add_entity(pos, "mcl_banners:standing_banner")
|
||||
end
|
||||
if banner == nil then
|
||||
return banner
|
||||
end
|
||||
local imeta = itemstack:get_meta()
|
||||
local layers = ""
|
||||
local colorid = ""
|
||||
banner:set_properties({textures = {"mcl_prideflags_base.png"}})
|
||||
local mname = imeta:get_string("name")
|
||||
if mname and mname ~= "" then
|
||||
banner:get_luaentity()._item_name = mname
|
||||
banner:get_luaentity()._item_description = imeta:get_string("description")
|
||||
end
|
||||
|
||||
return banner
|
||||
end
|
||||
|
||||
minetest.register_lbm({
|
||||
label = "Respawn banner entities",
|
||||
name = "mcl_prideflags:respawn_entities",
|
||||
run_at_every_load = true,
|
||||
nodenames = {"mcl_banners:standing_banner", "mcl_banners:hanging_banner"},
|
||||
action = function(pos, node)
|
||||
|
||||
local hanging = node.name == "mcl_banners:hanging_banner"
|
||||
local offset
|
||||
if hanging then
|
||||
offset = hanging_banner_entity_offset
|
||||
else
|
||||
offset = standing_banner_entity_offset
|
||||
end
|
||||
|
||||
local bpos = vector.add(pos, offset)
|
||||
local objects = minetest.get_objects_inside_radius(bpos, 0.5)
|
||||
|
||||
for _, v in ipairs(objects) do
|
||||
local ent = v:get_luaentity()
|
||||
if ent and (ent.name == "mcl_banners:standing_banner" or ent.name == "mcl_banners:hanging_banner") then
|
||||
local meta = minetest.get_meta(pos)
|
||||
if meta:get_int("pride") == 1 then
|
||||
v:set_properties({textures = {"mcl_prideflags_base.png"}})
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_craftitem("mcl_prideflags:pride_flag", {
|
||||
description = S("Pride Flag"),
|
||||
_tt_help = S("Pride Flag decoration"),
|
||||
_doc_items_create_entry = false,
|
||||
inventory_image = inv,
|
||||
wield_image = inv,
|
||||
-- Banner group groups together the banner items, but not the nodes.
|
||||
-- Used for crafting.
|
||||
groups = groups,
|
||||
stack_max = 16,
|
||||
|
||||
on_place = function(itemstack, placer, pointed_thing)
|
||||
local above = pointed_thing.above
|
||||
local under = pointed_thing.under
|
||||
|
||||
local node_under = minetest.get_node(under)
|
||||
if placer and not placer:get_player_control().sneak then
|
||||
-- Use pointed node's on_rightclick function first, if present
|
||||
if minetest.registered_nodes[node_under.name] and minetest.registered_nodes[node_under.name].on_rightclick then
|
||||
return minetest.registered_nodes[node_under.name].on_rightclick(under, node_under, placer, itemstack) or itemstack
|
||||
end
|
||||
end
|
||||
|
||||
-- Place the node!
|
||||
local hanging = false
|
||||
|
||||
-- Standing or hanging banner. The placement rules are enforced by the node definitions
|
||||
local _, success = minetest.item_place_node(ItemStack("mcl_banners:standing_banner"), placer, pointed_thing)
|
||||
if not success then
|
||||
-- Forbidden on ceiling
|
||||
if pointed_thing.under.y ~= pointed_thing.above.y then
|
||||
return itemstack
|
||||
end
|
||||
_, success = minetest.item_place_node(ItemStack("mcl_banners:hanging_banner"), placer, pointed_thing)
|
||||
if not success then
|
||||
return itemstack
|
||||
end
|
||||
hanging = true
|
||||
end
|
||||
local place_pos
|
||||
if minetest.registered_nodes[node_under.name].buildable_to then
|
||||
place_pos = under
|
||||
else
|
||||
place_pos = above
|
||||
end
|
||||
local bnode = minetest.get_node(place_pos)
|
||||
if bnode.name ~= "mcl_banners:standing_banner" and bnode.name ~= "mcl_banners:hanging_banner" then
|
||||
minetest.log("error", "[mcl_banners] The placed banner node is not what the mod expected!")
|
||||
return itemstack
|
||||
end
|
||||
local meta = minetest.get_meta(place_pos)
|
||||
local inv = meta:get_inventory()
|
||||
inv:set_size("banner", 1)
|
||||
local store_stack = ItemStack(itemstack)
|
||||
store_stack:set_count(1)
|
||||
inv:set_stack("banner", 1, store_stack)
|
||||
|
||||
-- Spawn entity
|
||||
local entity_place_pos
|
||||
if hanging then
|
||||
entity_place_pos = vector.add(place_pos, hanging_banner_entity_offset)
|
||||
else
|
||||
entity_place_pos = vector.add(place_pos, standing_banner_entity_offset)
|
||||
end
|
||||
local banner_entity = spawn_banner_entity(entity_place_pos, hanging, itemstack)
|
||||
-- Set rotation
|
||||
local final_yaw, rotation_level
|
||||
if hanging then
|
||||
local pdir = vector.direction(pointed_thing.under, pointed_thing.above)
|
||||
final_yaw = minetest.dir_to_yaw(pdir)
|
||||
if pdir.x > 0 then
|
||||
rotation_level = 4
|
||||
elseif pdir.z > 0 then
|
||||
rotation_level = 8
|
||||
elseif pdir.x < 0 then
|
||||
rotation_level = 12
|
||||
else
|
||||
rotation_level = 0
|
||||
end
|
||||
else
|
||||
-- Determine the rotation based on player's yaw
|
||||
local yaw = placer:get_look_horizontal()
|
||||
-- Select one of 16 possible rotations (0-15)
|
||||
rotation_level = round((yaw / (math.pi*2)) * 16)
|
||||
if rotation_level >= 16 then
|
||||
rotation_level = 0
|
||||
end
|
||||
final_yaw = rotation_level_to_yaw(rotation_level)
|
||||
end
|
||||
meta:set_int("rotation_level", rotation_level)
|
||||
meta:set_int("pride", 1)
|
||||
|
||||
if banner_entity then
|
||||
banner_entity:set_yaw(final_yaw)
|
||||
end
|
||||
|
||||
if not minetest.is_creative_enabled(placer:get_player_name()) then
|
||||
itemstack:take_item()
|
||||
end
|
||||
minetest.sound_play({name="default_place_node_hard", gain=1.0}, {pos = place_pos}, true)
|
||||
|
||||
return itemstack
|
||||
end,
|
||||
})
|
||||
|
||||
if mod_mcl_core then
|
||||
minetest.register_craft({
|
||||
output = "mcl_prideflags:pride_flag",
|
||||
recipe = { {"mcl_wool:red", "mcl_wool:orange", "mcl_wool:yellow"}, {"mcl_wool:green", "mcl_wool:blue", "mcl_wool:purple"}, {"", "mcl_core:stick", ""} }
|
||||
})
|
||||
end
|
4
mods/ITEMS/mcl_prideflags/mod.conf
Normal file
|
@ -0,0 +1,4 @@
|
|||
name = mcl_prideflags
|
||||
author = NilsG
|
||||
description = Adds decorative pride flags
|
||||
depends = mcl_colors, mcl_banners, mcl_dye, mcl_wool
|
BIN
mods/ITEMS/mcl_prideflags/textures/mcl_prideflags_base.png
Normal file
After Width: | Height: | Size: 6.7 KiB |
After Width: | Height: | Size: 4.9 KiB |