Compare commits

...

4 Commits

26 changed files with 995 additions and 0 deletions

View 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)

Binary file not shown.

View 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

View 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

View File

@ -0,0 +1,3 @@
name = mcl_colorbricks
depends = mcl_colors, mcl_stairs, mclx_stairs
optional_depends = mcl_sounds, mcl_core, doc, mcl_dye

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

View File

@ -0,0 +1,3 @@
License of code: WTFPL
License of textures: See README.md in top directory of MineClone 2.

View 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

View File

@ -0,0 +1,4 @@
name = mcl_prideflags
author = NilsG
description = Adds decorative pride flags
depends = mcl_colors, mcl_banners, mcl_dye, mcl_wool

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB