diff --git a/minetest.conf b/minetest.conf index e122db7b3e..223587f4db 100644 --- a/minetest.conf +++ b/minetest.conf @@ -1,5 +1,8 @@ # This is a game specific minetest.conf file, do not edit +# If any of these settings are set in your minetest.conf file in ~/.minetest (Linux) or in the root directory of the game (Run in place/Windows) +# They will override these settings + # Basic game rules time_speed = 72 @@ -33,7 +36,7 @@ mgvalleys_spflags = noaltitude_chill,noaltitude_dry,nohumid_rivers,vary_river_de keepInventory = false # Performance settings -# dedicated_server_step = 0.001 +dedicated_server_step = 0.05 #tick rate # abm_interval = 0.25 # max_objects_per_block = 4096 # max_packets_per_iteration = 10096 diff --git a/mods/CORE/controls/API.md b/mods/CORE/controls/API.md new file mode 100644 index 0000000000..8d9df6ca50 --- /dev/null +++ b/mods/CORE/controls/API.md @@ -0,0 +1,23 @@ +# controls + +## controls.players +Table containing player controls at runtime. +WARNING: Never use this table in writing + +## controls.register_on_press(func) +Register a function that will be executed with (player, keyname) every time a player press a key. + +## controls.registered_on_press +Table containing functions registered with controls.register_on_press(). + +## controls.register_on_release(func) +Register a function that will be executed with (player, keyname, clock_from_last_press) every time a player release a key. + +## controls.registered_on_release +Table containing functions registered with controls.register_on_release(). + +## controls.register_on_hold(func) +Register a function that will be executed with (player, keyname, clock_from_start_hold) every time a player hold a key. + +## controls.registered_on_hold +Table containing functions registered with controls.register_on_hold(). \ No newline at end of file diff --git a/mods/CORE/flowlib/API.md b/mods/CORE/flowlib/API.md new file mode 100644 index 0000000000..20e85036b9 --- /dev/null +++ b/mods/CORE/flowlib/API.md @@ -0,0 +1,45 @@ +# flowlib +Simple flow functions. + +## flowlib.is_touching(realpos, nodepos, radius) +Return true if a sphere of at collide with node at . +* realpos: position +* nodepos: position +* radius: number + +## flowlib.is_water(pos) +Return true if node at is water, false overwise. +* pos: position + +## flowlib.node_is_water(node) +Return true if is water, false overwise. +* node: node + +## flowlib.is_lava(pos) +Return true if node at is lava, false overwise. +* pos: position + +## flowlib.node_is_lava(node) +Return true if is lava, false overwise. +* node: node + +## flowlib.is_liquid(pos) +Return true if node at is liquid, false overwise. +* pos: position + +## flowlib.node_is_liquid(node) +Return true if is liquid, false overwise. +* node: node + +## flowlib.quick_flow(pos, node) +Return direction where the water is flowing (to be use to push mobs, items...). +* pos: position +* node: node + +## flowlib.move_centre(pos, realpos, node, radius) +Return the pos of the nearest not water block near from in a sphere of at . +WARNING: This function is never used in mcl2, use at your own risk. The informations described here may be wrong. +* pos: position +* realpos: position, position of the entity +* node: node +* radius: number \ No newline at end of file diff --git a/mods/CORE/mcl_autogroup/API.md b/mods/CORE/mcl_autogroup/API.md new file mode 100644 index 0000000000..79b9770b5d --- /dev/null +++ b/mods/CORE/mcl_autogroup/API.md @@ -0,0 +1,27 @@ +# mcl_autogroup +This mod emulate digging times from mc. + +## mcl_autogroup.can_harvest(nodename, toolname) +Return true if can be dig with . +* nodename: string, valid nodename +* toolname: (optional) string, valid toolname + +## mcl_autogroup.get_groupcaps(toolname, efficiency) +This function is used to calculate diggroups for tools. +WARNING: This function can only be called after mod initialization. +* toolname: string, name of the tool being enchanted (like "mcl_tools:diamond_pickaxe") +* efficiency: (optional) integer, the efficiency level the tool is enchanted with (default 0) + +## mcl_autogroup.get_wear(toolname, diggroup) +Return the max wear of with +WARNING: This function can only be called after mod initialization. +* toolname: string, name of the tool used +* diggroup: string, the name of the diggroup the tool is used on + +## mcl_autogroup.register_diggroup(group, def) +* group: string, name of the group to register as a digging group +* def: (optional) table, table with information about the diggroup (defaults to {} if unspecified) + * level: (optional) string, if specified it is an array containing the names of the different digging levels the digging group supports + +## mcl_autogroup.registered_diggroups +List of registered diggroups, indexed by name. \ No newline at end of file diff --git a/mods/CORE/mcl_colors/API.md b/mods/CORE/mcl_colors/API.md new file mode 100644 index 0000000000..71cad335b1 --- /dev/null +++ b/mods/CORE/mcl_colors/API.md @@ -0,0 +1,8 @@ +# mcl_colors +Mod providing global table containing legacity minecraft colors to be used in mods. + +## mcl_colors.* +Colors by upper name, in hex value. + +## mcl_colors.background.* +Background colors by upper name, in hex value. diff --git a/mods/CORE/mcl_explosions/API.md b/mods/CORE/mcl_explosions/API.md new file mode 100644 index 0000000000..cb0e9252d9 --- /dev/null +++ b/mods/CORE/mcl_explosions/API.md @@ -0,0 +1,15 @@ +# mcl_explosions +This mod provide helper functions to create explosions. + +## mcl_explosions.explode(pos, strength, info, puncher) +* pos: position, initial position of the explosion +* strenght: number, radius of the explosion +* info: table, explosion informations: + * drop_chance: number, if specified becomes the drop chance of all nodes in the explosion (default: 1.0 / strength) + * max_blast_resistance: int, if specified the explosion will treat all non-indestructible nodes as having a blast resistance of no more than this value + * sound: bool, if true, the explosion will play a sound (default: true) + * particles: bool, if true, the explosion will create particles (default: true) + * fire: bool, if true, 1/3 nodes become fire (default: false) + * griefing: bool, if true, the explosion will destroy nodes (default: true) + * grief_protected: bool, if true, the explosion will also destroy nodes which have been protected (default: false) +* puncher: (optional) entity, will be used as source for damage done by the explosion \ No newline at end of file diff --git a/mods/CORE/mcl_init/init.lua b/mods/CORE/mcl_init/init.lua index 014a30d1e3..066e555dff 100644 --- a/mods/CORE/mcl_init/init.lua +++ b/mods/CORE/mcl_init/init.lua @@ -21,6 +21,9 @@ mcl_vars.gui_bg_img = "background9[1,1;1,1;mcl_base_textures_background9.png;tru -- Legacy mcl_vars.inventory_header = "" +-- Tool wield size +mcl_vars.tool_wield_scale = { x = 1.8, y = 1.8, z = 1 } + -- Mapgen variables local mg_name = minetest.get_mapgen_setting("mg_name") local minecraft_height_limit = 256 diff --git a/mods/CORE/mcl_util/init.lua b/mods/CORE/mcl_util/init.lua index a43c3d5d0b..ac913de390 100644 --- a/mods/CORE/mcl_util/init.lua +++ b/mods/CORE/mcl_util/init.lua @@ -410,7 +410,7 @@ function mcl_util.get_color(colorstr) local mc_color = mcl_colors[colorstr:upper()] if mc_color then colorstr = mc_color - elseif #colorstr ~= 7 or colorstr:sub(1, 1) ~= "#"then + elseif #colorstr ~= 7 or colorstr:sub(1, 1) ~= "#" then return end local hex = tonumber(colorstr:sub(2, 7), 16) diff --git a/mods/CORE/mcl_worlds/API.md b/mods/CORE/mcl_worlds/API.md new file mode 100644 index 0000000000..a5509431c2 --- /dev/null +++ b/mods/CORE/mcl_worlds/API.md @@ -0,0 +1,80 @@ +# mcl_worlds +This mod provides utility functions about positions and dimensions. + +## mcl_worlds.is_in_void(pos) +This function returns: + +* true, true: if pos is in deep void (deadly) +* true, false: if the pos is in void (non deadly) +* false, false: owerwise + +Params: + +* pos: position + +## mcl_worlds.y_to_layer(y) +This function is used to calculate the minetest y layer and dimension of the given minecraft layer. +Mainly used for ore generation. +Takes an Y coordinate as input and returns: + +* The corresponding Minecraft layer (can be nil if void) +* The corresponding Minecraft dimension ("overworld", "nether" or "end") or "void" if is in the void +If the Y coordinate is not located in any dimension, it will return: nil, "void" + +Params: + +* y: int + +## mcl_worlds.pos_to_dimension(pos) +This function return the Minecraft dimension of ("overworld", "nether" or "end") or "void" if is in the void. + +* pos: position + +## mcl_worlds.layer_to_y(layer, mc_dimension) +Takes a Minecraft layer and a “dimension” name and returns the corresponding Y coordinate for MineClone 2. +mc_dimension can be "overworld", "nether", "end" (default: "overworld"). + +* layer: int +* mc_dimension: string + +## mcl_worlds.has_weather(pos) +Returns true if can have weather, false owerwise. +Weather can be only in the overworld. + +* pos: position + +## mcl_worlds.has_dust(pos) +Returns true if can have nether dust, false owerwise. +Nether dust can be only in the nether. + +* pos: position + +## mcl_worlds.compass_works(pos) +Returns true if compasses are working at , false owerwise. +In mc, you cant use compass in the nether and the end. + +* pos: position + +## mcl_worlds.compass_works(pos) +Returns true if clock are working at , false owerwise. +In mc, you cant use clock in the nether and the end. + +* pos: position + +## mcl_worlds.register_on_dimension_change(function(player, dimension)) +Register a callback function func(player, dimension). +It will be called whenever a player changes between dimensions. +The void counts as dimension. + +* player: player, the player who changed the dimension +* dimension: position, The new dimension of the player ("overworld", "nether", "end", "void"). + + +## mcl_worlds.registered_on_dimension_change +Table containing all function registered with mcl_worlds.register_on_dimension_change() + +## mcl_worlds.dimension_change(player, dimension) +Notify this mod of a dimmension change of to + +* player: player, player who changed the dimension +* dimension: string, new dimension ("overworld", "nether", "end", "void") \ No newline at end of file diff --git a/mods/ENTITIES/mcl_item_entity/init.lua b/mods/ENTITIES/mcl_item_entity/init.lua index 95b90e5467..b65585a158 100644 --- a/mods/ENTITIES/mcl_item_entity/init.lua +++ b/mods/ENTITIES/mcl_item_entity/init.lua @@ -1,14 +1,36 @@ +--these are lua locals, used for higher performance +local minetest,math,vector,ipairs = minetest,math,vector,ipairs + +--this is used for the player pool in the sound buffer +local pool = {} + +local tick = false + +minetest.register_on_joinplayer(function(player) + local name + name = player:get_player_name() + pool[name] = 0 +end) + +minetest.register_on_leaveplayer(function(player) + local name + name = player:get_player_name() + pool[name] = nil +end) + + local has_awards = minetest.get_modpath("awards") -mcl_item_entity = {} +local mcl_item_entity = {} --basic settings local item_drop_settings = {} --settings table +item_drop_settings.dug_buffer = 0.65 -- the warm up period before a dug item can be collected item_drop_settings.age = 1.0 --how old a dropped item (_insta_collect==false) has to be before collecting item_drop_settings.radius_magnet = 2.0 --radius of item magnet. MUST BE LARGER THAN radius_collect! item_drop_settings.xp_radius_magnet = 7.25 --radius of xp magnet. MUST BE LARGER THAN radius_collect! item_drop_settings.radius_collect = 0.2 --radius of collection -item_drop_settings.player_collect_height = 1.0 --added to their pos y value +item_drop_settings.player_collect_height = 0.8 --added to their pos y value item_drop_settings.collection_safety = false --do this to prevent items from flying away on laggy servers item_drop_settings.random_item_velocity = true --this sets random item velocity if velocity is 0 item_drop_settings.drop_single_item = false --if true, the drop control drops 1 item instead of the entire stack, and sneak+drop drops the stack @@ -74,103 +96,71 @@ local disable_physics = function(object, luaentity, ignore_check, reset_movement end end + minetest.register_globalstep(function(dtime) + + tick = not tick + for _,player in pairs(minetest.get_connected_players()) do if player:get_hp() > 0 or not minetest.settings:get_bool("enable_damage") then + + + local name = player:get_player_name() + local pos = player:get_pos() + + if tick == true and pool[name] > 0 then + minetest.sound_play("item_drop_pickup", { + pos = pos, + gain = 0.7, + max_hear_distance = 16, + pitch = math.random(70,110)/100 + }) + if pool[name] > 6 then + pool[name] = 6 + else + pool[name] = pool[name] - 1 + end + end + + + local inv = player:get_inventory() local checkpos = {x=pos.x,y=pos.y + item_drop_settings.player_collect_height,z=pos.z} --magnet and collection for _,object in pairs(minetest.get_objects_inside_radius(checkpos, item_drop_settings.xp_radius_magnet)) do if not object:is_player() and vector.distance(checkpos, object:get_pos()) < item_drop_settings.radius_magnet and object:get_luaentity() and object:get_luaentity().name == "__builtin:item" and object:get_luaentity()._magnet_timer and (object:get_luaentity()._insta_collect or (object:get_luaentity().age > item_drop_settings.age)) then - object:get_luaentity()._magnet_timer = object:get_luaentity()._magnet_timer + dtime - local collected = false + if object:get_luaentity()._magnet_timer >= 0 and object:get_luaentity()._magnet_timer < item_drop_settings.magnet_time and inv and inv:room_for_item("main", ItemStack(object:get_luaentity().itemstring)) then -- Collection - if vector.distance(checkpos, object:get_pos()) <= item_drop_settings.radius_collect and not object:get_luaentity()._removed then + if not object:get_luaentity()._removed then -- Ignore if itemstring is not set yet if object:get_luaentity().itemstring ~= "" then inv:add_item("main", ItemStack(object:get_luaentity().itemstring)) - minetest.sound_play("item_drop_pickup", { - pos = pos, - max_hear_distance = 16, - gain = 1.0, - }, true) - check_pickup_achievements(object, player) + check_pickup_achievements(object, player) -- Destroy entity -- This just prevents this section to be run again because object:remove() doesn't remove the item immediately. + object:get_luaentity().target = checkpos object:get_luaentity()._removed = true - object:remove() - collected = true + + object:set_velocity({x=0,y=0,z=0}) + object:set_acceleration({x=0,y=0,z=0}) + + object:move_to(checkpos) + + pool[name] = pool[name] + 1 + + minetest.after(0.25, function() + --safety check + if object and object:get_luaentity() then + object:remove() + end + end) end - - -- Magnet - else - - object:get_luaentity()._magnet_active = true - object:get_luaentity()._collector_timer = 0 - - -- Move object to player - disable_physics(object, object:get_luaentity()) - - local opos = object:get_pos() - local vec = vector.subtract(checkpos, opos) - vec = vector.add(opos, vector.divide(vec, 2)) - object:move_to(vec) - - - --fix eternally falling items - minetest.after(0, function(object) - local lua = object:get_luaentity() - if lua then - object:set_acceleration({x=0, y=0, z=0}) - end - end, object) - - - --this is a safety to prevent items flying away on laggy servers - if item_drop_settings.collection_safety == true then - if object:get_luaentity().init ~= true then - object:get_luaentity().init = true - minetest.after(1, function(args) - local playername = args[1] - local player = minetest.get_player_by_name(playername) - local object = args[2] - local lua = object:get_luaentity() - if player == nil or not player:is_player() or object == nil or lua == nil or lua.itemstring == nil then - return - end - if inv:room_for_item("main", ItemStack(object:get_luaentity().itemstring)) then - inv:add_item("main", ItemStack(object:get_luaentity().itemstring)) - if not object:get_luaentity()._removed then - minetest.sound_play("item_drop_pickup", { - pos = pos, - max_hear_distance = 16, - gain = 1.0, - }, true) - end - check_pickup_achievements(object, player) - object:get_luaentity()._removed = true - object:remove() - else - enable_physics(object, object:get_luaentity()) - end - end, {player:get_player_name(), object}) - end - end - end - end - - if not collected then - if object:get_luaentity()._magnet_timer > 1 then - object:get_luaentity()._magnet_timer = -item_drop_settings.magnet_time - object:get_luaentity()._magnet_active = false - elseif object:get_luaentity()._magnet_timer < 0 then - object:get_luaentity()._magnet_timer = object:get_luaentity()._magnet_timer + dtime end end @@ -230,12 +220,13 @@ local function get_fortune_drops(fortune_drops, fortune_level) return drop or {} end +local doTileDrops = minetest.settings:get_bool("mcl_doTileDrops", true) + function minetest.handle_node_drops(pos, drops, digger) -- NOTE: This function override allows digger to be nil. -- This means there is no digger. This is a special case which allows this function to be called -- by hand. Creative Mode is intentionally ignored in this case. - local doTileDrops = minetest.settings:get_bool("mcl_doTileDrops", true) if (digger and digger:is_player() and minetest.is_creative_enabled(digger:get_player_name())) or doTileDrops == false then return end @@ -335,6 +326,10 @@ function minetest.handle_node_drops(pos, drops, digger) z = -z end obj:set_velocity({x=1/x, y=obj:get_velocity().y, z=1/z}) + + obj:get_luaentity().age = item_drop_settings.dug_buffer + + obj:get_luaentity()._insta_collect = false end end end @@ -401,6 +396,9 @@ minetest.register_entity(":__builtin:item", { -- Number of seconds this item entity has existed so far age = 0, + -- How old it has become in the collection animation + collection_age = 0, + set_item = function(self, itemstring) self.itemstring = itemstring if self.itemstring == "" then @@ -566,6 +564,11 @@ minetest.register_entity(":__builtin:item", { on_step = function(self, dtime) if self._removed then + self.object:set_properties({ + physical = false + }) + self.object:set_velocity({x=0,y=0,z=0}) + self.object:set_acceleration({x=0,y=0,z=0}) return end self.age = self.age + dtime diff --git a/mods/ENTITIES/mcl_item_entity/sounds/Attributes.txt b/mods/ENTITIES/mcl_item_entity/sounds/Attributes.txt new file mode 100644 index 0000000000..7817593524 --- /dev/null +++ b/mods/ENTITIES/mcl_item_entity/sounds/Attributes.txt @@ -0,0 +1 @@ + Item_Drop_Pickup - https://freesound.org/people/benniknop/sounds/317848/ (License: CC0) diff --git a/mods/ENTITIES/mcl_item_entity/sounds/item_drop_pickup.1.ogg b/mods/ENTITIES/mcl_item_entity/sounds/item_drop_pickup.1.ogg deleted file mode 100644 index 8010ff0a29..0000000000 Binary files a/mods/ENTITIES/mcl_item_entity/sounds/item_drop_pickup.1.ogg and /dev/null differ diff --git a/mods/ENTITIES/mcl_item_entity/sounds/item_drop_pickup.2.ogg b/mods/ENTITIES/mcl_item_entity/sounds/item_drop_pickup.2.ogg deleted file mode 100644 index a5087ab7d9..0000000000 Binary files a/mods/ENTITIES/mcl_item_entity/sounds/item_drop_pickup.2.ogg and /dev/null differ diff --git a/mods/ENTITIES/mcl_item_entity/sounds/item_drop_pickup.3.ogg b/mods/ENTITIES/mcl_item_entity/sounds/item_drop_pickup.3.ogg deleted file mode 100644 index f234a482cf..0000000000 Binary files a/mods/ENTITIES/mcl_item_entity/sounds/item_drop_pickup.3.ogg and /dev/null differ diff --git a/mods/ENTITIES/mcl_item_entity/sounds/item_drop_pickup.4.ogg b/mods/ENTITIES/mcl_item_entity/sounds/item_drop_pickup.4.ogg deleted file mode 100644 index 6436f2678c..0000000000 Binary files a/mods/ENTITIES/mcl_item_entity/sounds/item_drop_pickup.4.ogg and /dev/null differ diff --git a/mods/ENTITIES/mcl_item_entity/sounds/item_drop_pickup.ogg b/mods/ENTITIES/mcl_item_entity/sounds/item_drop_pickup.ogg new file mode 100644 index 0000000000..e7f5df0949 Binary files /dev/null and b/mods/ENTITIES/mcl_item_entity/sounds/item_drop_pickup.ogg differ diff --git a/mods/ENTITIES/mcl_mobs/api.lua b/mods/ENTITIES/mcl_mobs/api.lua index f1df87e8b7..6c1a0567ec 100644 --- a/mods/ENTITIES/mcl_mobs/api.lua +++ b/mods/ENTITIES/mcl_mobs/api.lua @@ -61,8 +61,6 @@ end -- Load settings local damage_enabled = minetest.settings:get_bool("enable_damage") -local mobs_spawn = minetest.settings:get_bool("mobs_spawn", true) ~= false - local disable_blood = minetest.settings:get_bool("mobs_disable_blood") local mobs_drop_items = minetest.settings:get_bool("mobs_drop_items") ~= false local mobs_griefing = minetest.settings:get_bool("mobs_griefing") ~= false @@ -84,11 +82,6 @@ if minetest.settings:get_bool("only_peaceful_mobs", false) then end) end --- calculate aoc range for mob count -local aosrb = tonumber(minetest.settings:get("active_object_send_range_blocks")) -local abr = tonumber(minetest.settings:get("active_block_range")) -local aoc_range = max(aosrb, abr) * 16 - -- pathfinding settings local enable_pathfinding = true local stuck_timeout = 3 -- how long before mob gets stuck in place and starts searching @@ -735,7 +728,9 @@ local item_drop = function(self, cooked, looting_level) end -- add item if it exists - obj = minetest.add_item(pos, ItemStack(item .. " " .. num)) + for x = 1, num do + obj = minetest.add_item(pos, ItemStack(item .. " " .. 1)) + end if obj and obj:get_luaentity() then @@ -864,10 +859,12 @@ local check_for_death = function(self, cause, cmi_cause) remove_texture_mod(self, "^[colorize:#FF000040") remove_texture_mod(self, "^[brighten") self.passive = true + self.object:set_properties({ pointable = false, collide_with_objects = false, }) + set_velocity(self, 0) local acc = self.object:get_acceleration() acc.x, acc.y, acc.z = 0, DEFAULT_FALL_SPEED, 0 @@ -2817,6 +2814,10 @@ local do_states = function(self, dtime) local arrow, ent local v = 1 if not self.shoot_arrow then + self.firing = true + minetest.after(1, function() + self.firing = false + end) arrow = minetest.add_entity(p, self.arrow) ent = arrow:get_luaentity() if ent.velocity then @@ -3520,14 +3521,6 @@ local mob_step = function(self, dtime) -- end rotation - -- knockback timer - if self.pause_timer > 0 then - - self.pause_timer = self.pause_timer - dtime - - return - end - -- run custom function (defined in mob lua file) if self.do_custom then @@ -3537,6 +3530,14 @@ local mob_step = function(self, dtime) end end + -- knockback timer + if self.pause_timer > 0 then + + self.pause_timer = self.pause_timer - dtime + + return + end + -- attack timer self.timer = self.timer + dtime @@ -3555,7 +3556,7 @@ local mob_step = function(self, dtime) end -- mob plays random sound at times - if random(1, 100) == 1 then + if random(1, 70) == 1 then mob_sound(self, "random", true) end @@ -3735,6 +3736,8 @@ function mobs:register_mob(name, def) local can_despawn if def.can_despawn ~= nil then can_despawn = def.can_despawn +elseif def.spawn_class == "passive" then + can_despawn = false else can_despawn = true end @@ -3898,6 +3901,12 @@ minetest.register_entity(name, { on_detach_child = mob_detach_child, on_activate = function(self, staticdata, dtime) + --this is a temporary hack so mobs stop + --glitching and acting really weird with the + --default built in engine collision detection + self.object:set_properties({ + collide_with_objects = false, + }) return mob_activate(self, staticdata, def, dtime) end, @@ -3916,289 +3925,6 @@ end end -- END mobs:register_mob function --- count how many mobs of one type are inside an area -local count_mobs = function(pos, mobtype) - - local num = 0 - local objs = minetest.get_objects_inside_radius(pos, aoc_range) - - for n = 1, #objs do - - local obj = objs[n]:get_luaentity() - - if obj and obj.name and obj._cmi_is_mob then - - -- count passive mobs only - if mobtype == "!passive" then - if obj.spawn_class == "passive" then - num = num + 1 - end - -- count hostile mobs only - elseif mobtype == "!hostile" then - if obj.spawn_class == "hostile" then - num = num + 1 - end - -- count ambient mobs only - elseif mobtype == "!ambient" then - if obj.spawn_class == "ambient" then - num = num + 1 - end - -- count water mobs only - elseif mobtype == "!water" then - if obj.spawn_class == "water" then - num = num + 1 - end - -- count mob type - elseif mobtype and obj.name == mobtype then - num = num + 1 - -- count total mobs - elseif not mobtype then - num = num + 1 - end - end - end - - return num -end - - --- global functions - -function mobs:spawn_abm_check(pos, node, name) - -- global function to add additional spawn checks - -- return true to stop spawning mob -end - - -function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light, - interval, chance, aoc, min_height, max_height, day_toggle, on_spawn) - - -- Do mobs spawn at all? - if not mobs_spawn then - return - end - - -- chance/spawn number override in minetest.conf for registered mob - local numbers = minetest.settings:get(name) - - if numbers then - numbers = numbers:split(",") - chance = tonumber(numbers[1]) or chance - aoc = tonumber(numbers[2]) or aoc - - if chance == 0 then - minetest.log("warning", string.format("[mobs] %s has spawning disabled", name)) - return - end - - minetest.log("action", - string.format("[mobs] Chance setting for %s changed to %s (total: %s)", name, chance, aoc)) - - end - - local spawn_action - spawn_action = function(pos, node, active_object_count, active_object_count_wider, name) - - local orig_pos = table.copy(pos) - -- is mob actually registered? - if not mobs.spawning_mobs[name] - or not minetest.registered_entities[name] then - minetest.log("warning", "Mob spawn of "..name.." failed, unknown entity or mob is not registered for spawning!") - return - end - - -- additional custom checks for spawning mob - if mobs:spawn_abm_check(pos, node, name) == true then - minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, ABM check rejected!") - return - end - - -- count nearby mobs in same spawn class - local entdef = minetest.registered_entities[name] - local spawn_class = entdef and entdef.spawn_class - if not spawn_class then - if entdef.type == "monster" then - spawn_class = "hostile" - else - spawn_class = "passive" - end - end - local in_class_cap = count_mobs(pos, "!"..spawn_class) < MOB_CAP[spawn_class] - -- do not spawn if too many of same mob in area - if active_object_count_wider >= max_per_block -- large-range mob cap - or (not in_class_cap) -- spawn class mob cap - or count_mobs(pos, name) >= aoc then -- per-mob mob cap - -- too many entities - minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, too crowded!") - return - end - - -- if toggle set to nil then ignore day/night check - if day_toggle ~= nil then - - local tod = (minetest.get_timeofday() or 0) * 24000 - - if tod > 4500 and tod < 19500 then - -- daylight, but mob wants night - if day_toggle == false then - -- mob needs night - minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, mob needs light!") - return - end - else - -- night time but mob wants day - if day_toggle == true then - -- mob needs day - minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, mob needs daylight!") - return - end - end - end - - -- spawn above node - pos.y = pos.y + 1 - - -- only spawn away from player - local objs = minetest.get_objects_inside_radius(pos, 24) - - for n = 1, #objs do - - if objs[n]:is_player() then - -- player too close - minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, player too close!") - return - end - end - - -- mobs cannot spawn in protected areas when enabled - if not spawn_protected - and minetest.is_protected(pos, "") then - minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, position is protected!") - return - end - - -- are we spawning within height limits? - if pos.y > max_height - or pos.y < min_height then - minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, out of height limit!") - return - end - - -- are light levels ok? - local light = minetest.get_node_light(pos) - if not light - or light > max_light - or light < min_light then - minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, bad light!") - return - end - - -- do we have enough space to spawn mob? - local ent = minetest.registered_entities[name] - local width_x = max(1, math.ceil(ent.collisionbox[4] - ent.collisionbox[1])) - local min_x, max_x - if width_x % 2 == 0 then - max_x = math.floor(width_x/2) - min_x = -(max_x-1) - else - max_x = math.floor(width_x/2) - min_x = -max_x - end - - local width_z = max(1, math.ceil(ent.collisionbox[6] - ent.collisionbox[3])) - local min_z, max_z - if width_z % 2 == 0 then - max_z = math.floor(width_z/2) - min_z = -(max_z-1) - else - max_z = math.floor(width_z/2) - min_z = -max_z - end - - local max_y = max(0, math.ceil(ent.collisionbox[5] - ent.collisionbox[2]) - 1) - - for y = 0, max_y do - for x = min_x, max_x do - for z = min_z, max_z do - local pos2 = {x = pos.x+x, y = pos.y+y, z = pos.z+z} - if minetest.registered_nodes[node_ok(pos2).name].walkable == true then - -- inside block - minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, too little space!") - if ent.spawn_small_alternative ~= nil and (not minetest.registered_nodes[node_ok(pos).name].walkable) then - minetest.log("info", "Trying to spawn smaller alternative mob: "..ent.spawn_small_alternative) - spawn_action(orig_pos, node, active_object_count, active_object_count_wider, ent.spawn_small_alternative) - end - return - end - end - end - end - - -- tweak X/Y/Z spawn pos - if width_x % 2 == 0 then - pos.x = pos.x + 0.5 - end - if width_z % 2 == 0 then - pos.z = pos.z + 0.5 - end - pos.y = pos.y - 0.5 - - local mob = minetest.add_entity(pos, name) - minetest.log("action", "Mob spawned: "..name.." at "..minetest.pos_to_string(pos)) - - if on_spawn then - - local ent = mob:get_luaentity() - - on_spawn(ent, pos) - end - end - - local function spawn_abm_action(pos, node, active_object_count, active_object_count_wider) - spawn_action(pos, node, active_object_count, active_object_count_wider, name) - end - - minetest.register_abm({ - label = name .. " spawning", - nodenames = nodes, - neighbors = neighbors, - interval = interval, - chance = floor(max(1, chance * mobs_spawn_chance)), - catch_up = false, - action = spawn_abm_action, - }) -end - - --- compatibility with older mob registration -function mobs:register_spawn(name, nodes, max_light, min_light, chance, active_object_count, max_height, day_toggle) - - mobs:spawn_specific(name, nodes, {"air"}, min_light, max_light, 30, - chance, active_object_count, -31000, max_height, day_toggle) -end - - --- MarkBu's spawn function -function mobs:spawn(def) - - local name = def.name - local nodes = def.nodes or {"group:soil", "group:stone"} - local neighbors = def.neighbors or {"air"} - local min_light = def.min_light or 0 - local max_light = def.max_light or 15 - local interval = def.interval or 30 - local chance = def.chance or 5000 - local active_object_count = def.active_object_count or 1 - local min_height = def.min_height or -31000 - local max_height = def.max_height or 31000 - local day_toggle = def.day_toggle - local on_spawn = def.on_spawn - - mobs:spawn_specific(name, nodes, neighbors, min_light, max_light, interval, - chance, active_object_count, min_height, max_height, day_toggle, on_spawn) -end - - -- register arrow for shoot attack function mobs:register_arrow(name, def) @@ -4221,6 +3947,11 @@ function mobs:register_arrow(name, def) switch = 0, owner_id = def.owner_id, rotate = def.rotate, + on_punch = function(self) + local vel = self.object:get_velocity() + self.object:set_velocity({x=vel.x * -1, y=vel.y * -1, z=vel.z * -1}) + end, + collisionbox = def.collisionbox or {0, 0, 0, 0, 0, 0}, automatic_face_movement_dir = def.rotate and (def.rotate - (pi / 180)) or false, @@ -4283,7 +4014,7 @@ function mobs:register_arrow(name, def) if self.hit_player or self.hit_mob or self.hit_object then - for _,player in pairs(minetest.get_objects_inside_radius(pos, 1.0)) do + for _,player in pairs(minetest.get_objects_inside_radius(pos, 1.5)) do if self.hit_player and player:is_player() then @@ -4338,7 +4069,7 @@ end -- make explosion with protection and tnt mod check function mobs:boom(self, pos, strength, fire) - + self.object:remove() if mod_explosions then if mobs_griefing and not minetest.is_protected(pos, "") then mcl_explosions.explode(pos, strength, { drop_chance = 1.0, fire = fire }, self.object) @@ -4619,6 +4350,7 @@ function mobs:alias_mob(old_name, new_name) end +--[[ local timer = 0 minetest.register_globalstep(function(dtime) timer = timer + dtime @@ -4635,3 +4367,4 @@ minetest.register_globalstep(function(dtime) end timer = 0 end) +]]-- \ No newline at end of file diff --git a/mods/ENTITIES/mcl_mobs/init.lua b/mods/ENTITIES/mcl_mobs/init.lua index c2d6cb21bc..69246b4706 100644 --- a/mods/ENTITIES/mcl_mobs/init.lua +++ b/mods/ENTITIES/mcl_mobs/init.lua @@ -4,8 +4,11 @@ local path = minetest.get_modpath(minetest.get_current_modname()) -- Mob API dofile(path .. "/api.lua") +-- Spawning Algorithm +dofile(path .. "/spawning.lua") + -- Rideable Mobs dofile(path .. "/mount.lua") -- Mob Items -dofile(path .. "/crafts.lua") +dofile(path .. "/crafts.lua") \ No newline at end of file diff --git a/mods/ENTITIES/mcl_mobs/mount.lua b/mods/ENTITIES/mcl_mobs/mount.lua index d8ce484c32..9383ee067c 100644 --- a/mods/ENTITIES/mcl_mobs/mount.lua +++ b/mods/ENTITIES/mcl_mobs/mount.lua @@ -168,16 +168,20 @@ function mobs.detach(player, offset) mcl_player.player_set_animation(player, "stand" , 30) - local pos = player:get_pos() + --local pos = player:get_pos() - pos = {x = pos.x + offset.x, y = pos.y + 0.2 + offset.y, z = pos.z + offset.z} + --pos = {x = pos.x + offset.x, y = pos.y + 0.2 + offset.y, z = pos.z + offset.z} + player:add_velocity(vector.new(math.random(-6,6),math.random(5,8),math.random(-6,6))) --throw the rider off + + --[[ minetest.after(0.1, function(name, pos) local player = minetest.get_player_by_name(name) if player then player:set_pos(pos) end end, player:get_player_name(), pos) + ]]-- end diff --git a/mods/ENTITIES/mcl_mobs/spawning.lua b/mods/ENTITIES/mcl_mobs/spawning.lua new file mode 100644 index 0000000000..210c6b9c67 --- /dev/null +++ b/mods/ENTITIES/mcl_mobs/spawning.lua @@ -0,0 +1,647 @@ +--lua locals +local get_node = minetest.get_node +local get_item_group = minetest.get_item_group +local get_node_light = minetest.get_node_light +local find_nodes_in_area_under_air = minetest.find_nodes_in_area_under_air +local new_vector = vector.new +local math_random = math.random +local get_biome_name = minetest.get_biome_name +local max = math.max +local get_objects_inside_radius = minetest.get_objects_inside_radius +local vector_distance = vector.distance + +-- range for mob count +local aoc_range = 32 +--[[ + +THIS IS THE BIG LIST OF ALL BIOMES - used for programming/updating mobs + +underground: +"FlowerForest_underground", +"JungleEdge_underground",local spawning_position = spawning_position_list[math.random(1,#spawning_position_list)] +"ColdTaiga_underground", +"IcePlains_underground", +"IcePlainsSpikes_underground", +"MegaTaiga_underground", +"Taiga_underground", +"ExtremeHills+_underground", +"JungleM_underground", +"ExtremeHillsM_underground", +"JungleEdgeM_underground", + +ocean: +"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", +"MushroomIsland_ocean", +"MegaTaiga_ocean", +"StoneBeach_deep_ocean", +"IcePlainsSpikes_deep_ocean", +"ColdTaiga_ocean", +"SavannaM_ocean", +"MesaPlateauF_deep_ocean", +"MesaBryce_deep_ocean", +"ExtremeHills+_deep_ocean", +"ExtremeHills_ocean", +"MushroomIsland_deep_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", + +water or beach? +"MesaPlateauFM_sandlevel", +"MesaPlateauF_sandlevel", +"MesaBryce_sandlevel", +"Mesa_sandlevel", + +beach: +"FlowerForest_beach", +"Forest_beach", +"StoneBeach", +"ColdTaiga_beach_water", +"Taiga_beach", +"Savanna_beach", +"Plains_beach", +"ExtremeHills_beach", +"ColdTaiga_beach", +"Swampland_shore", +"MushroomIslandShore", +"JungleM_shore", +"Jungle_shore", + +dimension biome: +"Nether", +"End", + +Overworld regular: +"Mesa", +"FlowerForest", +"Swampland", +"Taiga", +"ExtremeHills", +"Jungle", +"Savanna", +"BirchForest", +"MegaSpruceTaiga", +"MegaTaiga", +"ExtremeHills+", +"Forest", +"Plains", +"Desert", +"ColdTaiga", +"MushroomIsland", +"IcePlainsSpikes", +"SunflowerPlains", +"IcePlains", +"RoofedForest", +"ExtremeHills+_snowtop", +"MesaPlateauFM_grasstop", +"JungleEdgeM", +"ExtremeHillsM", +"JungleM", +"BirchForestM", +"MesaPlateauF", +"MesaPlateauFM", +"MesaPlateauF_grasstop", +"MesaBryce", +"JungleEdge", +"SavannaM", +]]-- + + + + +local mobs_spawn = minetest.settings:get_bool("mobs_spawn", true) ~= false +-- count how many mobs of one type are inside an area + +local count_mobs = function(pos,mobtype) + local num = 0 + local objs = get_objects_inside_radius(pos, aoc_range) + for n = 1, #objs do + local obj = objs[n]:get_luaentity() + if obj and obj.name and obj._cmi_is_mob then + -- count hostile mobs only + if mobtype == "hostile" then + if obj.spawn_class == "hostile" then + num = num + 1 + end + -- count passive mobs only + else + num = num + 1 + end + end + end + + return num +end + + +-- global functions + +function mobs:spawn_abm_check(pos, node, name) + -- global function to add additional spawn checks + -- return true to stop spawning mob +end + + +--[[ + Custom elements changed: + +name: +the mobs name + +dimension: +"overworld" +"nether" +"end" + +types of spawning: +"water" +"ground" +"lava" + +biomes: tells the spawner to allow certain mobs to spawn in certain biomes +{"this", "that", "grasslands", "whatever"} + + +what is aoc??? objects in area + +WARNING: BIOME INTEGRATION NEEDED -> How to get biome through lua?? +]]-- + + +--this is where all of the spawning information is kept +local spawn_dictionary = {} + +function mobs:spawn_specific(name, dimension, type_of_spawning, biomes, min_light, max_light, interval, chance, aoc, min_height, max_height, day_toggle, on_spawn) + + --print(dump(biomes)) + + -- Do mobs spawn at all? + if not mobs_spawn then + return + end + + -- chance/spawn number override in minetest.conf for registered mob + local numbers = minetest.settings:get(name) + + if numbers then + numbers = numbers:split(",") + chance = tonumber(numbers[1]) or chance + aoc = tonumber(numbers[2]) or aoc + + if chance == 0 then + minetest.log("warning", string.format("[mobs] %s has spawning disabled", name)) + return + end + + minetest.log("action", + string.format("[mobs] Chance setting for %s changed to %s (total: %s)", name, chance, aoc)) + end + + --[[ + local spawn_action + spawn_action = function(pos, node, active_object_count, active_object_count_wider, name) + + local orig_pos = table.copy(pos) + -- is mob actually registered? + if not mobs.spawning_mobs[name] + or not minetest.registered_entities[name] then + minetest.log("warning", "Mob spawn of "..name.." failed, unknown entity or mob is not registered for spawning!") + return + end + + -- additional custom checks for spawning mob + if mobs:spawn_abm_check(pos, node, name) == true then + minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, ABM check rejected!") + return + end + + -- count nearby mobs in same spawn class + local entdef = minetest.registered_entities[name] + local spawn_class = entdef and entdef.spawn_class + if not spawn_class then + if entdef.type == "monster" then + spawn_class = "hostile" + else + spawn_class = "passive" + end + end + local in_class_cap = count_mobs(pos, "!"..spawn_class) < MOB_CAP[spawn_class] + -- do not spawn if too many of same mob in area + if active_object_count_wider >= max_per_block -- large-range mob cap + or (not in_class_cap) -- spawn class mob cap + or count_mobs(pos, name) >= aoc then -- per-mob mob cap + -- too many entities + minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, too crowded!") + return + end + + -- if toggle set to nil then ignore day/night check + if day_toggle ~= nil then + + local tod = (minetest.get_timeofday() or 0) * 24000 + + if tod > 4500 and tod < 19500 then + -- daylight, but mob wants night + if day_toggle == false then + -- mob needs night + minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, mob needs light!") + return + end + else + -- night time but mob wants day + if day_toggle == true then + -- mob needs day + minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, mob needs daylight!") + return + end + end + end + + -- spawn above node + pos.y = pos.y + 1 + + -- only spawn away from player + local objs = minetest.get_objects_inside_radius(pos, 24) + + for n = 1, #objs do + + if objs[n]:is_player() then + -- player too close + minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, player too close!") + return + end + end + + -- mobs cannot spawn in protected areas when enabled + if not spawn_protected + and minetest.is_protected(pos, "") then + minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, position is protected!") + return + end + + -- are we spawning within height limits? + if pos.y > max_height + or pos.y < min_height then + minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, out of height limit!") + return + end + + -- are light levels ok? + local light = minetest.get_node_light(pos) + if not light + or light > max_light + or light < min_light then + minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, bad light!") + return + end + + -- do we have enough space to spawn mob? + local ent = minetest.registered_entities[name] + local width_x = max(1, math.ceil(ent.collisionbox[4] - ent.collisionbox[1])) + local min_x, max_x + if width_x % 2 == 0 then + max_x = math.floor(width_x/2) + min_x = -(max_x-1) + else + max_x = math.floor(width_x/2) + min_x = -max_x + end + + local width_z = max(1, math.ceil(ent.collisionbox[6] - ent.collisionbox[3])) + local min_z, max_z + if width_z % 2 == 0 then + max_z = math.floor(width_z/2) + min_z = -(max_z-1) + else + max_z = math.floor(width_z/2) + min_z = -max_z + end + + local max_y = max(0, math.ceil(ent.collisionbox[5] - ent.collisionbox[2]) - 1) + + for y = 0, max_y do + for x = min_x, max_x do + for z = min_z, max_z do + local pos2 = {x = pos.x+x, y = pos.y+y, z = pos.z+z} + if minetest.registered_nodes[node_ok(pos2).name].walkable == true then + -- inside block + minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, too little space!") + if ent.spawn_small_alternative ~= nil and (not minetest.registered_nodes[node_ok(pos).name].walkable) then + minetest.log("info", "Trying to spawn smaller alternative mob: "..ent.spawn_small_alternative) + spawn_action(orig_pos, node, active_object_count, active_object_count_wider, ent.spawn_small_alternative) + end + return + end + end + end + end + + -- tweak X/Y/Z spawn pos + if width_x % 2 == 0 then + pos.x = pos.x + 0.5 + end + if width_z % 2 == 0 then + pos.z = pos.z + 0.5 + end + pos.y = pos.y - 0.5 + + local mob = minetest.add_entity(pos, name) + minetest.log("action", "Mob spawned: "..name.." at "..minetest.pos_to_string(pos)) + + if on_spawn then + + local ent = mob:get_luaentity() + + on_spawn(ent, pos) + end + end + + local function spawn_abm_action(pos, node, active_object_count, active_object_count_wider) + spawn_action(pos, node, active_object_count, active_object_count_wider, name) + end + ]]-- + + local entdef = minetest.registered_entities[name] + local spawn_class + if entdef.type == "monster" then + spawn_class = "hostile" + else + spawn_class = "passive" + end + + --load information into the spawn dictionary + local key = #spawn_dictionary + 1 + spawn_dictionary[key] = {} + spawn_dictionary[key]["name"] = name + spawn_dictionary[key]["dimension"] = dimension + spawn_dictionary[key]["type_of_spawning"] = type_of_spawning + spawn_dictionary[key]["biomes"] = biomes + spawn_dictionary[key]["min_light"] = min_light + spawn_dictionary[key]["max_light"] = max_light + spawn_dictionary[key]["interval"] = interval + spawn_dictionary[key]["chance"] = chance + spawn_dictionary[key]["aoc"] = aoc + spawn_dictionary[key]["min_height"] = min_height + spawn_dictionary[key]["max_height"] = max_height + spawn_dictionary[key]["day_toggle"] = day_toggle + --spawn_dictionary[key]["on_spawn"] = spawn_abm_action + spawn_dictionary[key]["spawn_class"] = spawn_class + + --[[ + minetest.register_abm({ + label = name .. " spawning", + nodenames = nodes, + neighbors = neighbors, + interval = interval, + chance = floor(max(1, chance * mobs_spawn_chance)), + catch_up = false, + action = spawn_abm_action, + }) + ]]-- +end + +-- compatibility with older mob registration +-- we're going to forget about this for now -j4i +--[[ +function mobs:register_spawn(name, nodes, max_light, min_light, chance, active_object_count, max_height, day_toggle) + + mobs:spawn_specific(name, nodes, {"air"}, min_light, max_light, 30, + chance, active_object_count, -31000, max_height, day_toggle) +end +]]-- + + +--Don't disable this yet-j4i +-- MarkBu's spawn function + +function mobs:spawn(def) + --does nothing for now + --[[ + local name = def.name + local nodes = def.nodes or {"group:soil", "group:stone"} + local neighbors = def.neighbors or {"air"} + local min_light = def.min_light or 0 + local max_light = def.max_light or 15 + local interval = def.interval or 30 + local chance = def.chance or 5000 + local active_object_count = def.active_object_count or 1 + local min_height = def.min_height or -31000 + local max_height = def.max_height or 31000 + local day_toggle = def.day_toggle + local on_spawn = def.on_spawn + + mobs:spawn_specific(name, nodes, neighbors, min_light, max_light, interval, + chance, active_object_count, min_height, max_height, day_toggle, on_spawn) + ]]-- +end + + + +local axis +--inner and outer part of square donut radius +local inner = 1 +local outer = 65 +local int = {-1,1} +local position_calculation = function(pos) + + pos = vector.floor(pos) + + --this is used to determine the axis buffer from the player + axis = math.random(0,1) + + --cast towards the direction + if axis == 0 then --x + pos.x = pos.x + math.random(inner,outer)*int[math.random(1,2)] + pos.z = pos.z + math.random(-outer,outer) + else --z + pos.z = pos.z + math.random(inner,outer)*int[math.random(1,2)] + pos.x = pos.x + math.random(-outer,outer) + end + return(pos) +end + +--[[ +local decypher_limits_dictionary = { + ["overworld"] = {mcl_vars.mg_overworld_min,mcl_vars.mg_overworld_max}, + ["nether"] = {mcl_vars.mg_nether_min, mcl_vars.mg_nether_max}, + ["end"] = {mcl_vars.mg_end_min, mcl_vars.mg_end_max} +} +]]-- + +local function decypher_limits(posy) + --local min_max_table = decypher_limits_dictionary[dimension] + --return min_max_table[1],min_max_table[2] + posy = math.floor(posy) + return posy - 32, posy + 32 +end + +--a simple helper function for mob_spawn +local function biome_check(biome_list, biome_goal) + for _,data in ipairs(biome_list) do + if data == biome_goal then + return true + end + end + + return false +end + + +--todo mob limiting +--MAIN LOOP + +if mobs_spawn then + local timer = 0 + minetest.register_globalstep(function(dtime) + timer = timer + dtime + if timer >= 8 then + timer = 0 + for _,player in pairs(minetest.get_connected_players()) do + for i = 1,math_random(3,8) do + repeat -- after this line each "break" means "continue" + local player_pos = player:get_pos() + + local _,dimension = mcl_worlds.y_to_layer(player_pos.y) + + if dimension == "void" or dimension == "default" then + break -- ignore void and unloaded area + end + + local min,max = decypher_limits(player_pos.y) + + local goal_pos = position_calculation(player_pos) + + local spawning_position_list = find_nodes_in_area_under_air(new_vector(goal_pos.x,min,goal_pos.z), vector.new(goal_pos.x,max,goal_pos.z), {"group:solid", "group:water", "group:lava"}) + + --couldn't find node + if #spawning_position_list <= 0 then + break + end + + local spawning_position = spawning_position_list[math_random(1,#spawning_position_list)] + + --Prevent strange behavior/too close to player + if not spawning_position or vector_distance(player_pos, spawning_position) < 15 then + break + end + + local gotten_node = get_node(spawning_position).name + + if not gotten_node or gotten_node == "air" then --skip air nodes + break + end + + local gotten_biome = minetest.get_biome_data(spawning_position) + + if not gotten_biome then + break --skip if in unloaded area + end + + gotten_biome = get_biome_name(gotten_biome.biome) --makes it easier to work with + + --grab random mob + local mob_def = spawn_dictionary[math.random(1,#spawn_dictionary)] + + if not mob_def then + break --skip if something ridiculous happens (nil mob def) + end + + --skip if not correct dimension + if mob_def.dimension ~= dimension then + break + end + + --skip if not in correct biome + if not biome_check(mob_def.biomes, gotten_biome) then + break + end + + --add this so mobs don't spawn inside nodes + spawning_position.y = spawning_position.y + 1 + + if spawning_position.y < mob_def.min_height or spawning_position.y > mob_def.max_height then + break + end + + --only need to poll for node light if everything else worked + local gotten_light = get_node_light(spawning_position) + + --don't spawn if not in light limits + if gotten_light < mob_def.min_light or gotten_light > mob_def.max_light then + break + end + + local is_water = get_item_group(gotten_node, "water") ~= 0 + local is_lava = get_item_group(gotten_node, "lava") ~= 0 + + if mob_def.type_of_spawning == "ground" and is_water then + break + end + + if mob_def.type_of_spawning == "ground" and is_lava then + break + end + + --finally do the heavy check (for now) of mobs in area + if count_mobs(spawning_position, mob_def.spawn_class) >= mob_def.aoc then + break + end + + --adjust the position for water and lava mobs + if mob_def.type_of_spawning == "water" or mob_def.type_of_spawning == "lava" then + spawning_position.y = spawning_position.y - 1 + end + + --everything is correct, spawn mob + minetest.add_entity(spawning_position, mob_def.name) + until true --this is a safety catch + end + end + end + end) +end diff --git a/mods/ENTITIES/mobs_mc/0_gameconfig.lua b/mods/ENTITIES/mobs_mc/0_gameconfig.lua index 74c92d4153..c92ccbba52 100644 --- a/mods/ENTITIES/mobs_mc/0_gameconfig.lua +++ b/mods/ENTITIES/mobs_mc/0_gameconfig.lua @@ -290,13 +290,13 @@ mobs_mc.spawn = { mobs_mc.spawn_height = { water = tonumber(minetest.settings:get("water_level")) or 0, -- Water level in the Overworld - -- Overworld boundaries (inclusive) - overworld_min = -2999, + -- Overworld boundaries (inclusive) --I adjusted this to be more reasonable + overworld_min = -64,-- -2999, overworld_max = 31000, -- Nether boundaries (inclusive) - nether_min = -3369, - nether_max = -3000, + nether_min = -29067,-- -3369, + nether_max = -28939,-- -3000, -- End boundaries (inclusive) end_min = -6200, diff --git a/mods/ENTITIES/mobs_mc/agent.lua b/mods/ENTITIES/mobs_mc/agent.lua index 8fa7314cf2..cc9910ee6d 100644 --- a/mods/ENTITIES/mobs_mc/agent.lua +++ b/mods/ENTITIES/mobs_mc/agent.lua @@ -1,5 +1,5 @@ --################### ---################### AGENT +--################### AGENT - seemingly unused --################### local S = minetest.get_translator("mobs_mc") diff --git a/mods/ENTITIES/mobs_mc/bat.lua b/mods/ENTITIES/mobs_mc/bat.lua index 103579b67f..677b96aad3 100644 --- a/mods/ENTITIES/mobs_mc/bat.lua +++ b/mods/ENTITIES/mobs_mc/bat.lua @@ -64,7 +64,81 @@ else end -- Spawn on solid blocks at or below Sea level and the selected light level -mobs:spawn_specific("mobs_mc:bat", mobs_mc.spawn.solid, {"air"}, 0, maxlight, 20, 5000, 2, mobs_mc.spawn_height.overworld_min, mobs_mc.spawn_height.water-1) +mobs:spawn_specific( +"mobs_mc:bat", +"overworld", +"ground", +{ +"FlowerForest_underground", +"JungleEdge_underground", +"StoneBeach_underground", +"MesaBryce_underground", +"Mesa_underground", +"RoofedForest_underground", +"Jungle_underground", +"Swampland_underground", +"MushroomIsland_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", +"Mesa", +"FlowerForest", +"Swampland", +"Taiga", +"ExtremeHills", +"Jungle", +"Savanna", +"BirchForest", +"MegaSpruceTaiga", +"MegaTaiga", +"ExtremeHills+", +"Forest", +"Plains", +"Desert", +"ColdTaiga", +"MushroomIsland", +"IcePlainsSpikes", +"SunflowerPlains", +"IcePlains", +"RoofedForest", +"ExtremeHills+_snowtop", +"MesaPlateauFM_grasstop", +"JungleEdgeM", +"ExtremeHillsM", +"JungleM", +"BirchForestM", +"MesaPlateauF", +"MesaPlateauFM", +"MesaPlateauF_grasstop", +"MesaBryce", +"JungleEdge", +"SavannaM", +}, +0, +maxlight, +20, +5000, +2, +mobs_mc.spawn_height.overworld_min, +mobs_mc.spawn_height.water-1) -- spawn eggs diff --git a/mods/ENTITIES/mobs_mc/blaze.lua b/mods/ENTITIES/mobs_mc/blaze.lua index 20fa86a1f3..847e2f4a53 100644 --- a/mods/ENTITIES/mobs_mc/blaze.lua +++ b/mods/ENTITIES/mobs_mc/blaze.lua @@ -1,6 +1,6 @@ -- daufinsyd -- My work is under the LGPL terms --- Model and mobs_blaze.png see https://github.com/22i/minecraft-voxel-blender-models +-- Model and mobs_blaze.png see https://github.com/22i/minecraft-voxel-blender-models -hi 22i ~jordan4ibanez -- blaze.lua partial copy of mobs_mc/ghast.lua local S = minetest.get_translator("mobs_mc") @@ -75,9 +75,71 @@ mobs:register_mob("mobs_mc:blaze", { fear_height = 0, glow = 14, fire_resistant = true, + do_custom = function(self) + if self.state == "attack" and vector.distance(self.object:get_pos(), self.attack:get_pos()) < 1.2 then + mcl_burning.set_on_fire(self.attack, 5) + end + local pos = self.object:get_pos() + minetest.add_particle({ + pos = {x=pos.x+math.random(-0.7,0.7)*math.random()/2,y=pos.y+math.random(0.7,1.2),z=pos.z+math.random(-0.7,0.7)*math.random()/2}, + velocity = {x=0, y=math.random(1,1), z=0}, + expirationtime = math.random(), + size = math.random(1, 4), + collisiondetection = true, + vertical = false, + texture = "mcl_particles_smoke_anim.png^[colorize:#2c2c2c:255", + animation = { + type = "vertical_frames", + aspect_w = 8, + aspect_h = 8, + length = 2.05, + }, + }) + minetest.add_particle({ + pos = {x=pos.x+math.random(-0.7,0.7)*math.random()/2,y=pos.y+math.random(0.7,1.2),z=pos.z+math.random(-0.7,0.7)*math.random()/2}, + velocity = {x=0, y=math.random(1,1), z=0}, + expirationtime = math.random(), + size = math.random(1, 4), + collisiondetection = true, + vertical = false, + texture = "mcl_particles_smoke_anim.png^[colorize:#424242:255", + animation = { + type = "vertical_frames", + aspect_w = 8, + aspect_h = 8, + length = 2.05, + }, + }) + minetest.add_particle({ + pos = {x=pos.x+math.random(-0.7,0.7)*math.random()/2,y=pos.y+math.random(0.7,1.2),z=pos.z+math.random(-0.7,0.7)*math.random()/2}, + velocity = {x=0, y=math.random(1,1), z=0}, + expirationtime = math.random(), + size = math.random(1, 4), + collisiondetection = true, + vertical = false, + texture = "mcl_particles_smoke_anim.png^[colorize:#0f0f0f:255", + animation = { + type = "vertical_frames", + aspect_w = 8, + aspect_h = 8, + length = 2.05, + }, + }) + end, }) -mobs:spawn_specific("mobs_mc:blaze", mobs_mc.spawn.nether_fortress, {"air"}, 0, minetest.LIGHT_MAX+1, 30, 5000, 3, mobs_mc.spawn_height.nether_min, mobs_mc.spawn_height.nether_max) +mobs:spawn_specific( +"mobs_mc:blaze", +"nether", +"ground", +{"Nether"}, +0, +minetest.LIGHT_MAX+1, +30, +5000, +3, +mobs_mc.spawn_height.nether_min, +mobs_mc.spawn_height.nether_max) -- Blaze fireball mobs:register_arrow("mobs_mc:blaze_fireball", { diff --git a/mods/ENTITIES/mobs_mc/chicken.lua b/mods/ENTITIES/mobs_mc/chicken.lua index 325371e2b2..246bf216ac 100644 --- a/mods/ENTITIES/mobs_mc/chicken.lua +++ b/mods/ENTITIES/mobs_mc/chicken.lua @@ -100,7 +100,34 @@ mobs:register_mob("mobs_mc:chicken", { }) --spawn -mobs:spawn_specific("mobs_mc:chicken", mobs_mc.spawn.grassland, {"air"}, 9, minetest.LIGHT_MAX+1, 30, 17000, 3, mobs_mc.spawn_height.overworld_min, mobs_mc.spawn_height.overworld_max) +mobs:spawn_specific( +"mobs_mc:chicken", +"overworld", +"ground", +{ +"FlowerForest", +"Swampland", +"Taiga", +"ExtremeHills", +"BirchForest", +"MegaSpruceTaiga", +"MegaTaiga", +"ExtremeHills+", +"Forest", +"Plains", +"ColdTaiga", +"SunflowerPlains", +"RoofedForest", +"MesaPlateauFM_grasstop", +"ExtremeHillsM", +"BirchForestM", +}, +9, +minetest.LIGHT_MAX+1, +30, 17000, +3, +mobs_mc.spawn_height.water, +mobs_mc.spawn_height.overworld_max) -- spawn eggs mobs:register_egg("mobs_mc:chicken", S("Chicken"), "mobs_mc_spawn_icon_chicken.png", 0) diff --git a/mods/ENTITIES/mobs_mc/cow+mooshroom.lua b/mods/ENTITIES/mobs_mc/cow+mooshroom.lua index 005af29807..48fcc81975 100644 --- a/mods/ENTITIES/mobs_mc/cow+mooshroom.lua +++ b/mods/ENTITIES/mobs_mc/cow+mooshroom.lua @@ -145,8 +145,53 @@ mobs:register_mob("mobs_mc:mooshroom", mooshroom_def) -- Spawning -mobs:spawn_specific("mobs_mc:cow", mobs_mc.spawn.grassland, {"air"}, 9, minetest.LIGHT_MAX+1, 30, 17000, 10, mobs_mc.spawn_height.overworld_min, mobs_mc.spawn_height.overworld_max) -mobs:spawn_specific("mobs_mc:mooshroom", mobs_mc.spawn.mushroom_island, {"air"}, 9, minetest.LIGHT_MAX+1, 30, 17000, 5, mobs_mc.spawn_height.overworld_min, mobs_mc.spawn_height.overworld_max) +mobs:spawn_specific( +"mobs_mc:cow", +"overworld", +"ground", +{ +"FlowerForest", +"Swampland", +"Taiga", +"ExtremeHills", +"BirchForest", +"MegaSpruceTaiga", +"MegaTaiga", +"ExtremeHills+", +"Forest", +"Plains", +"ColdTaiga", +"SunflowerPlains", +"RoofedForest", +"MesaPlateauFM_grasstop", +"ExtremeHillsM", +"BirchForestM", +}, +9, +minetest.LIGHT_MAX+1, +30, +17000, +10, +mobs_mc.spawn_height.water, +mobs_mc.spawn_height.overworld_max) + + + +mobs:spawn_specific( +"mobs_mc:mooshroom", +"overworld", +"ground", +{ +"MushroomIslandShore", +"MushroomIsland" +}, +9, +minetest.LIGHT_MAX+1, +30, +17000, +5, +mobs_mc.spawn_height.overworld_min, +mobs_mc.spawn_height.overworld_max) -- spawn egg mobs:register_egg("mobs_mc:cow", S("Cow"), "mobs_mc_spawn_icon_cow.png", 0) diff --git a/mods/ENTITIES/mobs_mc/creeper.lua b/mods/ENTITIES/mobs_mc/creeper.lua index 9ee9e9d248..0c884d5699 100644 --- a/mods/ENTITIES/mobs_mc/creeper.lua +++ b/mods/ENTITIES/mobs_mc/creeper.lua @@ -39,6 +39,8 @@ mobs:register_mob("mobs_mc:creeper", { runaway_from = { "mobs_mc:ocelot", "mobs_mc:cat" }, attack_type = "explode", + --hssssssssssss + explosion_strength = 3, explosion_radius = 3.5, explosion_damage_radius = 3.5, @@ -76,7 +78,6 @@ mobs:register_mob("mobs_mc:creeper", { self._forced_explosion_countdown_timer = self._forced_explosion_countdown_timer - dtime if self._forced_explosion_countdown_timer <= 0 then mobs:boom(self, mcl_util.get_object_center(self.object), self.explosion_strength) - self.object:remove() end end end, @@ -139,6 +140,9 @@ mobs:register_mob("mobs_mc:creeper_charged", { pathfinding = 1, visual = "mesh", mesh = "mobs_mc_creeper.b3d", + + --BOOM + textures = { {"mobs_mc_creeper.png", "mobs_mc_creeper_charge.png"}, @@ -195,7 +199,6 @@ mobs:register_mob("mobs_mc:creeper_charged", { self._forced_explosion_countdown_timer = self._forced_explosion_countdown_timer - dtime if self._forced_explosion_countdown_timer <= 0 then mobs:boom(self, mcl_util.get_object_center(self.object), self.explosion_strength) - self.object:remove() end end end, @@ -250,7 +253,158 @@ mobs:register_mob("mobs_mc:creeper_charged", { glow = 3, }) -mobs:spawn_specific("mobs_mc:creeper", mobs_mc.spawn.solid, {"air"}, 0, 7, 20, 16500, 2, mobs_mc.spawn_height.overworld_min, mobs_mc.spawn_height.overworld_max) +mobs:spawn_specific( +"mobs_mc:creeper", +"overworld", +"ground", +{ +"Mesa", +"FlowerForest", +"Swampland", +"Taiga", +"ExtremeHills", +"Jungle", +"Savanna", +"BirchForest", +"MegaSpruceTaiga", +"MegaTaiga", +"ExtremeHills+", +"Forest", +"Plains", +"Desert", +"ColdTaiga", +"MushroomIsland", +"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", +"MushroomIslandShore", +"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", +"MushroomIsland_ocean", +"MegaTaiga_ocean", +"StoneBeach_deep_ocean", +"IcePlainsSpikes_deep_ocean", +"ColdTaiga_ocean", +"SavannaM_ocean", +"MesaPlateauF_deep_ocean", +"MesaBryce_deep_ocean", +"ExtremeHills+_deep_ocean", +"ExtremeHills_ocean", +"MushroomIsland_deep_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", +"MushroomIsland_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, +mobs_mc.spawn_height.overworld_min, +mobs_mc.spawn_height.overworld_max) -- spawn eggs mobs:register_egg("mobs_mc:creeper", S("Creeper"), "mobs_mc_spawn_icon_creeper.png", 0) diff --git a/mods/ENTITIES/mobs_mc/depends.txt b/mods/ENTITIES/mobs_mc/depends.txt new file mode 100644 index 0000000000..674eb80940 --- /dev/null +++ b/mods/ENTITIES/mobs_mc/depends.txt @@ -0,0 +1 @@ +mcl_mobs \ No newline at end of file diff --git a/mods/ENTITIES/mobs_mc/ender_dragon.lua b/mods/ENTITIES/mobs_mc/ender_dragon.lua index e62b0d16b9..a6f4042754 100644 --- a/mods/ENTITIES/mobs_mc/ender_dragon.lua +++ b/mods/ENTITIES/mobs_mc/ender_dragon.lua @@ -50,8 +50,8 @@ mobs:register_mob("mobs_mc:enderdragon", { arrow = "mobs_mc:dragon_fireball", shoot_interval = 0.5, shoot_offset = -1.0, - xp_min = 12000, - xp_max = 12000, + xp_min = 500, + xp_max = 500, animation = { fly_speed = 8, stand_speed = 8, stand_start = 0, stand_end = 20, @@ -59,15 +59,47 @@ mobs:register_mob("mobs_mc:enderdragon", { run_start = 0, run_end = 20, }, ignores_nametag = true, - on_die = function(self, own_pos) - if self._egg_spawn_pos then - local pos = minetest.string_to_pos(self._egg_spawn_pos) - --if minetest.get_node(pos).buildable_to then - minetest.set_node(pos, {name = mobs_mc.items.dragon_egg}) - return - --end + do_custom = function(self) + mcl_bossbars.update_boss(self.object, "Ender Dragon", "light_purple") + for _, obj in ipairs(minetest.get_objects_inside_radius(self.object:get_pos(), 80)) do + local luaentity = obj:get_luaentity() + if luaentity and luaentity.name == "mcl_end:crystal" then + if luaentity.beam then + if luaentity.beam == self.beam then + break + end + else + if self.beam then + self.beam:remove() + end + minetest.add_entity(self.object:get_pos(), "mcl_end:crystal_beam"):get_luaentity():init(self.object, obj) + break + end + end + end + if self._portal_pos then + -- migrate old format + if type(self._portal_pos) == "string" then + self._portal_pos = minetest.string_to_pos(self._portal_pos) + end + local portal_center = vector.add(self._portal_pos, vector.new(3, 11, 3)) + local pos = self.object:get_pos() + if vector.distance(pos, portal_center) > 50 then + self.object:set_pos(self._last_good_pos or portal_center) + else + self._last_good_pos = pos + end + end + end, + on_die = function(self, pos) + if self._portal_pos then + mcl_portals.spawn_gateway_portal() + mcl_structures.call_struct(self._portal_pos, "end_exit_portal_open") + if self._initial then + mcl_experience.throw_experience(pos, 11500) -- 500 + 11500 = 12000 + minetest.set_node(vector.add(self._portal_pos, vector.new(3, 5, 3)), {name = mobs_mc.items.dragon_egg}) + end end - minetest.add_item(own_pos, mobs_mc.items.dragon_egg) end, fire_resistant = true, }) diff --git a/mods/ENTITIES/mobs_mc/enderman.lua b/mods/ENTITIES/mobs_mc/enderman.lua index efc789344a..6c87b9305e 100644 --- a/mods/ENTITIES/mobs_mc/enderman.lua +++ b/mods/ENTITIES/mobs_mc/enderman.lua @@ -295,7 +295,8 @@ mobs:register_mob("mobs_mc:enderman", { -- ARROW / DAYTIME PEOPLE AVOIDANCE BEHAVIOUR HERE. -- Check for arrows and people nearby. local enderpos = self.object:get_pos() - local objs = minetest.get_objects_inside_radius(enderpos, 4) + enderpos.y = enderpos.y + 1.5 + local objs = minetest.get_objects_inside_radius(enderpos, 2) for n = 1, #objs do local obj = objs[n] if obj then @@ -307,7 +308,7 @@ mobs:register_mob("mobs_mc:enderman", { else local lua = obj:get_luaentity() if lua then - if lua.name == "mcl_bows:arrow_entity" then + if lua.name == "mcl_bows:arrow_entity" or lua.name == "mcl_throwing:snowball_entity" then self:teleport(nil) end end @@ -328,35 +329,44 @@ mobs:register_mob("mobs_mc:enderman", { --end end -- Check to see if people are near by enough to look at us. - local objs = minetest.get_objects_inside_radius(enderpos, 64) - local obj - for n = 1, #objs do - obj = objs[n] - if obj then - if minetest.is_player(obj) then + for _,obj in pairs(minetest.get_connected_players()) do + + --check if they are within radius + local player_pos = obj:get_pos() + if player_pos then -- prevent crashing in 1 in a million scenario + + local ender_distance = vector.distance(enderpos, player_pos) + if ender_distance <= 64 then + -- Check if they are looking at us. - local player_pos = obj:get_pos() local look_dir_not_normalized = obj:get_look_dir() local look_dir = vector.normalize(look_dir_not_normalized) - local look_pos = vector.new({x = look_dir.x+player_pos.x, y = look_dir.y+player_pos.y + 1.5, z = look_dir.z+player_pos.z}) -- Arbitrary value (1.5) is head level according to player info mod. - -- Cast up to 64 to see if player is looking at enderman. - for n = 1,64,.25 do - local node = minetest.get_node(look_pos) - if node.name ~= "air" then - break - end - if look_pos.x-1enderpos.x and look_pos.y-2.89enderpos.y and look_pos.z-1enderpos.z then + local player_eye_height = obj:get_properties().eye_height + + --skip player if they have no data - log it + if not player_eye_height then + minetest.log("error", "Enderman at location: ".. dump(enderpos).." has indexed a null player!") + else + + --calculate very quickly the exact location the player is looking + --within the distance between the two "heads" (player and enderman) + local look_pos = vector.new(player_pos.x, player_pos.y + player_eye_height, player_pos.z) + local look_pos_base = look_pos + local ender_eye_pos = vector.new(enderpos.x, enderpos.y + 2.75, enderpos.z) + local eye_distance_from_player = vector.distance(ender_eye_pos, look_pos) + look_pos = vector.add(look_pos, vector.multiply(look_dir, eye_distance_from_player)) + + --if looking in general head position, turn hostile + if minetest.line_of_sight(ender_eye_pos, look_pos_base) and vector.distance(look_pos, ender_eye_pos) <= 0.4 then self.provoked = "staring" self.attack = minetest.get_player_by_name(obj:get_player_name()) break - else + else -- I'm not sure what this part does, but I don't want to break anything - jordan4ibanez if self.provoked == "staring" then self.provoked = "broke_contact" - end + end end - look_pos.x = look_pos.x + (.25 * look_dir.x) - look_pos.y = look_pos.y + (.25 * look_dir.y) - look_pos.z = look_pos.z + (.25 * look_dir.z) + end end end @@ -534,9 +544,11 @@ mobs:register_mob("mobs_mc:enderman", { --if (minetest.get_timeofday() * 24000) > 5001 and (minetest.get_timeofday() * 24000) < 19000 then -- self:teleport(nil) --else + if pr:next(1, 8) == 8 then --FIXME: real mc rate self:teleport(hitter) - self.attack=hitter - self.state="attack" + end + self.attack=hitter + self.state="attack" --end end end, @@ -549,11 +561,189 @@ mobs:register_mob("mobs_mc:enderman", { -- End spawn -mobs:spawn_specific("mobs_mc:enderman", mobs_mc.spawn.solid, {"air"}, 0, minetest.LIGHT_MAX+1, 30, 3000, 12, mobs_mc.spawn_height.end_min, mobs_mc.spawn_height.end_max) +mobs:spawn_specific( +"mobs_mc:enderman", +"end", +"ground", +{ +"End" +}, +0, +minetest.LIGHT_MAX+1, +30, +3000, +12, +mobs_mc.spawn_height.end_min, +mobs_mc.spawn_height.end_max) -- Overworld spawn -mobs:spawn_specific("mobs_mc:enderman", mobs_mc.spawn.solid, {"air"}, 0, 7, 30, 19000, 2, mobs_mc.spawn_height.overworld_min, mobs_mc.spawn_height.overworld_max) +mobs:spawn_specific( +"mobs_mc:enderman", +"overworld", +"ground", +{ +"Mesa", +"FlowerForest", +"Swampland", +"Taiga", +"ExtremeHills", +"Jungle", +"Savanna", +"BirchForest", +"MegaSpruceTaiga", +"MegaTaiga", +"ExtremeHills+", +"Forest", +"Plains", +"Desert", +"ColdTaiga", +"MushroomIsland", +"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", +"MushroomIslandShore", +"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", +"MushroomIsland_ocean", +"MegaTaiga_ocean", +"StoneBeach_deep_ocean", +"IcePlainsSpikes_deep_ocean", +"ColdTaiga_ocean", +"SavannaM_ocean", +"MesaPlateauF_deep_ocean", +"MesaBryce_deep_ocean", +"ExtremeHills+_deep_ocean", +"ExtremeHills_ocean", +"MushroomIsland_deep_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", +"MushroomIsland_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, +30, +19000, +2, +mobs_mc.spawn_height.overworld_min, +mobs_mc.spawn_height.overworld_max) + -- Nether spawn (rare) -mobs:spawn_specific("mobs_mc:enderman", mobs_mc.spawn.solid, {"air"}, 0, 7, 30, 27500, 4, mobs_mc.spawn_height.nether_min, mobs_mc.spawn_height.nether_max) +mobs:spawn_specific( +"mobs_mc:enderman", +"nether", +"ground", +{ +"Nether" +}, +0, +7, +30, +27500, +4, +mobs_mc.spawn_height.nether_min, +mobs_mc.spawn_height.nether_max) -- spawn eggs mobs:register_egg("mobs_mc:enderman", S("Enderman"), "mobs_mc_spawn_icon_enderman.png", 0) diff --git a/mods/ENTITIES/mobs_mc/ghast.lua b/mods/ENTITIES/mobs_mc/ghast.lua index 679a28c13d..83a10bfc40 100644 --- a/mods/ENTITIES/mobs_mc/ghast.lua +++ b/mods/ENTITIES/mobs_mc/ghast.lua @@ -63,10 +63,32 @@ mobs:register_mob("mobs_mc:ghast", { makes_footstep_sound = false, instant_death = true, fire_resistant = true, + do_custom = function(self) + if self.firing == true then + self.base_texture = {"mobs_mc_ghast_firing.png"} + self.object:set_properties({textures=self.base_texture}) + else + self.base_texture = {"mobs_mc_ghast.png"} + self.object:set_properties({textures=self.base_texture}) + end + end, }) -mobs:spawn_specific("mobs_mc:ghast", mobs_mc.spawn.nether, {"air"}, 0, minetest.LIGHT_MAX+1, 30, 18000, 2, mobs_mc.spawn_height.nether_min, mobs_mc.spawn_height.nether_max) +mobs:spawn_specific( +"mobs_mc:ghast", +"nether", +"ground", +{ +"Nether" +}, +0, +minetest.LIGHT_MAX+1, +30, +18000, +2, +mobs_mc.spawn_height.nether_min, +mobs_mc.spawn_height.nether_max) -- fireball (projectile) mobs:register_arrow("mobs_mc:fireball", { @@ -74,6 +96,7 @@ mobs:register_arrow("mobs_mc:fireball", { visual_size = {x = 1, y = 1}, textures = {"mcl_fire_fire_charge.png"}, velocity = 15, + collisionbox = {-.5, -.5, -.5, .5, .5, .5}, hit_player = function(self, player) if rawget(_G, "armor") and armor.last_damage_types then diff --git a/mods/ENTITIES/mobs_mc/guardian_elder.lua b/mods/ENTITIES/mobs_mc/guardian_elder.lua index a58a4a5b76..089f6e38f7 100644 --- a/mods/ENTITIES/mobs_mc/guardian_elder.lua +++ b/mods/ENTITIES/mobs_mc/guardian_elder.lua @@ -106,7 +106,7 @@ mobs:register_mob("mobs_mc:guardian_elder", { view_range = 16, }) --- Spawning disabled due to size issues +-- Spawning disabled due to size issues <- what do you mean? -j4i -- TODO: Re-enable spawning -- mobs:spawn_specific("mobs_mc:guardian_elder", mobs_mc.spawn.water, mobs_mc.spawn_water, 0, minetest.LIGHT_MAX+1, 30, 40000, 2, mobs_mc.spawn_height.overworld_min, mobs_mc.spawn_height.water-18) diff --git a/mods/ENTITIES/mobs_mc/horse.lua b/mods/ENTITIES/mobs_mc/horse.lua index 4e588855f4..938a6b6ace 100644 --- a/mods/ENTITIES/mobs_mc/horse.lua +++ b/mods/ENTITIES/mobs_mc/horse.lua @@ -157,8 +157,29 @@ local horse = { self._regentimer = 0 end - -- if driver present allow control of horse - if self.driver then + -- Some weird human is riding. Buck them off? + if self.driver and not self.tamed and self.buck_off_time <= 0 then + if math.random() < 0.2 then + mobs.detach(self.driver, {x = 1, y = 0, z = 1}) + -- TODO bucking animation + else + -- Nah, can't be bothered. Think about it again in one second + self.buck_off_time = 20 + end + end + + -- Tick the timer for trying to buck the player off + if self.buck_off_time then + if self.driver then + self.buck_off_time = self.buck_off_time - 1 + else + -- Player isn't riding anymore so no need to count + self.buck_off_time = nil + end + end + + -- if driver present and horse has a saddle allow control of horse + if self.driver and self._saddle then mobs.drive(self, "walk", "stand", false, dtime) @@ -191,6 +212,49 @@ local horse = { local item = clicker:get_wielded_item() local iname = item:get_name() local heal = 0 + + -- Taming + self.temper = self.temper or (math.random(1,100)) + + if not self.tamed then + local temper_increase = 0 + + -- Feeding, intentionally not using mobs:feed_tame because horse taming is + -- different and more complicated + if (iname == mobs_mc.items.sugar) then + temper_increase = 3 + elseif (iname == mobs_mc.items.wheat) then + temper_increase = 3 + elseif (iname == mobs_mc.items.apple) then + temper_increase = 3 + elseif (iname == mobs_mc.items.golden_carrot) then + temper_increase = 5 + elseif (iname == mobs_mc.items.golden_apple) then + temper_increase = 10 + -- Trying to ride + elseif not self.driver then + self.object:set_properties({stepheight = 1.1}) + mobs.attach(self, clicker) + self.buck_off_time = 40 -- TODO how long does it take in minecraft? + if self.temper > 100 then + self.tamed = true -- NOTE taming can only be finished by riding the horse + if not self.owner or self.owner == "" then + self.owner = clicker:get_player_name() + end + end + temper_increase = 5 + + -- Clicking on the horse while riding ==> unmount + elseif self.driver and self.driver == clicker then + mobs.detach(clicker, {x = 1, y = 0, z = 1}) + end + + -- If nothing happened temper_increase = 0 and addition does nothing + self.temper = self.temper + temper_increase + + return + end + if can_breed(self.name) then -- Breed horse with golden apple or golden carrot if (iname == mobs_mc.items.golden_apple) then @@ -202,7 +266,8 @@ local horse = { return end end - -- Feed/tame with anything else + -- Feed with anything else + -- TODO heal amounts don't work if (iname == mobs_mc.items.sugar) then heal = 1 elseif (iname == mobs_mc.items.wheat) then @@ -212,7 +277,7 @@ local horse = { elseif (iname == mobs_mc.items.hay_bale) then heal = 20 end - if heal > 0 and mobs:feed_tame(self, clicker, heal, false, true) then + if heal > 0 and mobs:feed_tame(self, clicker, heal, false, false) then return end @@ -445,8 +510,56 @@ mobs:register_mob("mobs_mc:mule", mule) --=========================== --Spawn Function -mobs:spawn_specific("mobs_mc:horse", mobs_mc.spawn.grassland_savanna, {"air"}, 0, minetest.LIGHT_MAX+1, 30, 15000, 4, mobs_mc.spawn_height.water+3, mobs_mc.spawn_height.overworld_max) -mobs:spawn_specific("mobs_mc:donkey", mobs_mc.spawn.grassland_savanna, {"air"}, 0, minetest.LIGHT_MAX+1, 30, 15000, 4, mobs_mc.spawn_height.water+3, mobs_mc.spawn_height.overworld_max) +mobs:spawn_specific( +"mobs_mc:horse", +"overworld", +"ground", +{ +"FlowerForest", +"Swampland", +"Taiga", +"ExtremeHills", +"BirchForest", +"MegaSpruceTaiga", +"MegaTaiga", +"ExtremeHills+", +"Forest", +"Plains", +"ColdTaiga", +"SunflowerPlains", +"RoofedForest", +"MesaPlateauFM_grasstop", +"ExtremeHillsM", +"BirchForestM", +}, +0, +minetest.LIGHT_MAX+1, +30, +15000, +4, +mobs_mc.spawn_height.water+3, +mobs_mc.spawn_height.overworld_max) + + +mobs:spawn_specific( +"mobs_mc:donkey", +"overworld", +"ground", +{ +"Mesa", +"MesaPlateauFM_grasstop", +"MesaPlateauF", +"MesaPlateauFM", +"MesaPlateauF_grasstop", +"MesaBryce", +}, +0, +minetest.LIGHT_MAX+1, +30, +15000, +4, +mobs_mc.spawn_height.water+3, +mobs_mc.spawn_height.overworld_max) -- spawn eggs mobs:register_egg("mobs_mc:horse", S("Horse"), "mobs_mc_spawn_icon_horse.png", 0) diff --git a/mods/ENTITIES/mobs_mc/llama.lua b/mods/ENTITIES/mobs_mc/llama.lua index 36d020a656..8ff82b502a 100644 --- a/mods/ENTITIES/mobs_mc/llama.lua +++ b/mods/ENTITIES/mobs_mc/llama.lua @@ -217,7 +217,25 @@ mobs:register_mob("mobs_mc:llama", { }) --spawn -mobs:spawn_specific("mobs_mc:llama", mobs_mc.spawn.savanna, {"air"}, 0, minetest.LIGHT_MAX+1, 30, 15000, 5, mobs_mc.spawn_height.water+15, mobs_mc.spawn_height.overworld_max) +mobs:spawn_specific( +"mobs_mc:llama", +"overworld", +"ground", +{ +"Mesa", +"MesaPlateauFM_grasstop", +"MesaPlateauF", +"MesaPlateauFM", +"MesaPlateauF_grasstop", +"MesaBryce", +}, +0, +minetest.LIGHT_MAX+1, +30, +15000, +5, +mobs_mc.spawn_height.water+15, +mobs_mc.spawn_height.overworld_max) -- spawn eggs mobs:register_egg("mobs_mc:llama", S("Llama"), "mobs_mc_spawn_icon_llama.png", 0) diff --git a/mods/ENTITIES/mobs_mc/ocelot.lua b/mods/ENTITIES/mobs_mc/ocelot.lua index eca74d3ba5..f3c8c87ae1 100644 --- a/mods/ENTITIES/mobs_mc/ocelot.lua +++ b/mods/ENTITIES/mobs_mc/ocelot.lua @@ -152,6 +152,25 @@ mobs:register_mob("mobs_mc:cat", cat) local base_spawn_chance = 5000 -- Spawn ocelot +--they get the same as the llama because I'm trying to rework so much of this code right now -j4i +mobs:spawn_specific( +"mobs_mc:ocelot", +"overworld", +"ground", +{ +"Jungle", +"JungleEdgeM", +"JungleM", +"JungleEdge", +}, +0, +minetest.LIGHT_MAX+1, +30, +15000, +5, +mobs_mc.spawn_height.water+15, +mobs_mc.spawn_height.overworld_max) +--[[ mobs:spawn({ name = "mobs_mc:ocelot", nodes = mobs_mc.spawn.jungle, @@ -163,8 +182,8 @@ mobs:spawn({ min_height = mobs_mc.spawn_height.water+1, -- Right above ocean level max_height = mobs_mc.spawn_height.overworld_max, on_spawn = function(self, pos) - --[[ Note: Minecraft has a 1/3 spawn failure rate. - In this mod it is emulated by reducing the spawn rate accordingly (see above). ]] + Note: Minecraft has a 1/3 spawn failure rate. + In this mod it is emulated by reducing the spawn rate accordingly (see above). -- 1/7 chance to spawn 2 ocelot kittens if pr:next(1,7) == 1 then @@ -207,6 +226,7 @@ mobs:spawn({ end end, }) +]]-- -- spawn eggs -- FIXME: The spawn icon shows a cat texture, not an ocelot texture diff --git a/mods/ENTITIES/mobs_mc/parrot.lua b/mods/ENTITIES/mobs_mc/parrot.lua index 407cb44667..5efcb191b4 100644 --- a/mods/ENTITIES/mobs_mc/parrot.lua +++ b/mods/ENTITIES/mobs_mc/parrot.lua @@ -90,8 +90,24 @@ mobs:register_mob("mobs_mc:parrot", { }) --- Parrots spawn rarely in jungles. TODO: Also check for jungle *biome* -mobs:spawn_specific("mobs_mc:parrot", {"mcl_core:jungletree", "mcl_core:jungleleaves"}, {"air"}, 0, minetest.LIGHT_MAX+1, 7, 30000, 1, mobs_mc.spawn_height.water+7, mobs_mc.spawn_height.overworld_max) +-- Parrots spawn rarely in jungles. TODO: Also check for jungle *biome* <- I'll get to this eventually -j4i +mobs:spawn_specific( +"mobs_mc:parrot", +"overworld", +"ground", +{ +"Jungle", +"JungleEdgeM", +"JungleM", +"JungleEdge", +}, +0, +minetest.LIGHT_MAX+1, +7, +30000, +1, +mobs_mc.spawn_height.water+7, +mobs_mc.spawn_height.overworld_max) -- spawn eggs mobs:register_egg("mobs_mc:parrot", S("Parrot"), "mobs_mc_spawn_icon_parrot.png", 0) diff --git a/mods/ENTITIES/mobs_mc/pig.lua b/mods/ENTITIES/mobs_mc/pig.lua index 38700b6ca7..b7cdf1afe9 100644 --- a/mods/ENTITIES/mobs_mc/pig.lua +++ b/mods/ENTITIES/mobs_mc/pig.lua @@ -182,7 +182,35 @@ mobs:register_mob("mobs_mc:pig", { end, }) -mobs:spawn_specific("mobs_mc:pig", mobs_mc.spawn.grassland, {"air"}, 9, minetest.LIGHT_MAX+1, 30, 15000, 8, mobs_mc.spawn_height.overworld_min, mobs_mc.spawn_height.overworld_max) +mobs:spawn_specific( +"mobs_mc:pig", +"overworld", +"ground", +{ +"FlowerForest", +"Swampland", +"Taiga", +"ExtremeHills", +"BirchForest", +"MegaSpruceTaiga", +"MegaTaiga", +"ExtremeHills+", +"Forest", +"Plains", +"ColdTaiga", +"SunflowerPlains", +"RoofedForest", +"MesaPlateauFM_grasstop", +"ExtremeHillsM", +"BirchForestM", +}, +9, +minetest.LIGHT_MAX+1, +30, +15000, +8, +mobs_mc.spawn_height.overworld_min, +mobs_mc.spawn_height.overworld_max) -- spawn eggs mobs:register_egg("mobs_mc:pig", S("Pig"), "mobs_mc_spawn_icon_pig.png", 0) diff --git a/mods/ENTITIES/mobs_mc/polar_bear.lua b/mods/ENTITIES/mobs_mc/polar_bear.lua index 459ca29b4a..5d2853f6d2 100644 --- a/mods/ENTITIES/mobs_mc/polar_bear.lua +++ b/mods/ENTITIES/mobs_mc/polar_bear.lua @@ -67,7 +67,23 @@ mobs:register_mob("mobs_mc:polar_bear", { }) -mobs:spawn_specific("mobs_mc:polar_bear", mobs_mc.spawn.snow, {"air"}, 0, minetest.LIGHT_MAX+1, 30, 7000, 3, mobs_mc.spawn_height.overworld_min, mobs_mc.spawn_height.overworld_max) +mobs:spawn_specific( +"mobs_mc:polar_bear", +"overworld", +"ground", +{ +"ColdTaiga", +"IcePlainsSpikes", +"IcePlains", +"ExtremeHills+_snowtop", +}, +0, +minetest.LIGHT_MAX+1, +30, +7000, +3, +mobs_mc.spawn_height.overworld_min, +mobs_mc.spawn_height.overworld_max) -- spawn egg mobs:register_egg("mobs_mc:polar_bear", S("Polar Bear"), "mobs_mc_spawn_icon_polarbear.png", 0) diff --git a/mods/ENTITIES/mobs_mc/rabbit.lua b/mods/ENTITIES/mobs_mc/rabbit.lua index e167649f6f..74bdffcd80 100644 --- a/mods/ENTITIES/mobs_mc/rabbit.lua +++ b/mods/ENTITIES/mobs_mc/rabbit.lua @@ -107,8 +107,39 @@ end mobs:register_mob("mobs_mc:killer_bunny", killer_bunny) -- Mob spawning rules. --- Different skins depending on spawn location +-- Different skins depending on spawn location <- we'll get to this when the spawning algorithm is fleshed out +mobs:spawn_specific( +"mobs_mc:rabbit", +"overworld", +"ground", +{ +"FlowerForest", +"Swampland", +"Taiga", +"ExtremeHills", +"BirchForest", +"MegaSpruceTaiga", +"MegaTaiga", +"ExtremeHills+", +"Forest", +"Plains", +"ColdTaiga", +"SunflowerPlains", +"RoofedForest", +"MesaPlateauFM_grasstop", +"ExtremeHillsM", +"BirchForestM", +}, +9, +minetest.LIGHT_MAX+1, +30, +15000, +8, +mobs_mc.spawn_height.overworld_min, +mobs_mc.spawn_height.overworld_max) + +--[[ local spawn = { name = "mobs_mc:rabbit", neighbors = {"air"}, @@ -165,6 +196,7 @@ spawn_grass.on_spawn = function(self, pos) self.object:set_properties({textures = self.base_texture}) end mobs:spawn(spawn_grass) +]]-- -- Spawn egg mobs:register_egg("mobs_mc:rabbit", S("Rabbit"), "mobs_mc_spawn_icon_rabbit.png", 0) diff --git a/mods/ENTITIES/mobs_mc/sheep.lua b/mods/ENTITIES/mobs_mc/sheep.lua index 84650b4ddd..d82df8cf9d 100644 --- a/mods/ENTITIES/mobs_mc/sheep.lua +++ b/mods/ENTITIES/mobs_mc/sheep.lua @@ -303,7 +303,35 @@ mobs:register_mob("mobs_mc:sheep", { end end, }) -mobs:spawn_specific("mobs_mc:sheep", mobs_mc.spawn.grassland, {"air"}, 0, minetest.LIGHT_MAX+1, 30, 15000, 3, mobs_mc.spawn_height.overworld_min, mobs_mc.spawn_height.overworld_max) +mobs:spawn_specific( +"mobs_mc:sheep", +"overworld", +"ground", +{ +"FlowerForest", +"Swampland", +"Taiga", +"ExtremeHills", +"BirchForest", +"MegaSpruceTaiga", +"MegaTaiga", +"ExtremeHills+", +"Forest", +"Plains", +"ColdTaiga", +"SunflowerPlains", +"RoofedForest", +"MesaPlateauFM_grasstop", +"ExtremeHillsM", +"BirchForestM", +}, +0, +minetest.LIGHT_MAX+1, +30, +15000, +3, +mobs_mc.spawn_height.overworld_min, +mobs_mc.spawn_height.overworld_max) -- spawn eggs mobs:register_egg("mobs_mc:sheep", S("Sheep"), "mobs_mc_spawn_icon_sheep.png", 0) diff --git a/mods/ENTITIES/mobs_mc/shulker.lua b/mods/ENTITIES/mobs_mc/shulker.lua index faaf2ac405..8000d0937b 100644 --- a/mods/ENTITIES/mobs_mc/shulker.lua +++ b/mods/ENTITIES/mobs_mc/shulker.lua @@ -81,4 +81,17 @@ mobs:register_arrow("mobs_mc:shulkerbullet", { mobs:register_egg("mobs_mc:shulker", S("Shulker"), "mobs_mc_spawn_icon_shulker.png", 0) -mobs:spawn_specific("mobs_mc:shulker", mobs_mc.spawn.end_city, {"air"}, 0, minetest.LIGHT_MAX+1, 30, 5000, 2, mobs_mc.spawn_height.end_min, mobs_mc.spawn_height.end_max) +mobs:spawn_specific( +"mobs_mc:shulker", +"end", +"ground", +{ +"End" +}, +0, +minetest.LIGHT_MAX+1, +30, +5000, +2, +mobs_mc.spawn_height.end_min, +mobs_mc.spawn_height.end_max) diff --git a/mods/ENTITIES/mobs_mc/skeleton+stray.lua b/mods/ENTITIES/mobs_mc/skeleton+stray.lua index cb12e905d5..b43873b2aa 100644 --- a/mods/ENTITIES/mobs_mc/skeleton+stray.lua +++ b/mods/ENTITIES/mobs_mc/skeleton+stray.lua @@ -139,13 +139,195 @@ table.insert(stray.drops, { mobs:register_mob("mobs_mc:stray", stray) -- Overworld spawn -mobs:spawn_specific("mobs_mc:skeleton", mobs_mc.spawn.solid, {"air"}, 0, 7, 20, 17000, 2, mobs_mc.spawn_height.overworld_min, mobs_mc.spawn_height.overworld_max) +mobs:spawn_specific( +"mobs_mc:skeleton", +"overworld", +"ground", +{ +"Mesa", +"FlowerForest", +"Swampland", +"Taiga", +"ExtremeHills", +"Jungle", +"Savanna", +"BirchForest", +"MegaSpruceTaiga", +"MegaTaiga", +"ExtremeHills+", +"Forest", +"Plains", +"Desert", +"ColdTaiga", +"MushroomIsland", +"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", +"MushroomIslandShore", +"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", +"MushroomIsland_ocean", +"MegaTaiga_ocean", +"StoneBeach_deep_ocean", +"IcePlainsSpikes_deep_ocean", +"ColdTaiga_ocean", +"SavannaM_ocean", +"MesaPlateauF_deep_ocean", +"MesaBryce_deep_ocean", +"ExtremeHills+_deep_ocean", +"ExtremeHills_ocean", +"MushroomIsland_deep_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", +"MushroomIsland_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, +17000, +2, +mobs_mc.spawn_height.overworld_min, +mobs_mc.spawn_height.overworld_max) + + -- Nether spawn -mobs:spawn_specific("mobs_mc:skeleton", mobs_mc.spawn.nether_fortress, {"air"}, 0, 7, 30, 10000, 3, mobs_mc.spawn_height.nether_min, mobs_mc.spawn_height.nether_max) +mobs:spawn_specific( +"mobs_mc:skeleton", +"nether", +"ground", +{ +"Nether" +}, +0, +7, +30, +10000, +3, +mobs_mc.spawn_height.nether_min, +mobs_mc.spawn_height.nether_max) -- Stray spawn -- TODO: Spawn directly under the sky -mobs:spawn_specific("mobs_mc:stray", mobs_mc.spawn.snow, {"air"}, 0, 7, 20, 19000, 2, mobs_mc.spawn_height.water, mobs_mc.spawn_height.overworld_max) +mobs:spawn_specific( +"mobs_mc:stray", +"overworld", +"ground", +{ +"ColdTaiga", +"IcePlainsSpikes", +"IcePlains", +"ExtremeHills+_snowtop", +}, +0, +7, +20, +19000, +2, +mobs_mc.spawn_height.water, +mobs_mc.spawn_height.overworld_max) -- spawn eggs diff --git a/mods/ENTITIES/mobs_mc/skeleton_wither.lua b/mods/ENTITIES/mobs_mc/skeleton_wither.lua index e4a1f86fc6..da472d6057 100644 --- a/mods/ENTITIES/mobs_mc/skeleton_wither.lua +++ b/mods/ENTITIES/mobs_mc/skeleton_wither.lua @@ -94,7 +94,20 @@ mobs:register_mob("mobs_mc:witherskeleton", { }) --spawn -mobs:spawn_specific("mobs_mc:witherskeleton", mobs_mc.spawn.nether_fortress, {"air"}, 0, 7, 30, 5000, 5, mobs_mc.spawn_height.nether_min, mobs_mc.spawn_height.nether_max) +mobs:spawn_specific( +"mobs_mc:witherskeleton", +"nether", +"ground", +{ +"Nether" +}, +0, +7, +30, +5000, +5, +mobs_mc.spawn_height.nether_min, +mobs_mc.spawn_height.nether_max) -- spawn eggs -mobs:register_egg("mobs_mc:witherskeleton", S("Wither Skeleton"), "mobs_mc_spawn_icon_witherskeleton.png", 0) +mobs:register_egg("mobs_mc:witherskeleton", S("Wither Skeleton"), "mobs_mc_spawn_icon_witherskeleton.png", 0) \ No newline at end of file diff --git a/mods/ENTITIES/mobs_mc/slime+magma_cube.lua b/mods/ENTITIES/mobs_mc/slime+magma_cube.lua index 7c21fb8124..6c8000a50d 100644 --- a/mods/ENTITIES/mobs_mc/slime+magma_cube.lua +++ b/mods/ENTITIES/mobs_mc/slime+magma_cube.lua @@ -51,7 +51,6 @@ local spawn_children_on_die = function(child_mob, children_count, spawn_distance end end, children, self.attack) end - return true end end @@ -158,9 +157,137 @@ mobs:register_mob("mobs_mc:slime_tiny", slime_tiny) local smin = mobs_mc.spawn_height.overworld_min local smax = mobs_mc.spawn_height.water - 23 -mobs:spawn_specific("mobs_mc:slime_tiny", mobs_mc.spawn.solid, {"air"}, 0, minetest.LIGHT_MAX+1, 30, 12000, 4, smin, smax) -mobs:spawn_specific("mobs_mc:slime_small", mobs_mc.spawn.solid, {"air"}, 0, minetest.LIGHT_MAX+1, 30, 8500, 4, smin, smax) -mobs:spawn_specific("mobs_mc:slime_big", mobs_mc.spawn.solid, {"air"}, 0, minetest.LIGHT_MAX+1, 30, 10000, 4, smin, smax) +mobs:spawn_specific( +"mobs_mc:slime_tiny", +"overworld", +"ground", +{ +"FlowerForest_underground", +"JungleEdge_underground", +"StoneBeach_underground", +"MesaBryce_underground", +"Mesa_underground", +"RoofedForest_underground", +"Jungle_underground", +"Swampland_underground", +"MushroomIsland_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, +minetest.LIGHT_MAX+1, +30, +12000, +4, +smin, +smax) + +mobs:spawn_specific( +"mobs_mc:slime_small", +"overworld", +"ground", +{ +"FlowerForest_underground", +"JungleEdge_underground", +"StoneBeach_underground", +"MesaBryce_underground", +"Mesa_underground", +"RoofedForest_underground", +"Jungle_underground", +"Swampland_underground", +"MushroomIsland_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, +minetest.LIGHT_MAX+1, +30, +8500, +4, +smin, +smax) + +mobs:spawn_specific( +"mobs_mc:slime_big", +"overworld", +"ground", +{ +"FlowerForest_underground", +"JungleEdge_underground", +"StoneBeach_underground", +"MesaBryce_underground", +"Mesa_underground", +"RoofedForest_underground", +"Jungle_underground", +"Swampland_underground", +"MushroomIsland_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, +minetest.LIGHT_MAX+1, +30, +10000, +4, +smin, +smax) -- Magma cube local magma_cube_big = { @@ -273,13 +400,55 @@ mobs:register_mob("mobs_mc:magma_cube_tiny", magma_cube_tiny) local mmin = mobs_mc.spawn_height.nether_min local mmax = mobs_mc.spawn_height.nether_max -mobs:spawn_specific("mobs_mc:magma_cube_tiny", mobs_mc.spawn.nether, {"air"}, 0, minetest.LIGHT_MAX+1, 30, 15000, 4, mmin, mmax) -mobs:spawn_specific("mobs_mc:magma_cube_small", mobs_mc.spawn.nether, {"air"}, 0, minetest.LIGHT_MAX+1, 30, 15500, 4, mmin, mmax) -mobs:spawn_specific("mobs_mc:magma_cube_big", mobs_mc.spawn.nether, {"air"}, 0, minetest.LIGHT_MAX+1, 30, 16000, 4, mmin, mmax) +mobs:spawn_specific( +"mobs_mc:magma_cube_tiny", +"nether", +"ground", +{ +"Nether" +}, +0, +minetest.LIGHT_MAX+1, +30, +15000, +4, +mmin, +mmax) -mobs:spawn_specific("mobs_mc:magma_cube_tiny", mobs_mc.spawn.nether_fortress, {"air"}, 0, minetest.LIGHT_MAX+1, 30, 11000, 4, mmin, mmax) -mobs:spawn_specific("mobs_mc:magma_cube_small", mobs_mc.spawn.nether_fortress, {"air"}, 0, minetest.LIGHT_MAX+1, 30, 11100, 4, mmin, mmax) -mobs:spawn_specific("mobs_mc:magma_cube_big", mobs_mc.spawn.nether_fortress, {"air"}, 0, minetest.LIGHT_MAX+1, 30, 11200, 4, mmin, mmax) + +mobs:spawn_specific( +"mobs_mc:magma_cube_small", +"nether", +"ground", +{ +"Nether" +}, +0, +minetest.LIGHT_MAX+1, +30, +15500, +4, +mmin, +mmax) + +mobs:spawn_specific( +"mobs_mc:magma_cube_big", +"nether", +"ground", +{ +"Nether" +}, +0, +minetest.LIGHT_MAX+1, +30, +16000, +4, +mmin, +mmax) + +--mobs:spawn_specific("mobs_mc:magma_cube_tiny", mobs_mc.spawn.nether_fortress, {"air"}, 0, minetest.LIGHT_MAX+1, 30, 11000, 4, mmin, mmax) +--mobs:spawn_specific("mobs_mc:magma_cube_small", mobs_mc.spawn.nether_fortress, {"air"}, 0, minetest.LIGHT_MAX+1, 30, 11100, 4, mmin, mmax) +--mobs:spawn_specific("mobs_mc:magma_cube_big", mobs_mc.spawn.nether_fortress, {"air"}, 0, minetest.LIGHT_MAX+1, 30, 11200, 4, mmin, mmax) -- spawn eggs diff --git a/mods/ENTITIES/mobs_mc/spider.lua b/mods/ENTITIES/mobs_mc/spider.lua index 0bb03a9c7c..bb5e29eb1f 100644 --- a/mods/ENTITIES/mobs_mc/spider.lua +++ b/mods/ENTITIES/mobs_mc/spider.lua @@ -87,7 +87,158 @@ cave_spider.sounds.base_pitch = 1.25 mobs:register_mob("mobs_mc:cave_spider", cave_spider) -mobs:spawn_specific("mobs_mc:spider", mobs_mc.spawn.solid, {"air"}, 0, 7, 30, 17000, 2, mobs_mc.spawn_height.overworld_min, mobs_mc.spawn_height.overworld_max) +mobs:spawn_specific( +"mobs_mc:spider", +"overworld", +"ground", +{ +"Mesa", +"FlowerForest", +"Swampland", +"Taiga", +"ExtremeHills", +"Jungle", +"Savanna", +"BirchForest", +"MegaSpruceTaiga", +"MegaTaiga", +"ExtremeHills+", +"Forest", +"Plains", +"Desert", +"ColdTaiga", +"MushroomIsland", +"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", +"MushroomIslandShore", +"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", +"MushroomIsland_ocean", +"MegaTaiga_ocean", +"StoneBeach_deep_ocean", +"IcePlainsSpikes_deep_ocean", +"ColdTaiga_ocean", +"SavannaM_ocean", +"MesaPlateauF_deep_ocean", +"MesaBryce_deep_ocean", +"ExtremeHills+_deep_ocean", +"ExtremeHills_ocean", +"MushroomIsland_deep_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", +"MushroomIsland_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, +30, +17000, +2, +mobs_mc.spawn_height.overworld_min, +mobs_mc.spawn_height.overworld_max) -- spawn eggs mobs:register_egg("mobs_mc:spider", S("Spider"), "mobs_mc_spawn_icon_spider.png", 0) diff --git a/mods/ENTITIES/mobs_mc/squid.lua b/mods/ENTITIES/mobs_mc/squid.lua index 1877a2104c..cf794ea5bf 100644 --- a/mods/ENTITIES/mobs_mc/squid.lua +++ b/mods/ENTITIES/mobs_mc/squid.lua @@ -62,7 +62,158 @@ mobs:register_mob("mobs_mc:squid", { local water = mobs_mc.spawn_height.water --name, nodes, neighbours, minlight, maxlight, interval, chance, active_object_count, min_height, max_height -mobs:spawn_specific("mobs_mc:squid", mobs_mc.spawn.water, {mobs_mc.items.water_source}, 0, minetest.LIGHT_MAX+1, 30, 5500, 3, water-16, water) +mobs:spawn_specific( +"mobs_mc:squid", +"overworld", +"water", +{ +"Mesa", +"FlowerForest", +"Swampland", +"Taiga", +"ExtremeHills", +"Jungle", +"Savanna", +"BirchForest", +"MegaSpruceTaiga", +"MegaTaiga", +"ExtremeHills+", +"Forest", +"Plains", +"Desert", +"ColdTaiga", +"MushroomIsland", +"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", +"MushroomIslandShore", +"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", +"MushroomIsland_ocean", +"MegaTaiga_ocean", +"StoneBeach_deep_ocean", +"IcePlainsSpikes_deep_ocean", +"ColdTaiga_ocean", +"SavannaM_ocean", +"MesaPlateauF_deep_ocean", +"MesaBryce_deep_ocean", +"ExtremeHills+_deep_ocean", +"ExtremeHills_ocean", +"MushroomIsland_deep_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", +"MushroomIsland_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, +minetest.LIGHT_MAX+1, +30, +5500, +3, +water-16, +water+1) -- spawn eggs mobs:register_egg("mobs_mc:squid", S("Squid"), "mobs_mc_spawn_icon_squid.png", 0) diff --git a/mods/ENTITIES/mobs_mc/textures/mobs_mc_ghast_firing.png b/mods/ENTITIES/mobs_mc/textures/mobs_mc_ghast_firing.png new file mode 100644 index 0000000000..3e5b41c327 Binary files /dev/null and b/mods/ENTITIES/mobs_mc/textures/mobs_mc_ghast_firing.png differ diff --git a/mods/ENTITIES/mobs_mc/villager.lua b/mods/ENTITIES/mobs_mc/villager.lua index 68644266f4..d251ba8239 100644 --- a/mods/ENTITIES/mobs_mc/villager.lua +++ b/mods/ENTITIES/mobs_mc/villager.lua @@ -1074,7 +1074,35 @@ mobs:register_mob("mobs_mc:villager", { -mobs:spawn_specific("mobs_mc:villager", mobs_mc.spawn.village, {"air"}, 0, minetest.LIGHT_MAX+1, 30, 20, 4, mobs_mc.spawn_height.water+1, mobs_mc.spawn_height.overworld_max) +mobs:spawn_specific( +"mobs_mc:villager", +"overworld", +"ground", +{ +"FlowerForest", +"Swampland", +"Taiga", +"ExtremeHills", +"BirchForest", +"MegaSpruceTaiga", +"MegaTaiga", +"ExtremeHills+", +"Forest", +"Plains", +"ColdTaiga", +"SunflowerPlains", +"RoofedForest", +"MesaPlateauFM_grasstop", +"ExtremeHillsM", +"BirchForestM", +}, +0, +minetest.LIGHT_MAX+1, +30, +20, +4, +mobs_mc.spawn_height.water+1, +mobs_mc.spawn_height.overworld_max) -- spawn eggs mobs:register_egg("mobs_mc:villager", S("Villager"), "mobs_mc_spawn_icon_villager.png", 0) diff --git a/mods/ENTITIES/mobs_mc/villager_zombie.lua b/mods/ENTITIES/mobs_mc/villager_zombie.lua index 09539fa76e..325cf5955b 100644 --- a/mods/ENTITIES/mobs_mc/villager_zombie.lua +++ b/mods/ENTITIES/mobs_mc/villager_zombie.lua @@ -146,8 +146,99 @@ mobs:register_mob("mobs_mc:villager_zombie", { harmed_by_heal = true, }) -mobs:spawn_specific("mobs_mc:villager_zombie", mobs_mc.spawn.village, {"air"}, 0, 7, 30, 4090, 4, mobs_mc.spawn_height.overworld_min, mobs_mc.spawn_height.overworld_max) -mobs:spawn_specific("mobs_mc:villager_zombie", mobs_mc.spawn.solid, {"air"}, 0, 7, 30, 60000, 4, mobs_mc.spawn_height.overworld_min, mobs_mc.spawn_height.overworld_max) +mobs:spawn_specific( +"mobs_mc:villager_zombie", +"overworld", +"ground", +{ +"FlowerForest_underground", +"JungleEdge_underground", +"StoneBeach_underground", +"MesaBryce_underground", +"Mesa_underground", +"RoofedForest_underground", +"Jungle_underground", +"Swampland_underground", +"MushroomIsland_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", +"Mesa", +"FlowerForest", +"Swampland", +"Taiga", +"ExtremeHills", +"Jungle", +"Savanna", +"BirchForest", +"MegaSpruceTaiga", +"MegaTaiga", +"ExtremeHills+", +"Forest", +"Plains", +"Desert", +"ColdTaiga", +"MushroomIsland", +"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", +"MushroomIslandShore", +"JungleM_shore", +"Jungle_shore", +"MesaPlateauFM_sandlevel", +"MesaPlateauF_sandlevel", +"MesaBryce_sandlevel", +"Mesa_sandlevel", +}, +0, +7, +30, +4090, +4, +mobs_mc.spawn_height.overworld_min, +mobs_mc.spawn_height.overworld_max) +--mobs:spawn_specific("mobs_mc:villager_zombie", "overworld", "ground", 0, 7, 30, 60000, 4, mobs_mc.spawn_height.overworld_min, mobs_mc.spawn_height.overworld_max) -- spawn eggs mobs:register_egg("mobs_mc:villager_zombie", S("Zombie Villager"), "mobs_mc_spawn_icon_zombie_villager.png", 0) diff --git a/mods/ENTITIES/mobs_mc/witch.lua b/mods/ENTITIES/mobs_mc/witch.lua index 383cbd36fe..f9f9b8d1f0 100644 --- a/mods/ENTITIES/mobs_mc/witch.lua +++ b/mods/ENTITIES/mobs_mc/witch.lua @@ -99,7 +99,7 @@ mobs:register_arrow("mobs_mc:potion_arrow", { end }) --- TODO: Spawn when witch works properly +-- TODO: Spawn when witch works properly <- eventually -j4i --mobs:spawn_specific("mobs_mc:witch", mobs_mc.spawn.jungle, {"air"}, 0, minetest.LIGHT_MAX-6, 12, 20000, 2, mobs_mc.spawn_height.water-6, mobs_mc.spawn_height.overworld_max) -- spawn eggs diff --git a/mods/ENTITIES/mobs_mc/wither.lua b/mods/ENTITIES/mobs_mc/wither.lua index caf5a248d3..2d53cc547f 100644 --- a/mods/ENTITIES/mobs_mc/wither.lua +++ b/mods/ENTITIES/mobs_mc/wither.lua @@ -73,6 +73,7 @@ mobs:register_mob("mobs_mc:wither", { self.object:set_properties({textures={self.base_texture}}) self.armor = {undead = 80, fleshy = 80} end + mcl_bossbars.update_boss(self.object, "Wither", "dark_purple") end, on_spawn = function(self) minetest.sound_play("mobs_mc_wither_spawn", {object=self.object, gain=1.0, max_hear_distance=64}) @@ -115,4 +116,4 @@ mobs:register_arrow("mobs_mc:wither_skull", { --Spawn egg mobs:register_egg("mobs_mc:wither", S("Wither"), "mobs_mc_spawn_icon_wither.png", 0, true) -mcl_wip.register_wip_item("mobs_mc:wither") \ No newline at end of file +mcl_wip.register_wip_item("mobs_mc:wither") diff --git a/mods/ENTITIES/mobs_mc/wolf.lua b/mods/ENTITIES/mobs_mc/wolf.lua index fe30318954..b1c077d465 100644 --- a/mods/ENTITIES/mobs_mc/wolf.lua +++ b/mods/ENTITIES/mobs_mc/wolf.lua @@ -232,6 +232,34 @@ end mobs:register_mob("mobs_mc:dog", dog) -- Spawn -mobs:spawn_specific("mobs_mc:wolf", mobs_mc.spawn.wolf, {"air"}, 0, minetest.LIGHT_MAX+1, 30, 9000, 7, mobs_mc.spawn_height.water+3, mobs_mc.spawn_height.overworld_max) +mobs:spawn_specific( +"mobs_mc:wolf", +"overworld", +"ground", +{ +"FlowerForest", +"Swampland", +"Taiga", +"ExtremeHills", +"BirchForest", +"MegaSpruceTaiga", +"MegaTaiga", +"ExtremeHills+", +"Forest", +"Plains", +"ColdTaiga", +"SunflowerPlains", +"RoofedForest", +"MesaPlateauFM_grasstop", +"ExtremeHillsM", +"BirchForestM", +}, +0, +minetest.LIGHT_MAX+1, +30, +9000, +7, +mobs_mc.spawn_height.water+3, +mobs_mc.spawn_height.overworld_max) mobs:register_egg("mobs_mc:wolf", S("Wolf"), "mobs_mc_spawn_icon_wolf.png", 0) diff --git a/mods/ENTITIES/mobs_mc/zombie.lua b/mods/ENTITIES/mobs_mc/zombie.lua index df9727d34f..fed83f233a 100644 --- a/mods/ENTITIES/mobs_mc/zombie.lua +++ b/mods/ENTITIES/mobs_mc/zombie.lua @@ -135,11 +135,227 @@ mobs:register_mob("mobs_mc:baby_husk", baby_husk) -- Spawning -mobs:spawn_specific("mobs_mc:zombie", mobs_mc.spawn.solid, {"air"}, 0, 7, 30, 6000, 4, mobs_mc.spawn_height.overworld_min, mobs_mc.spawn_height.overworld_max) +mobs:spawn_specific( +"mobs_mc:zombie", +"overworld", +"ground", +{ +"FlowerForest_underground", +"JungleEdge_underground", +"StoneBeach_underground", +"MesaBryce_underground", +"Mesa_underground", +"RoofedForest_underground", +"Jungle_underground", +"Swampland_underground", +"MushroomIsland_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", +"Mesa", +"FlowerForest", +"Swampland", +"Taiga", +"ExtremeHills", +"Jungle", +"Savanna", +"BirchForest", +"MegaSpruceTaiga", +"MegaTaiga", +"ExtremeHills+", +"Forest", +"Plains", +"Desert", +"ColdTaiga", +"MushroomIsland", +"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", +"MushroomIslandShore", +"JungleM_shore", +"Jungle_shore", +"MesaPlateauFM_sandlevel", +"MesaPlateauF_sandlevel", +"MesaBryce_sandlevel", +"Mesa_sandlevel", +}, +0, +7, +30, +6000, +4, +mobs_mc.spawn_height.overworld_min, +mobs_mc.spawn_height.overworld_max) -- Baby zombie is 20 times less likely than regular zombies -mobs:spawn_specific("mobs_mc:baby_zombie", mobs_mc.spawn.solid, {"air"}, 0, 7, 30, 60000, 4, mobs_mc.spawn_height.overworld_min, mobs_mc.spawn_height.overworld_max) -mobs:spawn_specific("mobs_mc:husk", mobs_mc.spawn.desert, {"air"}, 0, 7, 30, 6500, 4, mobs_mc.spawn_height.overworld_min, mobs_mc.spawn_height.overworld_max) -mobs:spawn_specific("mobs_mc:baby_husk", mobs_mc.spawn.desert, {"air"}, 0, 7, 30, 65000, 4, mobs_mc.spawn_height.overworld_min, mobs_mc.spawn_height.overworld_max) +mobs:spawn_specific( +"mobs_mc:baby_zombie", +"overworld", +"ground", +{ +"FlowerForest_underground", +"JungleEdge_underground", +"StoneBeach_underground", +"MesaBryce_underground", +"Mesa_underground", +"RoofedForest_underground", +"Jungle_underground", +"Swampland_underground", +"MushroomIsland_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", +"Mesa", +"FlowerForest", +"Swampland", +"Taiga", +"ExtremeHills", +"Jungle", +"Savanna", +"BirchForest", +"MegaSpruceTaiga", +"MegaTaiga", +"ExtremeHills+", +"Forest", +"Plains", +"Desert", +"ColdTaiga", +"MushroomIsland", +"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", +"MushroomIslandShore", +"JungleM_shore", +"Jungle_shore", +"MesaPlateauFM_sandlevel", +"MesaPlateauF_sandlevel", +"MesaBryce_sandlevel", +"Mesa_sandlevel", +}, +0, +7, +30, +60000, +4, +mobs_mc.spawn_height.overworld_min, +mobs_mc.spawn_height.overworld_max) + + +mobs:spawn_specific( +"mobs_mc:husk", +"overworld", +"ground", +{ +"Desert", +"SavannaM", +"Savanna", +"Savanna_beach", +}, +0, +7, +30, +6500, +4, +mobs_mc.spawn_height.overworld_min, +mobs_mc.spawn_height.overworld_max) +mobs:spawn_specific( +"mobs_mc:baby_husk", +"overworld", +"ground", +{ +"Desert", +"SavannaM", +"Savanna", +"Savanna_beach", +}, +0, +7, +30, +65000, +4, +mobs_mc.spawn_height.overworld_min, +mobs_mc.spawn_height.overworld_max) -- Spawn eggs mobs:register_egg("mobs_mc:husk", S("Husk"), "mobs_mc_spawn_icon_husk.png", 0) diff --git a/mods/ENTITIES/mobs_mc/zombiepig.lua b/mods/ENTITIES/mobs_mc/zombiepig.lua index 8c29a4bff7..ebd8ce4856 100644 --- a/mods/ENTITIES/mobs_mc/zombiepig.lua +++ b/mods/ENTITIES/mobs_mc/zombiepig.lua @@ -111,12 +111,38 @@ baby_pigman.child = 1 mobs:register_mob("mobs_mc:baby_pigman", baby_pigman) -- Regular spawning in the Nether -mobs:spawn_specific("mobs_mc:pigman", mobs_mc.spawn.solid, {"air"}, 0, minetest.LIGHT_MAX+1, 30, 6000, 3, mobs_mc.spawn_height.nether_min, mobs_mc.spawn_height.nether_max) +mobs:spawn_specific( +"mobs_mc:pigman", +"nether", +"ground", +{ +"Nether" +}, +0, +minetest.LIGHT_MAX+1, +30, +6000, +3, +mobs_mc.spawn_height.nether_min, +mobs_mc.spawn_height.nether_max) -- Baby zombie is 20 times less likely than regular zombies -mobs:spawn_specific("mobs_mc:baby_pigman", mobs_mc.spawn.solid, {"air"}, 0, minetest.LIGHT_MAX+1, 30, 100000, 4, mobs_mc.spawn_height.nether_min, mobs_mc.spawn_height.nether_max) +mobs:spawn_specific( +"mobs_mc:baby_pigman", +"nether", +"ground", +{ +"Nether" +}, +0, +minetest.LIGHT_MAX+1, +30, +100000, +4, +mobs_mc.spawn_height.nether_min, +mobs_mc.spawn_height.nether_max) -- Spawning in Nether portals in the Overworld -mobs:spawn_specific("mobs_mc:pigman", mobs_mc.spawn.nether_portal, {"air"}, 0, minetest.LIGHT_MAX+1, 30, 500, 4, mobs_mc.spawn_height.overworld_min, mobs_mc.spawn_height.overworld_max) +--mobs:spawn_specific("mobs_mc:pigman", mobs_mc.spawn.nether_portal, {"air"}, 0, minetest.LIGHT_MAX+1, 30, 500, 4, mobs_mc.spawn_height.overworld_min, mobs_mc.spawn_height.overworld_max) -- spawn eggs mobs:register_egg("mobs_mc:pigman", S("Zombie Pigman"), "mobs_mc_spawn_icon_zombie_pigman.png", 0) diff --git a/mods/HUD/hudbars/API.md b/mods/HUD/hudbars/API.md index ca6144ad1c..ee112ecebc 100644 --- a/mods/HUD/hudbars/API.md +++ b/mods/HUD/hudbars/API.md @@ -17,7 +17,7 @@ To give you a *very* brief overview over this API, here is the basic workflow on In order to use this API, you should be aware of a few basic rules in order to understand it: * A HUD bar is an approximate graphical representation of the ratio of a current value and a maximum value, i.e. current health of 15 and maximum health of 20. A full HUD bar represents 100%, an empty HUD bar represents 0%. -* The current value must always be equal to or smaller then the maximum +* The current value must always be equal to or smaller then the maximum * Both current value and maximum must not be smaller than 0 * Both current value and maximum must be real numbers. So no NaN, infinity, etc. * The HUD bar will be hidden if the maximum equals 0. This is intentional. @@ -45,7 +45,7 @@ a vertical gradient. ### Icon A 16×16 image shown left of the HUD bar. This is optional. -### `hb.register_hudbar(identifier, text_color, label, textures, default_start_value, default_start_max, default_start_hidden, format_string, format_string_config)` +### `hb.register_hudbar(identifier, text_color, label, textures, direction, default_start_value, default_start_max, default_start_hidden, format_string, format_string_config)` This function registers a new custom HUD bar definition to the HUD bars mod, so it can be later used to be displayed, changed, hidden and unhidden on a per-player basis. Note this does not yet display the HUD bar. @@ -63,6 +63,7 @@ for more information. * `bar`: The file name of the bar image (as string). This is only used for the `progress_bar` bar type (see `README.txt`, settings section). * `icon`: The file name of the icon, as string. For the `progress_bar` type, it is shown as single image left of the bar, for the two statbar bar types, it is used as the statbar icon and will be repeated. This field can be `nil`, in which case no icon will be used, but this is not recommended, because the HUD bar will be invisible if the one of the statbar bar types is used. * `bgicon`: The file name of the background icon, it is used as the background for the modern statbar mode only. This field can be `nil`, in which case no background icon will be displayed in this mode. +* `direction`: Either left to right(0), or right to left(1). * `default_start_value`: If this HUD bar is added to a player, and no initial value is specified, this value will be used as initial current value * `default_max_value`: If this HUD bar is added to a player, and no initial maximum value is specified, this value will be used as initial maximum value * `default_start_hidden`: The HUD bar will be initially start hidden by default when added to a player. Use `hb.unhide_hudbar` to unhide it. diff --git a/mods/HUD/hudbars/default_settings.lua b/mods/HUD/hudbars/default_settings.lua index 0bd267d0e7..ce43cc8be1 100644 --- a/mods/HUD/hudbars/default_settings.lua +++ b/mods/HUD/hudbars/default_settings.lua @@ -20,9 +20,9 @@ if hb.settings.bar_type == "progress_bar" then hb.settings.start_offset_right.x = hb.load_setting("hudbars_start_offset_right_x", "number", 15) hb.settings.start_offset_right.y = hb.load_setting("hudbars_start_offset_right_y", "number", -86) else - hb.settings.start_offset_left.x = hb.load_setting("hudbars_start_statbar_offset_left_x", "number", -265) + hb.settings.start_offset_left.x = hb.load_setting("hudbars_start_statbar_offset_left_x", "number", -258) hb.settings.start_offset_left.y = hb.load_setting("hudbars_start_statbar_offset_left_y", "number", -90) - hb.settings.start_offset_right.x = hb.load_setting("hudbars_start_statbar_offset_right_x", "number", 25) + hb.settings.start_offset_right.x = hb.load_setting("hudbars_start_statbar_offset_right_x", "number", 16) hb.settings.start_offset_right.y = hb.load_setting("hudbars_start_statbar_offset_right_y", "number", -90) end -- Modified in MCL2! diff --git a/mods/HUD/hudbars/init.lua b/mods/HUD/hudbars/init.lua index e1ff3f5f11..6f90aa03d8 100644 --- a/mods/HUD/hudbars/init.lua +++ b/mods/HUD/hudbars/init.lua @@ -124,7 +124,7 @@ function hb.get_hudbar_position_index(identifier) end end -function hb.register_hudbar(identifier, text_color, label, textures, default_start_value, default_start_max, default_start_hidden, format_string, format_string_config) +function hb.register_hudbar(identifier, text_color, label, textures, direction, default_start_value, default_start_max, default_start_hidden, format_string, format_string_config) minetest.log("action", "hb.register_hudbar: "..tostring(identifier)) local hudtable = {} local pos, offset @@ -133,30 +133,33 @@ function hb.register_hudbar(identifier, text_color, label, textures, default_sta if hb.settings.alignment_pattern == "stack_up" then pos = hb.settings.pos_left offset = { - x = hb.settings.start_offset_left.x, + x = direction == 0 and hb.settings.start_offset_left.x or -hb.settings.start_offset_right.x, y = hb.settings.start_offset_left.y - hb.settings.vmargin * index } elseif hb.settings.alignment_pattern == "stack_down" then pos = hb.settings.pos_left offset = { - x = hb.settings.start_offset_left.x, + x = direction == 0 and hb.settings.start_offset_right.x or -hb.settings.start_offset_left.x, y = hb.settings.start_offset_left.y + hb.settings.vmargin * index } - else + else -- zigzag if index % 2 == 0 then pos = hb.settings.pos_left offset = { - x = hb.settings.start_offset_left.x, + -- -(24+18) = -42. using linear eq, -42 = -258m - 24. + x = direction == 0 and hb.settings.start_offset_left.x or (-42+24)/(-258.0) * hb.settings.start_offset_left.x - 24, y = hb.settings.start_offset_left.y - hb.settings.vmargin * (index/2) } else pos = hb.settings.pos_right offset = { - x = hb.settings.start_offset_right.x, + -- 24*10+30 - 24 = 234. using linear eq, 234 = 16m - 24. + x = direction == 0 and hb.settings.start_offset_right.x or (234+24)/(16) * hb.settings.start_offset_right.x - 24, y = hb.settings.start_offset_right.y - hb.settings.vmargin * ((index-1)/2) } end end + if format_string == nil then format_string = N("@1: @2/@3") end @@ -181,6 +184,7 @@ function hb.register_hudbar(identifier, text_color, label, textures, default_sta local state = {} local name = player:get_player_name() local bgscale, iconscale, text, barnumber, bgiconnumber + if start_max == 0 or start_hidden then bgscale = { x=0, y=0 } else @@ -197,6 +201,7 @@ function hb.register_hudbar(identifier, text_color, label, textures, default_sta bgiconnumber = hb.settings.statbar_length text = make_label(format_string, format_string_config, label, start_value, start_max) end + if hb.settings.bar_type == "progress_bar" then ids.bg = player:hud_add({ hud_elem_type = "image", @@ -219,6 +224,7 @@ function hb.register_hudbar(identifier, text_color, label, textures, default_sta }) end end + local bar_image, bgicon, bar_size if hb.settings.bar_type == "progress_bar" then bar_image = textures.bar @@ -234,10 +240,12 @@ function hb.register_hudbar(identifier, text_color, label, textures, default_sta bgicon = textures.bgicon bar_size = {x=24, y=24} end + local text2 if hb.settings.bar_type == "statbar_modern" then text2 = bgicon end + ids.bar = player:hud_add({ hud_elem_type = "statbar", position = pos, @@ -247,7 +255,7 @@ function hb.register_hudbar(identifier, text_color, label, textures, default_sta item = bgiconnumber, alignment = {x=-1,y=-1}, offset = offset, - direction = 0, + direction = direction, size = bar_size, z_index = 1, }) @@ -258,7 +266,7 @@ function hb.register_hudbar(identifier, text_color, label, textures, default_sta text = text, alignment = {x=1,y=1}, number = text_color, - direction = 0, + direction = direction, offset = { x = offset.x + 2, y = offset.y - 1}, z_index = 2, }) @@ -298,7 +306,7 @@ function hb.register_hudbar(identifier, text_color, label, textures, default_sta hudtable.default_start_max = default_start_max hb.hudbars_count= hb.hudbars_count + 1 - + hb.hudtables[identifier] = hudtable end @@ -359,6 +367,7 @@ function hb.change_hudbar(player, identifier, new_value, new_max_value, new_icon if new_text_color ~= nil then player:hud_change(hudtable.hudids[name].text, "number", new_text_color) end + else if new_icon ~= nil and hudtable.hudids[name].bar ~= nil then player:hud_change(hudtable.hudids[name].bar, "text", new_icon) @@ -474,8 +483,8 @@ end --register built-in HUD bars if minetest.settings:get_bool("enable_damage") or hb.settings.forceload_default_hudbars then - hb.register_hudbar("health", 0xFFFFFF, S("Health"), { bar = "hudbars_bar_health.png", icon = "hudbars_icon_health.png", bgicon = "hudbars_bgicon_health.png" }, 20, 20, false) - hb.register_hudbar("breath", 0xFFFFFF, S("Breath"), { bar = "hudbars_bar_breath.png", icon = "hudbars_icon_breath.png", bgicon = "hudbars_bgicon_breath.png" }, 10, 10, true) + hb.register_hudbar("health", 0xFFFFFF, S("Health"), { bar = "hudbars_bar_health.png", icon = "hudbars_icon_health.png", bgicon = "hudbars_bgicon_health.png" }, 0, 20, 20, false) + hb.register_hudbar("breath", 0xFFFFFF, S("Breath"), { bar = "hudbars_bar_breath.png", icon = "hudbars_icon_breath.png", bgicon = "hudbars_bgicon_breath.png" }, 1, 10, 10, true) end local function hide_builtin(player) @@ -520,7 +529,7 @@ local function update_hud(player, has_damage) --air local breath_max = player:get_properties().breath_max local breath = player:get_breath() - + if breath >= breath_max and hb.settings.autohide_breath == true then hb.hide_hudbar(player, "breath") else diff --git a/mods/HUD/mcl_bossbars/init.lua b/mods/HUD/mcl_bossbars/init.lua new file mode 100644 index 0000000000..f1d99e0139 --- /dev/null +++ b/mods/HUD/mcl_bossbars/init.lua @@ -0,0 +1,199 @@ +mcl_bossbars = { + bars = {}, + huds = {}, + static = {}, + colors = {"light_purple", "blue", "red", "green", "yellow", "dark_purple", "white"}, + max_bars = tonumber(minetest.settings:get("max_bossbars")) or 4 +} + +function mcl_bossbars.recalculate_colors() + local sorted = {} + local colors = mcl_bossbars.colors + local color_count = #colors + local frame_count = color_count * 2 + for i, color in ipairs(colors) do + local idx = i * 2 - 1 + local image = "mcl_bossbars.png" + .. "^[transformR270" + .. "^[verticalframe:" .. frame_count .. ":" .. (idx - 1) + .. "^(mcl_bossbars_empty.png" + .. "^[lowpart:%d:mcl_bossbars.png" + .. "^[transformR270" + .. "^[verticalframe:" .. frame_count .. ":" .. idx .. ")" + local _, hex = mcl_util.get_color(color) + sorted[color] = { + image = image, + hex = hex, + } + end + mcl_bossbars.colors_sorted = sorted +end + +local function get_color_info(color, percentage) + local cdef = mcl_bossbars.colors_sorted[color] + return cdef.hex, string.format(cdef.image, percentage) +end + +local last_id = 0 + +function mcl_bossbars.add_bar(player, def, dynamic, priority) + local name = player:get_player_name() + local bars = mcl_bossbars.bars[name] + local bar = {text = def.text, priority = priority or 0, timeout = def.timeout} + bar.color, bar.image = get_color_info(def.color, def.percentage) + if dynamic then + for _, other in pairs(bars) do + if not other.id and other.color == bar.color and (other.original_text or other.text) == bar.text and other.image == bar.image then + if not other.count then + other.count = 1 + other.original_text = other.text + end + other.count = other.count + 1 + other.text = other.original_text .. " x" .. other.count + return + end + end + end + table.insert(bars, bar) + if not dynamic then + bar.raw_color = def.color + bar.id = last_id + 1 + last_id = bar.id + mcl_bossbars.static[bar.id] = bar + return bar.id + end +end + +function mcl_bossbars.remove_bar(id) + mcl_bossbars.static[id].id = nil + mcl_bossbars.static[id] = nil +end + +function mcl_bossbars.update_bar(id, def, priority) + local old = mcl_bossbars.static[id] + old.color = get_color_info(def.color or old.raw_color, def.percentage or old.percentage) + old.text = def.text or old.text + old.priority = priority or old.priority +end + +function mcl_bossbars.update_boss(object, name, color) + local props = object:get_luaentity() + if not props or not props._cmi_is_mob then + props = object:get_properties() + props.health = object:get_hp() + end + + local bardef = { + color = color, + text = props.nametag, + percentage = math.floor(props.health / props.hp_max * 100), + } + + if not bardef.text or bardef.text == "" then + bardef.text = name + end + + local pos = object:get_pos() + for _, player in pairs(minetest.get_connected_players()) do + local d = vector.distance(pos, player:get_pos()) + if d <= 80 then + mcl_bossbars.add_bar(player, bardef, true, d) + end + end +end + +minetest.register_on_joinplayer(function(player) + local name = player:get_player_name() + mcl_bossbars.huds[name] = {} + mcl_bossbars.bars[name] = {} +end) + +minetest.register_on_leaveplayer(function(player) + local name = player:get_player_name() + mcl_bossbars.huds[name] = nil + for _, bar in pairs(mcl_bossbars.bars[name]) do + if bar.id then + mcl_bossbars.static[bar.id] = nil + end + end + mcl_bossbars.bars[name] = nil +end) + +minetest.register_globalstep(function(dtime) + for _, player in pairs(minetest.get_connected_players()) do + local name = player:get_player_name() + local bars = mcl_bossbars.bars[name] + local huds = mcl_bossbars.huds[name] + table.sort(bars, function(a, b) return a.priority < b.priority end) + local huds_new = {} + local bars_new = {} + local i = 0 + + while #huds > 0 or #bars > 0 do + local bar = table.remove(bars, 1) + local hud = table.remove(huds, 1) + + if bar and bar.id then + if bar.timeout then + bar.timeout = bar.timeout - dtime + end + if not bar.timeout or bar.timeout > 0 then + table.insert(bars_new, bar) + end + end + + if bar and not hud then + if i < mcl_bossbars.max_bars then + hud = { + color = bar.color, + image = bar.image, + text = bar.text, + text_id = player:hud_add({ + hud_elem_type = "text", + text = bar.text, + number = bar.color, + position = {x = 0.5, y = 0}, + alignment = {x = 0, y = 1}, + offset = {x = 0, y = i * 40}, + }), + image_id = player:hud_add({ + hud_elem_type = "image", + text = bar.image, + position = {x = 0.5, y = 0}, + alignment = {x = 0, y = 1}, + offset = {x = 0, y = i * 40 + 25}, + scale = {x = 3, y = 3}, + }), + } + end + elseif hud and not bar then + player:hud_remove(hud.text_id) + player:hud_remove(hud.image_id) + hud = nil + else + if bar.text ~= hud.text then + player:hud_change(hud.text_id, "text", bar.text) + hud.text = bar.text + end + + if bar.color ~= hud.color then + player:hud_change(hud.text_id, "number", bar.color) + hud.color = bar.color + end + + if bar.image ~= hud.image then + player:hud_change(hud.image_id, "text", bar.image) + hud.image = bar.image + end + end + + table.insert(huds_new, hud) + i = i + 1 + end + + mcl_bossbars.huds[name] = huds_new + mcl_bossbars.bars[name] = bars_new + end +end) + +mcl_bossbars.recalculate_colors() diff --git a/mods/HUD/mcl_bossbars/mod.conf b/mods/HUD/mcl_bossbars/mod.conf new file mode 100644 index 0000000000..64cbd4c9f7 --- /dev/null +++ b/mods/HUD/mcl_bossbars/mod.conf @@ -0,0 +1,4 @@ +name = mcl_bossbars +author = Fleckenstein +description = Show enderdragon & wither boss bars. Also allows custom bars. +depends = mcl_util, mcl_colors diff --git a/mods/HUD/mcl_bossbars/textures/mcl_bossbars.png b/mods/HUD/mcl_bossbars/textures/mcl_bossbars.png new file mode 100644 index 0000000000..55bf36dc28 Binary files /dev/null and b/mods/HUD/mcl_bossbars/textures/mcl_bossbars.png differ diff --git a/mods/HUD/mcl_bossbars/textures/mcl_bossbars_empty.png b/mods/HUD/mcl_bossbars/textures/mcl_bossbars_empty.png new file mode 100644 index 0000000000..1e50b6afc2 Binary files /dev/null and b/mods/HUD/mcl_bossbars/textures/mcl_bossbars_empty.png differ diff --git a/mods/HUD/mcl_credits/init.lua b/mods/HUD/mcl_credits/init.lua new file mode 100644 index 0000000000..1e8138ab45 --- /dev/null +++ b/mods/HUD/mcl_credits/init.lua @@ -0,0 +1,209 @@ +mcl_credits = { + players = {}, +} + +mcl_credits.description = "A faithful Open Source clone of Minecraft" + +-- Sub-lists are sorted by number of commits, but the list should not be rearranged (-> new contributors are just added at the end of the list) +mcl_credits.people = { + {"Creator of MineClone", 0x0A9400, { + "davedevils", + }}, + {"Creator of MineClone2", 0xFBF837, { + "Wuzzy", + }}, + {"Maintainers", 0xFF51D5, { + "Fleckenstein", + "kay27", + "oilboi", + }}, + {"Developers", 0xF84355, { + "bzoss", + "AFCMS", + "epCode", + "ryvnf", + "iliekprogrammar", + "MysticTempest", + "Rootyjr", + "Nicu", + "aligator", + }}, + {"Contributors", 0x52FF00, { + "Code-Sploit", + "Laurent Rocher", + "HimbeerserverDE", + "TechDudie", + "Alexander Minges", + "ArTee3", + "ZeDique la Ruleta", + "pitchum", + "wuniversales", + "Bu-Gee", + "David McMackins II", + "Nicholas Niro", + "Wouters Dorian", + "Blue Blancmange", + "Jared Moody", + "Li0n", + "Midgard", + "NO11", + "Saku Laesvuori", + "Yukitty", + "ZedekThePD", + "aldum", + "dBeans", + "nickolas360", + "yutyo", + "ztianyang", + }}, + {"MineClone5", 0xA60014, { + "kay27", + "Debiankaios", + "epCode", + "NO11", + "j45", + }}, + {"3D Models", 0x0019FF, { + "22i", + "tobyplowy", + "epCode", + }}, + {"Textures", 0xFF9705, { + "XSSheep", + "Wuzzy", + "kingoscargames", + "leorockway", + "xMrVizzy", + "yutyo" + }}, + {"Translations", 0x00FF60, { + "Wuzzy", + "Rocher Laurent", + "wuniversales", + "kay27", + "pitchum", + }}, +} + +local function add_hud_element(def, huds, y) + def.alignment = {x = 0, y = 0} + def.position = {x = 0.5, y = 0} + def.offset = {x = 0, y = y} + def.z_index = 1001 + local id = huds.player:hud_add(def) + table.insert(huds.ids, id) + huds.moving[id] = y + return id +end + +function mcl_credits.show(player) + local name = player:get_player_name() + if mcl_credits.players[name] then + return + end + local huds = { + new = true, -- workaround for MT < 5.5 (sending hud_add and hud_remove in the same tick) + player = player, + moving = {}, + ids = { + player:hud_add({ + hud_elem_type = "image", + text = "menu_bg.png", + position = {x = 0, y = 0}, + alignment = {x = 1, y = 1}, + scale = {x = -100, y = -100}, + z_index = 1000, + }), + player:hud_add({ + hud_elem_type = "text", + text = "Sneak to skip", + position = {x = 1, y = 1}, + alignment = {x = -1, y = -1}, + offset = {x = -5, y = -5}, + z_index = 1001, + number = 0xFFFFFF, + }) + }, + } + add_hud_element({ + hud_elem_type = "image", + text = "mineclone2_logo.png", + scale = {x = 1, y = 1}, + }, huds, 300, 0) + add_hud_element({ + hud_elem_type = "text", + text = mcl_credits.description, + number = 0x757575, + scale = {x = 5, y = 5}, + }, huds, 350, 0) + local y = 450 + for _, group in ipairs(mcl_credits.people) do + add_hud_element({ + hud_elem_type = "text", + text = group[1], + number = group[2], + scale = {x = 3, y = 3}, + }, huds, y, 0) + y = y + 25 + for _, name in ipairs(group[3]) do + y = y + 25 + add_hud_element({ + hud_elem_type = "text", + text = name, + number = 0xFFFFFF, + scale = {x = 1, y = 1}, + }, huds, y, 0) + end + y = y + 200 + end + huds.icon = add_hud_element({ + hud_elem_type = "image", + text = "mineclone2_icon.png", + scale = {x = 1, y = 1}, + }, huds, y) + mcl_credits.players[name] = huds +end + +function mcl_credits.hide(player) + local name = player:get_player_name() + local huds = mcl_credits.players[name] + if huds then + for _, id in pairs(huds.ids) do + player:hud_remove(id) + end + end + mcl_credits.players[name] = nil +end + +minetest.register_on_leaveplayer(function(player) + mcl_credits.players[player:get_player_name()] = nil +end) + +minetest.register_globalstep(function(dtime) + for _, huds in pairs(mcl_credits.players) do + local player = huds.player + if not huds.new and player:get_player_control().sneak then + mcl_credits.hide(player) + else + local moving = {} + local any + for id, y in pairs(huds.moving) do + y = y - 1 + if y > -100 then + if id == huds.icon then + y = math.max(400, y) + else + any = true + end + player:hud_change(id, "offset", {x = 0, y = y}) + moving[id] = y + end + end + if not any then + mcl_credits.hide(player) + end + huds.moving = moving + end + huds.new = false + end +end) diff --git a/mods/HUD/mcl_credits/mod.conf b/mods/HUD/mcl_credits/mod.conf new file mode 100644 index 0000000000..3df6370afc --- /dev/null +++ b/mods/HUD/mcl_credits/mod.conf @@ -0,0 +1,3 @@ +name = mcl_credits +author = Fleckenstein +description = Show a HUD containing the credits diff --git a/mods/HUD/mcl_credits/textures/mineclone2_icon.png b/mods/HUD/mcl_credits/textures/mineclone2_icon.png new file mode 100644 index 0000000000..e479dfff5a Binary files /dev/null and b/mods/HUD/mcl_credits/textures/mineclone2_icon.png differ diff --git a/mods/HUD/mcl_credits/textures/mineclone2_logo.png b/mods/HUD/mcl_credits/textures/mineclone2_logo.png new file mode 100644 index 0000000000..11435df510 Binary files /dev/null and b/mods/HUD/mcl_credits/textures/mineclone2_logo.png differ diff --git a/mods/HUD/mcl_hbarmor/init.lua b/mods/HUD/mcl_hbarmor/init.lua index 4434f5dad2..89b2db7a89 100644 --- a/mods/HUD/mcl_hbarmor/init.lua +++ b/mods/HUD/mcl_hbarmor/init.lua @@ -57,7 +57,7 @@ local function custom_hud(player) end --register and define armor HUD bar -hb.register_hudbar("armor", 0xFFFFFF, S("Armor"), { icon = "hbarmor_icon.png", bgicon = "hbarmor_bgicon.png", bar = "hbarmor_bar.png" }, 0, 20, mcl_hbarmor.autohide) +hb.register_hudbar("armor", 0xFFFFFF, S("Armor"), { icon = "hbarmor_icon.png", bgicon = "hbarmor_bgicon.png", bar = "hbarmor_bar.png" }, 0, 0, 20, mcl_hbarmor.autohide) function mcl_hbarmor.get_armor(player) if not player or not armor.def then diff --git a/mods/ITEMS/REDSTONE/mesecons/internal.lua b/mods/ITEMS/REDSTONE/mesecons/internal.lua index 7986c2908b..f4ed9df4eb 100644 --- a/mods/ITEMS/REDSTONE/mesecons/internal.lua +++ b/mods/ITEMS/REDSTONE/mesecons/internal.lua @@ -47,28 +47,34 @@ -- mesecon.rotate_rules_down(rules) -- These functions return rules that have been rotated in the specific direction +local equals = vector.equals +local get_node_force = mesecon.get_node_force +local invertRule = mesecon.invertRule +local copy, insert = table.copy, table.insert +local registered_nodes = minetest.registered_nodes + -- General function mesecon.get_effector(nodename) - if minetest.registered_nodes[nodename] - and minetest.registered_nodes[nodename].mesecons - and minetest.registered_nodes[nodename].mesecons.effector then - return minetest.registered_nodes[nodename].mesecons.effector + if registered_nodes[nodename] + and registered_nodes[nodename].mesecons + and registered_nodes[nodename].mesecons.effector then + return registered_nodes[nodename].mesecons.effector end end function mesecon.get_receptor(nodename) - if minetest.registered_nodes[nodename] - and minetest.registered_nodes[nodename].mesecons - and minetest.registered_nodes[nodename].mesecons.receptor then - return minetest.registered_nodes[nodename].mesecons.receptor + if registered_nodes[nodename] + and registered_nodes[nodename].mesecons + and registered_nodes[nodename].mesecons.receptor then + return registered_nodes[nodename].mesecons.receptor end end function mesecon.get_conductor(nodename) - if minetest.registered_nodes[nodename] - and minetest.registered_nodes[nodename].mesecons - and minetest.registered_nodes[nodename].mesecons.conductor then - return minetest.registered_nodes[nodename].mesecons.conductor + if registered_nodes[nodename] + and registered_nodes[nodename].mesecons + and registered_nodes[nodename].mesecons.conductor then + return registered_nodes[nodename].mesecons.conductor end end @@ -103,13 +109,14 @@ end -- Receptors -- Nodes that can power mesecons -function mesecon.is_receptor_on(nodename) +local function is_receptor_on(nodename) local receptor = mesecon.get_receptor(nodename) if receptor and receptor.state == mesecon.state.on then return true end return false end +mesecon.is_receptor_on = is_receptor_on function mesecon.is_receptor_off(nodename) local receptor = mesecon.get_receptor(nodename) @@ -127,7 +134,7 @@ function mesecon.is_receptor(nodename) return false end -function mesecon.receptor_get_rules(node) +local function receptor_get_rules(node) local receptor = mesecon.get_receptor(node.name) if receptor then local rules = receptor.rules @@ -140,6 +147,7 @@ function mesecon.receptor_get_rules(node) return mesecon.rules.default end +mesecon.receptor_get_rules = receptor_get_rules -- Effectors -- Nodes that can be powered by mesecons @@ -186,7 +194,7 @@ end -- Activation: mesecon.queue:add_function("activate", function (pos, rulename) - local node = mesecon.get_node_force(pos) + local node = get_node_force(pos) if not node then return end local effector = mesecon.get_effector(node.name) @@ -198,7 +206,7 @@ end) function mesecon.activate(pos, node, rulename, depth) if rulename == nil then - for _,rule in ipairs(mesecon.effector_get_rules(node)) do + for _,rule in pairs(mesecon.effector_get_rules(node)) do mesecon.activate(pos, node, rule, depth + 1) end return @@ -209,7 +217,7 @@ end -- Deactivation mesecon.queue:add_function("deactivate", function (pos, rulename) - local node = mesecon.get_node_force(pos) + local node = get_node_force(pos) if not node then return end local effector = mesecon.get_effector(node.name) @@ -221,7 +229,7 @@ end) function mesecon.deactivate(pos, node, rulename, depth) if rulename == nil then - for _,rule in ipairs(mesecon.effector_get_rules(node)) do + for _,rule in pairs(mesecon.effector_get_rules(node)) do mesecon.deactivate(pos, node, rule, depth + 1) end return @@ -232,7 +240,7 @@ end -- Change mesecon.queue:add_function("change", function (pos, rulename, changetype) - local node = mesecon.get_node_force(pos) + local node = get_node_force(pos) if not node then return end local effector = mesecon.get_effector(node.name) @@ -244,7 +252,7 @@ end) function mesecon.changesignal(pos, node, rulename, newstate, depth) if rulename == nil then - for _,rule in ipairs(mesecon.effector_get_rules(node)) do + for _,rule in pairs(mesecon.effector_get_rules(node)) do mesecon.changesignal(pos, node, rule, newstate, depth + 1) end return @@ -356,15 +364,15 @@ end -- some more general high-level stuff function mesecon.is_power_on(pos, rulename) - local node = mesecon.get_node_force(pos) - if node and (mesecon.is_conductor_on(node, rulename) or mesecon.is_receptor_on(node.name)) then + local node = get_node_force(pos) + if node and (mesecon.is_conductor_on(node, rulename) or is_receptor_on(node.name)) then return true end return false end function mesecon.is_power_off(pos, rulename) - local node = mesecon.get_node_force(pos) + local node = get_node_force(pos) if node and (mesecon.is_conductor_off(node, rulename) or mesecon.is_receptor_off(node.name)) then return true end @@ -381,7 +389,7 @@ function mesecon.turnon(pos, link) local depth = 1 while frontiers[1] do local f = table.remove(frontiers, 1) - local node = mesecon.get_node_force(f.pos) + local node = get_node_force(f.pos) if not node then -- Area does not exist; do nothing @@ -389,10 +397,10 @@ function mesecon.turnon(pos, link) local rules = mesecon.conductor_get_rules(node) -- Call turnon on neighbors - for _, r in ipairs(mesecon.rule2meta(f.link, rules)) do + for _, r in pairs(mesecon.rule2meta(f.link, rules)) do local np = vector.add(f.pos, r) - for _, l in ipairs(mesecon.rules_link_rule_all(f.pos, r)) do - table.insert(frontiers, {pos = np, link = l}) + for _, l in pairs(mesecon.rules_link_rule_all(f.pos, r)) do + insert(frontiers, {pos = np, link = l}) end end @@ -406,12 +414,12 @@ function mesecon.turnon(pos, link) if node and f.link.spread and minetest.get_item_group(node.name, "opaque") == 1 then -- Call turnon on neighbors -- Warning: A LOT of nodes need to be looked at for this to work - for _, r in ipairs(mesecon.rule2meta(f.link, mesecon.rules.mcl_alldirs_spread)) do + for _, r in pairs(mesecon.rule2meta(f.link, mesecon.rules.mcl_alldirs_spread)) do local np = vector.add(f.pos, r) - for _, l in ipairs(mesecon.rules_link_rule_all(f.pos, r)) do - local nlink = table.copy(l) + for _, l in pairs(mesecon.rules_link_rule_all(f.pos, r)) do + local nlink = copy(l) nlink.spread = false - table.insert(frontiers, {pos = np, link = nlink}) + insert(frontiers, {pos = np, link = nlink}) end end end @@ -443,33 +451,33 @@ function mesecon.turnoff(pos, link) local depth = 1 while frontiers[1] do local f = table.remove(frontiers, 1) - local node = mesecon.get_node_force(f.pos) + local node = get_node_force(f.pos) if not node then -- No-op elseif mesecon.is_conductor_on(node, f.link) then local rules = mesecon.conductor_get_rules(node) - for _, r in ipairs(mesecon.rule2meta(f.link, rules)) do + for _, r in pairs(mesecon.rule2meta(f.link, rules)) do local np = vector.add(f.pos, r) -- Check if an onstate receptor is connected. If that is the case, -- abort this turnoff process by returning false. `receptor_off` will -- discard all the changes that we made in the voxelmanip: - for _, l in ipairs(mesecon.rules_link_rule_all_inverted(f.pos, r)) do - if mesecon.is_receptor_on(mesecon.get_node_force(np).name) then + for _, l in pairs(mesecon.rules_link_rule_all_inverted(f.pos, r)) do + if is_receptor_on(get_node_force(np).name) then return false end end -- Call turnoff on neighbors - for _, l in ipairs(mesecon.rules_link_rule_all(f.pos, r)) do - table.insert(frontiers, {pos = np, link = l}) + for _, l in pairs(mesecon.rules_link_rule_all(f.pos, r)) do + insert(frontiers, {pos = np, link = l}) end end mesecon.swap_node_force(f.pos, mesecon.get_conductor_off(node, f.link)) elseif mesecon.is_effector(node.name) then - table.insert(signals, { + insert(signals, { pos = f.pos, node = node, link = f.link, @@ -480,21 +488,22 @@ function mesecon.turnoff(pos, link) if node and f.link.spread and minetest.get_item_group(node.name, "opaque") == 1 then -- Call turnoff on neighbors -- Warning: A LOT of nodes need to be looked at for this to work - for _, r in ipairs(mesecon.rule2meta(f.link, mesecon.rules.mcl_alldirs_spread)) do - local np = vector.add(f.pos, r) - local n = mesecon.get_node_force(np) - if mesecon.is_receptor_on(n.name) then - local receptorrules = mesecon.receptor_get_rules(n) + local fpos = f.pos + for _, r in pairs(mesecon.rule2meta(f.link, mesecon.rules.mcl_alldirs_spread)) do + local np = {x=fpos.x+r.x, y=fpos.y+r.y, z=fpos.z+r.z} + local n = get_node_force(np) + if n and is_receptor_on(n.name) then + local receptorrules = receptor_get_rules(n) for _, rr in pairs(receptorrules) do - if rr.spread and vector.equals(mesecon.invertRule(rr), r) then + if rr.spread and equals(invertRule(rr), r) then return false end end end - for _, l in ipairs(mesecon.rules_link_rule_all(f.pos, r)) do - local nlink = table.copy(l) + for _, l in pairs(mesecon.rules_link_rule_all(fpos, r)) do + local nlink = copy(l) nlink.spread = false - table.insert(frontiers, {pos = np, link = nlink}) + insert(frontiers, {pos = np, link = nlink}) end end end @@ -502,7 +511,7 @@ function mesecon.turnoff(pos, link) depth = depth + 1 end - for _, sig in ipairs(signals) do + for _, sig in pairs(signals) do mesecon.changesignal(sig.pos, sig.node, sig.link, mesecon.state.off, sig.depth) if mesecon.is_effector_on(sig.node.name) and not mesecon.is_powered(sig.pos) then mesecon.deactivate(sig.pos, sig.node, sig.link, sig.depth) @@ -516,19 +525,19 @@ end -- outputnode (receptor or conductor) at position `output` and has an output in direction `rule` function mesecon.rules_link_rule_all(output, rule) local input = vector.add(output, rule) - local inputnode = mesecon.get_node_force(input) + local inputnode = get_node_force(input) local inputrules = mesecon.get_any_inputrules(inputnode) if not inputrules then return {} end local rules = {} - for _, inputrule in ipairs(mesecon.flattenrules(inputrules)) do + for _, inputrule in pairs(mesecon.flattenrules(inputrules)) do -- Check if input accepts from output - if vector.equals(vector.add(input, inputrule), output) then - local newrule = table.copy(inputrule) + if equals(vector.add(input, inputrule), output) then + local newrule = copy(inputrule) newrule.spread = rule.spread - table.insert(rules, newrule) + insert(rules, newrule) end end @@ -539,19 +548,19 @@ end -- inputnode (effector or conductor) at position `input` and has an input in direction `rule` function mesecon.rules_link_rule_all_inverted(input, rule) local output = vector.add(input, rule) - local outputnode = mesecon.get_node_force(output) + local outputnode = get_node_force(output) local outputrules = mesecon.get_any_outputrules(outputnode) if not outputrules then return {} end local rules = {} - for _, outputrule in ipairs(mesecon.flattenrules(outputrules)) do - if vector.equals(vector.add(output, outputrule), input) then - local newrule = table.copy(outputrule) - newrule = mesecon.invertRule(newrule) + for _, outputrule in pairs(mesecon.flattenrules(outputrules)) do + if equals(vector.add(output, outputrule), input) then + local newrule = copy(outputrule) + newrule = invertRule(newrule) newrule.spread = rule.spread - table.insert(rules, newrule) + insert(rules, newrule) end end return rules @@ -562,7 +571,7 @@ function mesecon.is_powered(pos, rule, depth, sourcepos, home_pos) if depth > 1 then return false, false end - local node = mesecon.get_node_force(pos) + local node = get_node_force(pos) local rules = mesecon.get_any_inputrules(node) if not rules then return false, false @@ -578,23 +587,23 @@ function mesecon.is_powered(pos, rule, depth, sourcepos, home_pos) local function power_walk(pos, home_pos, sourcepos, rulenames, rule, depth) local spread = false - for _, rname in ipairs(rulenames) do + for _, rname in pairs(rulenames) do local np = vector.add(pos, rname) - local nn = mesecon.get_node_force(np) - if (mesecon.is_conductor_on (nn, mesecon.invertRule(rname)) - or mesecon.is_receptor_on (nn.name)) then - if not vector.equals(home_pos, np) then + local nn = get_node_force(np) + if (mesecon.is_conductor_on (nn, invertRule(rname)) + or is_receptor_on (nn.name)) then + if not equals(home_pos, np) then local rulez = mesecon.get_any_outputrules(nn) local spread_tmp = false for r=1, #rulez do - if vector.equals(mesecon.invertRule(rname), rulez[r]) then + if equals(invertRule(rname), rulez[r]) then if rulez[r].spread then spread_tmp = true end end end if depth == 0 or spread_tmp then - table.insert(sourcepos, np) + insert(sourcepos, np) if spread_tmp then spread = true end @@ -612,7 +621,7 @@ function mesecon.is_powered(pos, rule, depth, sourcepos, home_pos) local spread = false if not rule then - for _, rule in ipairs(mesecon.flattenrules(rules)) do + for _, rule in pairs(mesecon.flattenrules(rules)) do local spread_temp local rulenames = mesecon.rules_link_rule_all_inverted(pos, rule) sourcepos, spread_temp = power_walk(pos, home_pos, sourcepos, rulenames, rule, depth) diff --git a/mods/ITEMS/REDSTONE/mesecons_torch/init.lua b/mods/ITEMS/REDSTONE/mesecons_torch/init.lua index c7c4a4ca2a..9aefae96c4 100644 --- a/mods/ITEMS/REDSTONE/mesecons_torch/init.lua +++ b/mods/ITEMS/REDSTONE/mesecons_torch/init.lua @@ -117,83 +117,90 @@ minetest.register_craft({ {"mcl_core:stick"},} }) -mcl_torches.register_torch("mesecon_torch_off", S("Redstone Torch (off)"), - nil, - nil, - "jeija_torches_off.png", - "mcl_torches_torch_floor.obj", "mcl_torches_torch_wall.obj", - {"jeija_torches_off.png"}, - 0, - {dig_immediate=3, dig_by_water=1, redstone_torch=2, mesecon_ignore_opaque_dig=1, not_in_creative_inventory=1}, - mcl_sounds.node_sound_wood_defaults(), - { - mesecons = { - receptor = { - state = mesecon.state.off, - rules = torch_get_output_rules, - }, - effector = { - state = mesecon.state.on, - rules = torch_get_input_rules, - action_off = torch_action_off, - }, +local off_def = { + name = "mesecon_torch_off", + description = S("Redstone Torch (off)"), + doc_items_create_entry = false, + icon = "jeija_torches_off.png", + tiles = {"jeija_torches_off.png"}, + light = 0, + groups = {dig_immediate=3, dig_by_water=1, redstone_torch=2, mesecon_ignore_opaque_dig=1, not_in_creative_inventory=1}, + sounds = mcl_sounds.node_sound_wood_defaults(), + drop = "mesecons_torch:mesecon_torch_on", +} + +mcl_torches.register_torch(off_def) + +local off_override = { + mesecons = { + receptor = { + state = mesecon.state.off, + rules = torch_get_output_rules, + }, + effector = { + state = mesecon.state.on, + rules = torch_get_input_rules, + action_off = torch_action_off, }, - drop = "mesecons_torch:mesecon_torch_on", - _doc_items_create_entry = false, } -) +} -mcl_torches.register_torch("mesecon_torch_overheated", S("Redstone Torch (overheated)"), - nil, - nil, - "jeija_torches_off.png", - "mcl_torches_torch_floor.obj", "mcl_torches_torch_wall.obj", - {"jeija_torches_off.png"}, - 0, - {dig_immediate=3, dig_by_water=1, redstone_torch=2, mesecon_ignore_opaque_dig=1, not_in_creative_inventory=1}, - mcl_sounds.node_sound_wood_defaults(), - { - drop = "mesecons_torch:mesecon_torch_on", - _doc_items_create_entry = false, - on_timer = function(pos, elapsed) - if not mesecon.is_powered(pos) then - local node = minetest.get_node(pos) - torch_action_off(pos, node) - end - end, - } -) +minetest.override_item("mesecons_torch:mesecon_torch_off", off_override) +minetest.override_item("mesecons_torch:mesecon_torch_off_wall", off_override) +local overheated_def = table.copy(off_def) +overheated_def.name = "mesecon_torch_overheated" +overheated_def.description = S("Redstone Torch (overheated)") +mcl_torches.register_torch(overheated_def) -mcl_torches.register_torch("mesecon_torch_on", S("Redstone Torch"), - S("A redstone torch is a redstone component which can be used to invert a redstone signal. It supplies its surrounding blocks with redstone power, except for the block it is attached to. A redstone torch is normally lit, but it can also be turned off by powering the block it is attached to. While unlit, a redstone torch does not power anything."), - S("Redstone torches can be placed at the side and on the top of full solid opaque blocks."), - "jeija_torches_on.png", - "mcl_torches_torch_floor.obj", "mcl_torches_torch_wall.obj", - {"jeija_torches_on.png"}, - 7, - {dig_immediate=3, dig_by_water=1, redstone_torch=1, mesecon_ignore_opaque_dig=1}, - mcl_sounds.node_sound_wood_defaults(), - { - on_destruct = function(pos, oldnode) +local overheated_override = { + on_timer = function(pos, elapsed) + if not mesecon.is_powered(pos) then local node = minetest.get_node(pos) - torch_action_on(pos, node) - end, - mesecons = { - receptor = { - state = mesecon.state.on, - rules = torch_get_output_rules - }, - effector = { - state = mesecon.state.off, - rules = torch_get_input_rules, - action_on = torch_action_on, - }, + torch_action_off(pos, node) + end + end +} + +minetest.override_item("mesecons_torch:mesecon_torch_overheated", overheated_override) +minetest.override_item("mesecons_torch:mesecon_torch_overheated_wall", overheated_override) + +local on_def = { + name = "mesecon_torch_on", + description = S("Redstone Torch"), + doc_items_longdesc = S("A redstone torch is a redstone component which can be used to invert a redstone signal. It supplies its surrounding blocks with redstone power, except for the block it is attached to. A redstone torch is normally lit, but it can also be turned off by powering the block it is attached to. While unlit, a redstone torch does not power anything."), + doc_items_usagehelp = S("Redstone torches can be placed at the side and on the top of full solid opaque blocks."), + icon = "jeija_torches_on.png", + tiles = {"jeija_torches_on.png"}, + light = 7, + groups = {dig_immediate=3, dig_by_water=1, redstone_torch=1, mesecon_ignore_opaque_dig=1}, + sounds = mcl_sounds.node_sound_wood_defaults(), +} + +mcl_torches.register_torch(on_def) + +local on_override = { + on_destruct = function(pos, oldnode) + local node = minetest.get_node(pos) + torch_action_on(pos, node) + end, + mesecons = { + receptor = { + state = mesecon.state.on, + rules = torch_get_output_rules }, - _tt_help = S("Provides redstone power when it's not powered itself"), - } -) + effector = { + state = mesecon.state.off, + rules = torch_get_input_rules, + action_on = torch_action_on, + }, + }, + _tt_help = S("Provides redstone power when it's not powered itself"), +} + +minetest.override_item("mesecons_torch:mesecon_torch_on", on_override) +minetest.override_item("mesecons_torch:mesecon_torch_on_wall", on_override) minetest.register_node("mesecons_torch:redstoneblock", { description = S("Block of Redstone"), diff --git a/mods/ITEMS/mcl_armor/armor.lua b/mods/ITEMS/mcl_armor/armor.lua index c6cadafa86..c53fc417e2 100644 --- a/mods/ITEMS/mcl_armor/armor.lua +++ b/mods/ITEMS/mcl_armor/armor.lua @@ -382,6 +382,7 @@ mcl_player.player_register_model("mcl_armor_character.b3d", { run_walk_mine = {x=461, y=480}, sit_mount = {x=484, y=484}, die = {x=498, y=498}, + fly = {x=502, y=581}, }, }) @@ -410,6 +411,8 @@ mcl_player.player_register_model("mcl_armor_character_female.b3d", { run_walk = {x=440, y=459}, run_walk_mine = {x=461, y=480}, sit_mount = {x=484, y=484}, + die = {x=498, y=498}, + fly = {x=502, y=581}, }, }) diff --git a/mods/ITEMS/mcl_armor/init.lua b/mods/ITEMS/mcl_armor/init.lua index 0328ce8e3b..8bb0a05899 100644 --- a/mods/ITEMS/mcl_armor/init.lua +++ b/mods/ITEMS/mcl_armor/init.lua @@ -9,6 +9,20 @@ dofile(modpath.."/alias.lua") local longdesc = S("This is a piece of equippable armor which reduces the amount of damage you receive.") local usage = S("To equip it, put it on the corresponding armor slot in your inventory menu.") +minetest.register_tool("mcl_armor:elytra", { + description = S("Elytra"), + _doc_items_longdesc = longdesc, + _doc_items_usagehelp = usage, + inventory_image = "mcl_armor_inv_elytra.png", + groups = {armor_torso=1, mcl_armor_points=0, mcl_armor_uses=10, enchantability=0}, + sounds = { + _mcl_armor_equip = "mcl_armor_equip_leather", + _mcl_armor_unequip = "mcl_armor_unequip_leather", + }, + on_place = armor.on_armor_use, + on_secondary_use = armor.on_armor_use, +}) + minetest.register_tool("mcl_armor:helmet_leather", { description = S("Leather Cap"), _doc_items_longdesc = longdesc, @@ -323,7 +337,7 @@ local craft_ingreds = { gold = { "mcl_core:gold_ingot", "mcl_core:gold_nugget" }, diamond = { "mcl_core:diamond" }, chain = { nil, "mcl_core:iron_nugget"} , -} +} for k, v in pairs(craft_ingreds) do -- material diff --git a/mods/ITEMS/mcl_armor/models/mcl_armor_character.b3d b/mods/ITEMS/mcl_armor/models/mcl_armor_character.b3d index a658f753c3..952850ba38 100644 Binary files a/mods/ITEMS/mcl_armor/models/mcl_armor_character.b3d and b/mods/ITEMS/mcl_armor/models/mcl_armor_character.b3d differ diff --git a/mods/ITEMS/mcl_armor/models/mcl_armor_character.blend b/mods/ITEMS/mcl_armor/models/mcl_armor_character.blend index 12869b59df..a41a1031ab 100644 Binary files a/mods/ITEMS/mcl_armor/models/mcl_armor_character.blend and b/mods/ITEMS/mcl_armor/models/mcl_armor_character.blend differ diff --git a/mods/ITEMS/mcl_armor/models/mcl_armor_character_female.b3d b/mods/ITEMS/mcl_armor/models/mcl_armor_character_female.b3d index 44494d1eca..59b8675740 100644 Binary files a/mods/ITEMS/mcl_armor/models/mcl_armor_character_female.b3d and b/mods/ITEMS/mcl_armor/models/mcl_armor_character_female.b3d differ diff --git a/mods/ITEMS/mcl_armor/models/mcl_armor_character_female.blend b/mods/ITEMS/mcl_armor/models/mcl_armor_character_female.blend index c854a49e5e..a0cd5b5198 100644 Binary files a/mods/ITEMS/mcl_armor/models/mcl_armor_character_female.blend and b/mods/ITEMS/mcl_armor/models/mcl_armor_character_female.blend differ diff --git a/mods/ITEMS/mcl_armor/textures/mcl_armor_elytra.png b/mods/ITEMS/mcl_armor/textures/mcl_armor_elytra.png new file mode 100644 index 0000000000..b05a4975a7 Binary files /dev/null and b/mods/ITEMS/mcl_armor/textures/mcl_armor_elytra.png differ diff --git a/mods/ITEMS/mcl_armor/textures/mcl_armor_inv_elytra.png b/mods/ITEMS/mcl_armor/textures/mcl_armor_inv_elytra.png new file mode 100644 index 0000000000..f5d5cfda6c Binary files /dev/null and b/mods/ITEMS/mcl_armor/textures/mcl_armor_inv_elytra.png differ diff --git a/mods/ITEMS/mcl_bows/bow.lua b/mods/ITEMS/mcl_bows/bow.lua index 87820071de..45912384ea 100644 --- a/mods/ITEMS/mcl_bows/bow.lua +++ b/mods/ITEMS/mcl_bows/bow.lua @@ -133,7 +133,7 @@ S("The speed and damage of the arrow increases the longer you charge. The regula _doc_items_usagehelp = S("To use the bow, you first need to have at least one arrow anywhere in your inventory (unless in Creative Mode). Hold down the right mouse button to charge, release to shoot."), _doc_items_durability = BOW_DURABILITY, inventory_image = "mcl_bows_bow.png", - wield_scale = { x = 1.8, y = 1.8, z = 1 }, + wield_scale = mcl_vars.tool_wield_scale, stack_max = 1, range = 4, -- Trick to disable digging as well @@ -198,7 +198,7 @@ for level=0, 2 do description = S("Bow"), _doc_items_create_entry = false, inventory_image = "mcl_bows_bow_"..level..".png", - wield_scale = { x = 1.8, y = 1.8, z = 1 }, + wield_scale = mcl_vars.tool_wield_scale, stack_max = 1, range = 0, -- Pointing range to 0 to prevent punching with bow :D groups = {not_in_creative_inventory=1, not_in_craft_guide=1, bow=1, enchantability=1}, diff --git a/mods/ITEMS/mcl_bows/mod.conf b/mods/ITEMS/mcl_bows/mod.conf index cfb4234740..79ae42436d 100644 --- a/mods/ITEMS/mcl_bows/mod.conf +++ b/mods/ITEMS/mcl_bows/mod.conf @@ -1,6 +1,6 @@ name = mcl_bows author = Arcelmi description = This mod adds bows and arrows for MineClone 2. -depends = controls, mcl_particles, mcl_enchanting +depends = controls, mcl_particles, mcl_enchanting, mcl_init optional_depends = awards, mcl_achievements, mcl_core, mcl_mobitems, playerphysics, doc, doc_identifier, mesecons_button diff --git a/mods/ITEMS/mcl_chests/textures/mcl_chests_normal.png b/mods/ITEMS/mcl_chests/textures/mcl_chests_normal.png index 5133f53ff7..9974f60d57 100644 Binary files a/mods/ITEMS/mcl_chests/textures/mcl_chests_normal.png and b/mods/ITEMS/mcl_chests/textures/mcl_chests_normal.png differ diff --git a/mods/ITEMS/mcl_chests/textures/mcl_chests_normal_double.png b/mods/ITEMS/mcl_chests/textures/mcl_chests_normal_double.png index a8793f600b..f7357ddaa8 100644 Binary files a/mods/ITEMS/mcl_chests/textures/mcl_chests_normal_double.png and b/mods/ITEMS/mcl_chests/textures/mcl_chests_normal_double.png differ diff --git a/mods/ITEMS/mcl_chests/textures/mcl_chests_trapped.png b/mods/ITEMS/mcl_chests/textures/mcl_chests_trapped.png index de21d8f2fa..ebbca8a6ae 100644 Binary files a/mods/ITEMS/mcl_chests/textures/mcl_chests_trapped.png and b/mods/ITEMS/mcl_chests/textures/mcl_chests_trapped.png differ diff --git a/mods/ITEMS/mcl_chests/textures/mcl_chests_trapped_double.png b/mods/ITEMS/mcl_chests/textures/mcl_chests_trapped_double.png index 95f768f97c..88ff45825f 100644 Binary files a/mods/ITEMS/mcl_chests/textures/mcl_chests_trapped_double.png and b/mods/ITEMS/mcl_chests/textures/mcl_chests_trapped_double.png differ diff --git a/mods/ITEMS/mcl_core/crafting.lua b/mods/ITEMS/mcl_core/crafting.lua index a0ad38a777..7a2b6a5c8a 100644 --- a/mods/ITEMS/mcl_core/crafting.lua +++ b/mods/ITEMS/mcl_core/crafting.lua @@ -46,6 +46,56 @@ minetest.register_craft({ } }) +-- Stripped Bark +minetest.register_craft({ + output = "mcl_core:stripped_oak_bark 3", + recipe = { + { "mcl_core:stripped_oak", "mcl_core:stripped_oak" }, + { "mcl_core:stripped_oak", "mcl_core:stripped_oak" }, + } +}) + +minetest.register_craft({ + output = "mcl_core:stripped_acacia_bark 3", + recipe = { + { "mcl_core:stripped_acacia", "mcl_core:stripped_acacia" }, + { "mcl_core:stripped_acacia", "mcl_core:stripped_acacia" }, + } +}) + +minetest.register_craft({ + output = "mcl_core:stripped_dark_oak_bark 3", + recipe = { + { "mcl_core:stripped_dark_oak", "mcl_core:stripped_dark_oak" }, + { "mcl_core:stripped_dark_oak", "mcl_core:stripped_dark_oak" }, + } +}) + +minetest.register_craft({ + output = "mcl_core:stripped_birch_bark 3", + recipe = { + { "mcl_core:stripped_birch", "mcl_core:stripped_birch" }, + { "mcl_core:stripped_birch", "mcl_core:stripped_birch" }, + } +}) + +minetest.register_craft({ + output = "mcl_core:stripped_spruce_bark 3", + recipe = { + { "mcl_core:stripped_spruce", "mcl_core:stripped_spruce" }, + { "mcl_core:stripped_spruce", "mcl_core:stripped_spruce" }, + } +}) + +minetest.register_craft({ + output = "mcl_core:stripped_jungle_bark 3", + recipe = { + { "mcl_core:stripped_jungle", "mcl_core:stripped_jungle" }, + { "mcl_core:stripped_jungle", "mcl_core:stripped_jungle" }, + } +}) + + minetest.register_craft({ type = 'shapeless', output = 'mcl_core:mossycobble', diff --git a/mods/ITEMS/mcl_core/nodes_liquid.lua b/mods/ITEMS/mcl_core/nodes_liquid.lua index 0479c7f723..4696a629ac 100644 --- a/mods/ITEMS/mcl_core/nodes_liquid.lua +++ b/mods/ITEMS/mcl_core/nodes_liquid.lua @@ -7,10 +7,10 @@ local WATER_ALPHA = 179 local WATER_VISC = 1 local LAVA_VISC = 7 local LIGHT_LAVA = minetest.LIGHT_MAX -local USE_TEXTURE_ALPHA +local USE_TEXTURE_ALPHA = true + if minetest.features.use_texture_alpha_string_modes then USE_TEXTURE_ALPHA = "blend" - WATER_ALPHA = nil end local lava_death_messages = { @@ -40,7 +40,6 @@ minetest.register_node("mcl_core:water_flowing", { }, sounds = mcl_sounds.node_sound_water_defaults(), is_ground_content = false, - alpha = WATER_ALPHA, use_texture_alpha = USE_TEXTURE_ALPHA, paramtype = "light", paramtype2 = "flowingliquid", @@ -86,7 +85,6 @@ S("• When water is directly below lava, the water turns into stone."), }, sounds = mcl_sounds.node_sound_water_defaults(), is_ground_content = false, - alpha = WATER_ALPHA, use_texture_alpha = USE_TEXTURE_ALPHA, paramtype = "light", walkable = false, diff --git a/mods/ITEMS/mcl_core/nodes_trees.lua b/mods/ITEMS/mcl_core/nodes_trees.lua index 197846ebcc..4af3eef34c 100644 --- a/mods/ITEMS/mcl_core/nodes_trees.lua +++ b/mods/ITEMS/mcl_core/nodes_trees.lua @@ -1,4 +1,4 @@ --- Tree nodes: Wood, Wooden Planks, Sapling, Leaves +-- Tree nodes: Wood, Wooden Planks, Sapling, Leaves, Stripped Wood local S = minetest.get_translator("mcl_core") local mod_screwdriver = minetest.get_modpath("screwdriver") ~= nil @@ -48,6 +48,166 @@ local register_tree_trunk = function(subname, description_trunk, description_bar }) end +-- Register stripped trunk +minetest.register_node("mcl_core:stripped_oak", { + description = "Stripped Oak Log", + _doc_items_longdesc = "Stripped Oak Log is a log that has been stripped of it's bark.", + tiles = {"mcl_core_stripped_oak_top.png", "mcl_core_stripped_oak_top.png", "mcl_core_stripped_oak_side.png"}, + is_ground_content = false, + paramtype2 = "facedir", + on_place = mcl_util.rotate_axis, + groups = {handy=1,axey=1, flammable=2, building_block=1, material_wood=1, fire_encouragement=5, fire_flammability=5, tree=1}, + sounds = mcl_sounds.node_sound_wood_defaults(), + _mcl_blast_resistance = 10, + _mcl_hardness = 2, +}) + +minetest.register_node("mcl_core:stripped_acacia", { + description = "Stripped Acacia Log", + _doc_items_longdesc = "Stripped Acacia Log is a log that has been stripped of it's bark.", + tiles = {"mcl_core_stripped_acacia_top.png", "mcl_core_stripped_acacia_top.png", "mcl_core_stripped_acacia_side.png"}, + is_ground_content = false, + paramtype2 = "facedir", + on_place = mcl_util.rotate_axis, + groups = {handy=1,axey=1, flammable=2, building_block=1, material_wood=1, fire_encouragement=5, fire_flammability=5, tree=1}, + sounds = mcl_sounds.node_sound_wood_defaults(), + _mcl_blast_resistance = 10, + _mcl_hardness = 2, +}) + +minetest.register_node("mcl_core:stripped_dark_oak", { + description = "Stripped Dark Oak Log", + _doc_items_longdesc = "Stripped Dark Oak Log is a log that has been stripped of it's bark.", + tiles = {"mcl_core_stripped_dark_oak_top.png", "mcl_core_stripped_dark_oak_top.png", "mcl_core_stripped_dark_oak_side.png"}, + is_ground_content = false, + paramtype2 = "facedir", + on_place = mcl_util.rotate_axis, + groups = {handy=1,axey=1, flammable=2, building_block=1, material_wood=1, fire_encouragement=5, fire_flammability=5, tree=1}, + sounds = mcl_sounds.node_sound_wood_defaults(), + _mcl_blast_resistance = 10, + _mcl_hardness = 2, +}) + +minetest.register_node("mcl_core:stripped_birch", { + description = "Stripped Birch Log", + _doc_items_longdesc = "Stripped Birch Log is a log that has been stripped of it's bark.", + tiles = {"mcl_core_stripped_birch_top.png", "mcl_core_stripped_birch_top.png", "mcl_core_stripped_birch_side.png"}, + is_ground_content = false, + paramtype2 = "facedir", + on_place = mcl_util.rotate_axis, + groups = {handy=1,axey=1, flammable=2, building_block=1, material_wood=1, fire_encouragement=5, fire_flammability=5, tree=1}, + sounds = mcl_sounds.node_sound_wood_defaults(), + _mcl_blast_resistance = 10, + _mcl_hardness = 2, +}) + +minetest.register_node("mcl_core:stripped_spruce", { + description = "Stripped Spruce Log", + _doc_items_longdesc = "Stripped Spruce Log is a log that has been stripped of it's bark.", + tiles = {"mcl_core_stripped_spruce_top.png", "mcl_core_stripped_spruce_top.png", "mcl_core_stripped_spruce_side.png"}, + is_ground_content = false, + paramtype2 = "facedir", + on_place = mcl_util.rotate_axis, + groups = {handy=1,axey=1, flammable=2, building_block=1, material_wood=1, fire_encouragement=5, fire_flammability=5, tree=1}, + sounds = mcl_sounds.node_sound_wood_defaults(), + _mcl_blast_resistance = 10, + _mcl_hardness = 2, +}) + +minetest.register_node("mcl_core:stripped_jungle", { + description = "Stripped Jungle Log", + _doc_items_longdesc = "Stripped Jungle Log is a log that has been stripped of it's bark.", + tiles = {"mcl_core_stripped_jungle_top.png", "mcl_core_stripped_jungle_top.png", "mcl_core_stripped_jungle_side.png"}, + is_ground_content = false, + paramtype2 = "facedir", + on_place = mcl_util.rotate_axis, + groups = {handy=1,axey=1, flammable=2, building_block=1, material_wood=1, fire_encouragement=5, fire_flammability=5, tree=1}, + sounds = mcl_sounds.node_sound_wood_defaults(), + _mcl_blast_resistance = 10, + _mcl_hardness = 2, +}) + + +-- Register stripped bark +minetest.register_node("mcl_core:stripped_oak_bark", { + description = "Stripped Oak Bark", + _doc_items_longdesc = "Stripped Oak Bark is a bark that has been stripped.", + tiles = {"mcl_core_stripped_oak_side.png"}, + is_ground_content = false, + paramtype2 = "facedir", + on_place = mcl_util.rotate_axis, + groups = {handy=1,axey=1, flammable=2, building_block=1, material_wood=1, fire_encouragement=5, fire_flammability=5}, + sounds = mcl_sounds.node_sound_wood_defaults(), + _mcl_blast_resistance = 10, + _mcl_hardness = 2, +}) + +minetest.register_node("mcl_core:stripped_acacia_bark", { + description = "Stripped Acacia Bark", + _doc_items_longdesc = "Stripped Acacia Bark is a bark that has been stripped.", + tiles = {"mcl_core_stripped_acacia_side.png"}, + is_ground_content = false, + paramtype2 = "facedir", + on_place = mcl_util.rotate_axis, + groups = {handy=1,axey=1, flammable=2, building_block=1, material_wood=1, fire_encouragement=5, fire_flammability=5}, + sounds = mcl_sounds.node_sound_wood_defaults(), + _mcl_blast_resistance = 10, + _mcl_hardness = 2, +}) + +minetest.register_node("mcl_core:stripped_dark_oak_bark", { + description = "Stripped Dark Oak Bark", + _doc_items_longdesc = "Stripped Dark Oak Bark is a bark that has been stripped.", + tiles = {"mcl_core_stripped_dark_oak_side.png"}, + is_ground_content = false, + paramtype2 = "facedir", + on_place = mcl_util.rotate_axis, + groups = {handy=1,axey=1, flammable=2, building_block=1, material_wood=1, fire_encouragement=5, fire_flammability=5}, + sounds = mcl_sounds.node_sound_wood_defaults(), + _mcl_blast_resistance = 10, + _mcl_hardness = 2, +}) + +minetest.register_node("mcl_core:stripped_birch_bark", { + description = "Stripped Birch Bark", + _doc_items_longdesc = "Stripped Birch Bark is a bark that has been stripped.", + tiles = {"mcl_core_stripped_birch_side.png"}, + is_ground_content = false, + paramtype2 = "facedir", + on_place = mcl_util.rotate_axis, + groups = {handy=1,axey=1, flammable=2, building_block=1, material_wood=1, fire_encouragement=5, fire_flammability=5}, + sounds = mcl_sounds.node_sound_wood_defaults(), + _mcl_blast_resistance = 10, + _mcl_hardness = 2, +}) + +minetest.register_node("mcl_core:stripped_spruce_bark", { + description = "Stripped Spruce Bark", + _doc_items_longdesc = "Stripped Spruce Bark is a bark that has been stripped.", + tiles = {"mcl_core_stripped_spruce_side.png"}, + is_ground_content = false, + paramtype2 = "facedir", + on_place = mcl_util.rotate_axis, + groups = {handy=1,axey=1, flammable=2, building_block=1, material_wood=1, fire_encouragement=5, fire_flammability=5}, + sounds = mcl_sounds.node_sound_wood_defaults(), + _mcl_blast_resistance = 10, + _mcl_hardness = 2, +}) + +minetest.register_node("mcl_core:stripped_jungle_bark", { + description = "Stripped Jungle Bark", + _doc_items_longdesc = "Stripped Jungles Bark is a bark that has been stripped.", + tiles = {"mcl_core_stripped_jungle_side.png"}, + is_ground_content = false, + paramtype2 = "facedir", + on_place = mcl_util.rotate_axis, + groups = {handy=1,axey=1, flammable=2, building_block=1, material_wood=1, fire_encouragement=5, fire_flammability=5}, + sounds = mcl_sounds.node_sound_wood_defaults(), + _mcl_blast_resistance = 10, + _mcl_hardness = 2, +}) + + local register_wooden_planks = function(subname, description, tiles) minetest.register_node("mcl_core:"..subname, { description = description, @@ -226,4 +386,4 @@ register_leaves("birchleaves", S("Birch Leaves"), S("Birch leaves are grown from -- Node aliases minetest.register_alias("default:acacia_tree", "mcl_core:acaciatree") -minetest.register_alias("default:acacia_leaves", "mcl_core:acacialeaves") +minetest.register_alias("default:acacia_leaves", "mcl_core:acacialeaves") \ No newline at end of file diff --git a/mods/ITEMS/mcl_core/textures/mcl_core_stripped_acacia_side.png b/mods/ITEMS/mcl_core/textures/mcl_core_stripped_acacia_side.png new file mode 100644 index 0000000000..2e2de8dbeb Binary files /dev/null and b/mods/ITEMS/mcl_core/textures/mcl_core_stripped_acacia_side.png differ diff --git a/mods/ITEMS/mcl_core/textures/mcl_core_stripped_acacia_top.png b/mods/ITEMS/mcl_core/textures/mcl_core_stripped_acacia_top.png new file mode 100644 index 0000000000..0746884de9 Binary files /dev/null and b/mods/ITEMS/mcl_core/textures/mcl_core_stripped_acacia_top.png differ diff --git a/mods/ITEMS/mcl_core/textures/mcl_core_stripped_birch_side.png b/mods/ITEMS/mcl_core/textures/mcl_core_stripped_birch_side.png new file mode 100644 index 0000000000..a27739c1e6 Binary files /dev/null and b/mods/ITEMS/mcl_core/textures/mcl_core_stripped_birch_side.png differ diff --git a/mods/ITEMS/mcl_core/textures/mcl_core_stripped_birch_top.png b/mods/ITEMS/mcl_core/textures/mcl_core_stripped_birch_top.png new file mode 100644 index 0000000000..e5290422d4 Binary files /dev/null and b/mods/ITEMS/mcl_core/textures/mcl_core_stripped_birch_top.png differ diff --git a/mods/ITEMS/mcl_core/textures/mcl_core_stripped_dark_oak_side.png b/mods/ITEMS/mcl_core/textures/mcl_core_stripped_dark_oak_side.png new file mode 100644 index 0000000000..9345a14dc2 Binary files /dev/null and b/mods/ITEMS/mcl_core/textures/mcl_core_stripped_dark_oak_side.png differ diff --git a/mods/ITEMS/mcl_core/textures/mcl_core_stripped_dark_oak_top.png b/mods/ITEMS/mcl_core/textures/mcl_core_stripped_dark_oak_top.png new file mode 100644 index 0000000000..fbc45938f3 Binary files /dev/null and b/mods/ITEMS/mcl_core/textures/mcl_core_stripped_dark_oak_top.png differ diff --git a/mods/ITEMS/mcl_core/textures/mcl_core_stripped_jungle_side.png b/mods/ITEMS/mcl_core/textures/mcl_core_stripped_jungle_side.png new file mode 100644 index 0000000000..74f9f03d5e Binary files /dev/null and b/mods/ITEMS/mcl_core/textures/mcl_core_stripped_jungle_side.png differ diff --git a/mods/ITEMS/mcl_core/textures/mcl_core_stripped_jungle_top.png b/mods/ITEMS/mcl_core/textures/mcl_core_stripped_jungle_top.png new file mode 100644 index 0000000000..bfa54d8fe5 Binary files /dev/null and b/mods/ITEMS/mcl_core/textures/mcl_core_stripped_jungle_top.png differ diff --git a/mods/ITEMS/mcl_core/textures/mcl_core_stripped_oak_side.png b/mods/ITEMS/mcl_core/textures/mcl_core_stripped_oak_side.png new file mode 100644 index 0000000000..3bdffd76e1 Binary files /dev/null and b/mods/ITEMS/mcl_core/textures/mcl_core_stripped_oak_side.png differ diff --git a/mods/ITEMS/mcl_core/textures/mcl_core_stripped_oak_top.png b/mods/ITEMS/mcl_core/textures/mcl_core_stripped_oak_top.png new file mode 100644 index 0000000000..b07c726135 Binary files /dev/null and b/mods/ITEMS/mcl_core/textures/mcl_core_stripped_oak_top.png differ diff --git a/mods/ITEMS/mcl_core/textures/mcl_core_stripped_spruce_side.png b/mods/ITEMS/mcl_core/textures/mcl_core_stripped_spruce_side.png new file mode 100644 index 0000000000..11ea15bebb Binary files /dev/null and b/mods/ITEMS/mcl_core/textures/mcl_core_stripped_spruce_side.png differ diff --git a/mods/ITEMS/mcl_core/textures/mcl_core_stripped_spruce_top.png b/mods/ITEMS/mcl_core/textures/mcl_core_stripped_spruce_top.png new file mode 100644 index 0000000000..7699612b6b Binary files /dev/null and b/mods/ITEMS/mcl_core/textures/mcl_core_stripped_spruce_top.png differ diff --git a/mods/ITEMS/mcl_end/building.lua b/mods/ITEMS/mcl_end/building.lua index 3dcf0671ef..94fd264342 100644 --- a/mods/ITEMS/mcl_end/building.lua +++ b/mods/ITEMS/mcl_end/building.lua @@ -169,7 +169,16 @@ minetest.register_node("mcl_end:dragon_egg", { sounds = mcl_sounds.node_sound_stone_defaults(), _mcl_blast_resistance = 9, _mcl_hardness = 3, - -- TODO: Make dragon egg teleport on punching + on_punch = function(pos, node) + local max_dist = vector.new(15, 7, 15) + local positions = minetest.find_nodes_in_area(vector.subtract(pos, max_dist), vector.add(pos, max_dist), "air", false) + if #positions > 0 then + local tpos = positions[math.random(#positions)] + minetest.remove_node(pos) + minetest.set_node(tpos, node) + minetest.check_for_falling(tpos) + end + end, }) diff --git a/mods/ITEMS/mcl_end/end_crystal.lua b/mods/ITEMS/mcl_end/end_crystal.lua index b6b9fdd6a5..720d8ed8db 100644 --- a/mods/ITEMS/mcl_end/end_crystal.lua +++ b/mods/ITEMS/mcl_end/end_crystal.lua @@ -58,8 +58,9 @@ local function spawn_crystal(pos) for _, crystal in pairs(crystals) do crystal_explode(crystal) end - local dragon = minetest.add_entity(vector.add(portal_center, {x = 0, y = 10, z = 0}), "mobs_mc:enderdragon") - dragon:get_luaentity()._egg_spawn_pos = minetest.pos_to_string(vector.add(portal_center, {x = 0, y = 4, z = 0})) + local portal_pos = vector.add(portal_center, vector.new(-3, -1, -3)) + mcl_structures.call_struct(portal_pos, "end_exit_portal") + minetest.add_entity(vector.add(portal_pos, vector.new(3, 11, 3)), "mobs_mc:enderdragon"):get_luaentity()._portal_pos = portal_pos end minetest.register_entity("mcl_end:crystal", { @@ -70,7 +71,7 @@ minetest.register_entity("mcl_end:crystal", { collisionbox = {-1, 0.5, -1, 1, 2.5, 1}, mesh = "mcl_end_crystal.b3d", textures = {"mcl_end_crystal.png"}, - collide_with_objects = true, + collide_with_objects = false, }, on_punch = crystal_explode, on_activate = set_crystal_animation, @@ -78,6 +79,54 @@ minetest.register_entity("mcl_end:crystal", { _hittable_by_projectile = true }) +minetest.register_entity("mcl_end:crystal_beam", { + initial_properties = { + physical = false, + visual = "cube", + visual_size = {x = 1, y = 1, z = 1}, + textures = { + "mcl_end_crystal_beam.png^[transformR90", + "mcl_end_crystal_beam.png^[transformR90", + "mcl_end_crystal_beam.png", + "mcl_end_crystal_beam.png", + "blank.png", + "blank.png", + }, + static_save = false, + }, + spin = 0, + init = function(self, dragon, crystal) + self.dragon, self.crystal = dragon, crystal + crystal:get_luaentity().beam = self.object + dragon:get_luaentity().beam = self.object + end, + on_deactivate = function(self) + if self.crystal and self.crystal:get_luaentity() then + self.crystal:get_luaentity().beam = nil + end + if self.dragon and self.dragon:get_luaentity() then + self.dragon:get_luaentity().beam = nil + end + end, + on_step = function(self, dtime) + if self.dragon and self.dragon:get_luaentity() and self.crystal and self.crystal:get_luaentity() then + self.spin = self.spin + dtime * math.pi * 2 / 4 + local dragon_pos, crystal_pos = self.dragon:get_pos(), self.crystal:get_pos() + + dragon_pos.y = dragon_pos.y + 4 + crystal_pos.y = crystal_pos.y + 2 + + self.object:set_pos(vector.divide(vector.add(dragon_pos, crystal_pos), 2)) + local rot = vector.dir_to_rotation(vector.direction(dragon_pos, crystal_pos)) + rot.z = self.spin + self.object:set_rotation(rot) + self.object:set_properties({visual_size = {x = 0.5, y = 0.5, z = vector.distance(dragon_pos, crystal_pos)}}) + else + self.object:remove() + end + end, +}) + minetest.register_craftitem("mcl_end:crystal", { inventory_image = "mcl_end_crystal_item.png", description = S("End Crystal"), diff --git a/mods/ITEMS/mcl_end/textures/mcl_end_crystal_beam.png b/mods/ITEMS/mcl_end/textures/mcl_end_crystal_beam.png new file mode 100644 index 0000000000..1259a5d0ec Binary files /dev/null and b/mods/ITEMS/mcl_end/textures/mcl_end_crystal_beam.png differ diff --git a/mods/ITEMS/mcl_farming/hoes.lua b/mods/ITEMS/mcl_farming/hoes.lua index a45b382ed6..db470b9992 100644 --- a/mods/ITEMS/mcl_farming/hoes.lua +++ b/mods/ITEMS/mcl_farming/hoes.lua @@ -68,7 +68,7 @@ minetest.register_tool("mcl_farming:hoe_wood", { _doc_items_usagehelp = hoe_usagehelp, _doc_items_hidden = false, inventory_image = "farming_tool_woodhoe.png", - wield_scale = { x = 1.8, y = 1.8, z = 1 }, + wield_scale = mcl_vars.tool_wield_scale, on_place = hoe_on_place_function(uses.wood), groups = { tool=1, hoe=1, enchantability=15 }, tool_capabilities = { @@ -111,7 +111,7 @@ minetest.register_tool("mcl_farming:hoe_stone", { _doc_items_longdesc = hoe_longdesc, _doc_items_usagehelp = hoe_usagehelp, inventory_image = "farming_tool_stonehoe.png", - wield_scale = { x = 1.8, y = 1.8, z = 1 }, + wield_scale = mcl_vars.tool_wield_scale, on_place = hoe_on_place_function(uses.stone), groups = { tool=1, hoe=1, enchantability=5 }, tool_capabilities = { @@ -149,7 +149,7 @@ minetest.register_tool("mcl_farming:hoe_iron", { _doc_items_longdesc = hoe_longdesc, _doc_items_usagehelp = hoe_usagehelp, inventory_image = "farming_tool_steelhoe.png", - wield_scale = { x = 1.8, y = 1.8, z = 1 }, + wield_scale = mcl_vars.tool_wield_scale, on_place = hoe_on_place_function(uses.iron), groups = { tool=1, hoe=1, enchantability=14 }, tool_capabilities = { @@ -195,7 +195,7 @@ minetest.register_tool("mcl_farming:hoe_gold", { _doc_items_longdesc = hoe_longdesc, _doc_items_usagehelp = hoe_usagehelp, inventory_image = "farming_tool_goldhoe.png", - wield_scale = { x = 1.8, y = 1.8, z = 1 }, + wield_scale = mcl_vars.tool_wield_scale, on_place = hoe_on_place_function(uses.gold), groups = { tool=1, hoe=1, enchantability=22 }, tool_capabilities = { @@ -242,7 +242,7 @@ minetest.register_tool("mcl_farming:hoe_diamond", { _doc_items_longdesc = hoe_longdesc, _doc_items_usagehelp = hoe_usagehelp, inventory_image = "farming_tool_diamondhoe.png", - wield_scale = { x = 1.8, y = 1.8, z = 1 }, + wield_scale = mcl_vars.tool_wield_scale, on_place = hoe_on_place_function(uses.diamond), groups = { tool=1, hoe=1, enchantability=10 }, tool_capabilities = { diff --git a/mods/ITEMS/mcl_farming/mod.conf b/mods/ITEMS/mcl_farming/mod.conf index 9ab36c39f1..fe4bc15640 100644 --- a/mods/ITEMS/mcl_farming/mod.conf +++ b/mods/ITEMS/mcl_farming/mod.conf @@ -1,3 +1,3 @@ name = mcl_farming -depends = mcl_core, mcl_sounds, mcl_wool, mcl_torches, mcl_weather, mobs_mc, mcl_colors +depends = mcl_core, mcl_sounds, mcl_wool, mcl_torches, mcl_weather, mobs_mc, mcl_colors, mcl_init optional_depends = mcl_armor, doc diff --git a/mods/ITEMS/mcl_fishing/init.lua b/mods/ITEMS/mcl_fishing/init.lua index 228d490ea6..2bd0ed5155 100644 --- a/mods/ITEMS/mcl_fishing/init.lua +++ b/mods/ITEMS/mcl_fishing/init.lua @@ -303,8 +303,8 @@ local flying_bobber_ENTITY={ collisionbox = {0,0,0,0,0,0}, pointable = false, - get_staticdata = get_staticdata, - on_activate = on_activate, + get_staticdata = mcl_throwing.get_staticdata, + on_activate = mcl_throwing.on_activate, _lastpos={}, _thrower = nil, diff --git a/mods/ITEMS/mcl_ocean/kelp.lua b/mods/ITEMS/mcl_ocean/kelp.lua index 3aefe85f8e..9670943da6 100644 --- a/mods/ITEMS/mcl_ocean/kelp.lua +++ b/mods/ITEMS/mcl_ocean/kelp.lua @@ -1,6 +1,9 @@ -- TODO: whenever it becomes possible to fully implement kelp without the -- plantlike_rooted limitation, please update accordingly. -- +-- TODO: whenever it becomes possible to make kelp grow infinitely without +-- resorting to making intermediate kelp stem node, please update accordingly. +-- -- TODO: In MC, you can't actually destroy kelp by bucket'ing water in the middle. -- However, because of the plantlike_rooted hack, we'll just allow it for now. @@ -191,17 +194,18 @@ end -- Converts param2 to kelp height. +-- For the special case where the max param2 is reached, interpret that as the +-- 16th kelp stem. function kelp.get_height(param2) - return math_floor(param2 / 16) + return math_floor(param2 / 16) + math_floor(param2 % 16 / 8) end -- Obtain pos and node of the tip of kelp. -function kelp.get_tip(pos, param2) - -- Optional params: param2 - local height = kelp.get_height(param2 or mt_get_node(pos).param2) - local pos_tip = {x=pos.x, y=pos.y, z=pos.z} - pos_tip.y = pos_tip.y + height + 1 +function kelp.get_tip(pos, height) + -- Optional params: height + local height = height or kelp.get_height(mt_get_node(pos).param2) + local pos_tip = {x=pos.x, y=pos.y+height+1, z=pos.z} return pos_tip, mt_get_node(pos_tip), height end @@ -210,7 +214,7 @@ end function kelp.find_unsubmerged(pos, node, height) -- Optional params: node, height local node = node or mt_get_node(pos) - local height = height or kelp.get_height(node.param2) + local height = height or ((node.param2 >= 0 and node.param2 < 16) and 1) or kelp.get_height(node.param2) local walk_pos = {x=pos.x, z=pos.z} local y = pos.y @@ -227,7 +231,8 @@ end -- Obtain next param2. function kelp.next_param2(param2) - return param2+16 - param2 % 16 + -- param2 max value is 255, so adding to 256 causes overflow. + return math_min(param2+16 - param2 % 16, 255); end @@ -311,7 +316,7 @@ function kelp.init_timer(pos, pos_hash) end --- Apply next kelp height. +-- Apply next kelp height. The surface is swapped. so on_construct is skipped. function kelp.next_height(pos, node, pos_tip, node_tip, submerged, downward_flowing) -- Modified params: node -- Optional params: node, set_node, pos_tip, node_tip, submerged, downward_flowing @@ -367,9 +372,9 @@ end -- Drops the items for detached kelps. -function kelp.detach_drop(pos, param2) - -- Optional params: param2 - local height = kelp.get_height(param2 or mt_get_node(pos).param2) +function kelp.detach_drop(pos, height) + -- Optional params: height + local height = height or kelp.get_height(mt_get_node(pos).param2) local y = pos.y local walk_pos = {x=pos.x, z=pos.z} for i=1,height do @@ -384,17 +389,18 @@ end -- Synonymous to digging the kelp. -- NOTE: this is intended for whenever kelp truly becomes segmented plants -- instead of rooted to the floor. Don't try to remove dig_pos. -function kelp.detach_dig(dig_pos, pos, node, drop) - -- Optional params: drop +function kelp.detach_dig(dig_pos, pos, drop, node, height) + -- Optional params: drop, node, height - local param2 = node.param2 + local node = node or mt_get_node(pos) + local height = height or kelp.get_height(node.param2) -- pos.y points to the surface, offset needed to point to the first kelp. local new_height = dig_pos.y - (pos.y+1) -- Digs the entire kelp. if new_height <= 0 then if drop then - kelp.detach_drop(dig_pos, param2) + kelp.detach_drop(dig_pos, height) end mt_set_node(pos, { name=mt_registered_nodes[node.name].node_dig_prediction, @@ -404,7 +410,7 @@ function kelp.detach_dig(dig_pos, pos, node, drop) -- Digs the kelp beginning at a height. else if drop then - kelp.detach_drop(dig_pos, param2 - new_height) + kelp.detach_drop(dig_pos, height - new_height) end mt_swap_node(pos, {name=node.name, param=node.param, param2=16*new_height}) end @@ -416,7 +422,7 @@ end -------------------------------------------------------------------------------- function kelp.surface_on_dig(pos, node, digger) - kelp.detach_dig(pos, pos, node, true) + kelp.detach_dig(pos, pos, true, node) end @@ -430,11 +436,11 @@ function kelp.surface_on_timer(pos) local pos_hash -- Update detahed kelps - local dig_pos = kelp.find_unsubmerged(pos, node) + local dig_pos,_, height = kelp.find_unsubmerged(pos, node) if dig_pos then pos_hash = mt_hash_node_position(pos) mt_sound_play(mt_registered_nodes[node.name].sounds.dug, { gain = 0.5, pos = dig_pos }, true) - kelp.detach_dig(dig_pos, pos, node, true) + kelp.detach_dig(dig_pos, pos, true, node, height) kelp.store_age(kelp.roll_init_age(), pos, pos_hash) end @@ -463,7 +469,7 @@ function kelp.surface_on_destruct(pos) -- on_falling callback. Activated by pistons for falling nodes too. if kelp.is_falling(pos, node) then - kelp.detach_drop(pos, node.param2) + kelp.detach_drop(pos, kelp.get_height(node.param2)) end -- Removes position from queue @@ -474,7 +480,7 @@ end function kelp.surface_on_mvps_move(pos, node, oldpos, nodemeta) -- Pistons moving falling nodes will have already activated on_falling callback. - kelp.detach_dig(pos, pos, node, mt_get_item_group(node.name, "falling_node") ~= 1) + kelp.detach_dig(pos, pos, mt_get_item_group(node.name, "falling_node") ~= 1, node) end @@ -518,7 +524,7 @@ function kelp.kelp_on_place(itemstack, placer, pointed_thing) end - local pos_tip, node_tip, def_tip, new_kelp + local pos_tip, node_tip, def_tip, new_surface, height -- Kelp must also be placed on the top/tip side of the surface/kelp if pos_under.y >= pos_above.y then return itemstack @@ -526,31 +532,33 @@ function kelp.kelp_on_place(itemstack, placer, pointed_thing) -- When placed on kelp. if mt_get_item_group(nu_name, "kelp") == 1 then - pos_tip,node_tip = kelp.get_tip(pos_under, node_under.param2) + height = kelp.get_height(node_under.param2) + pos_tip,node_tip = kelp.get_tip(pos_under, height) def_tip = mt_registered_nodes[node_tip.name] -- When placed on surface. else - new_kelp = false + new_surface = false for _,surface in pairs(kelp.surfaces) do if nu_name == surface.nodename then node_under.name = "mcl_ocean:kelp_" ..surface.name node_under.param2 = 0 - new_kelp = true + new_surface = true break end end -- Surface must support kelp - if not new_kelp then + if not new_surface then return itemstack end pos_tip = pos_above node_tip = mt_get_node(pos_above) def_tip = mt_registered_nodes[node_tip.name] + height = 0 end - -- New kelp must also be submerged in water. + -- Next kelp must also be submerged in water. local downward_flowing = kelp.is_downward_flowing(pos_tip, node_tip) local submerged = kelp.is_submerged(node_tip) if not submerged then @@ -562,14 +570,19 @@ function kelp.kelp_on_place(itemstack, placer, pointed_thing) if def_node.sounds then mt_sound_play(def_node.sounds.place, { gain = 0.5, pos = pos_under }, true) end - kelp.next_height(pos_under, node_under, pos_tip, node_tip, def_tip, submerged, downward_flowing) + -- TODO: get rid of rooted plantlike hack + if height < 16 then + kelp.next_height(pos_under, node_under, pos_tip, node_tip, def_tip, submerged, downward_flowing) + else + mt_add_item(pos_tip, "mcl_ocean:kelp") + end if not mt_is_creative_enabled(player_name) then itemstack:take_item() end - -- Initialize age and timer when it's a new kelp + -- Initialize age and timer when it's planted on a new surface. local pos_hash = mt_hash_node_position(pos_under) - if new_kelp then + if new_surface then kelp.init_age(pos_under, nil, pos_hash) kelp.init_timer(pos_under, pos_hash) else diff --git a/mods/ITEMS/mcl_portals/init.lua b/mods/ITEMS/mcl_portals/init.lua index 2fd96afadb..080051ffa4 100644 --- a/mods/ITEMS/mcl_portals/init.lua +++ b/mods/ITEMS/mcl_portals/init.lua @@ -1,6 +1,8 @@ -- Load files -mcl_portals = {} +mcl_portals = { + storage = minetest.get_mod_storage(), +} -- Nether portal: -- Obsidian frame, activated by flint and steel @@ -10,3 +12,5 @@ dofile(minetest.get_modpath("mcl_portals").."/portal_nether.lua") -- Red nether brick block frame, activated by an eye of ender dofile(minetest.get_modpath("mcl_portals").."/portal_end.lua") +dofile(minetest.get_modpath("mcl_portals").."/portal_gateway.lua") + diff --git a/mods/ITEMS/mcl_portals/portal_end.lua b/mods/ITEMS/mcl_portals/portal_end.lua index 0bc0ce57e8..192f5001c0 100644 --- a/mods/ITEMS/mcl_portals/portal_end.lua +++ b/mods/ITEMS/mcl_portals/portal_end.lua @@ -4,11 +4,6 @@ local S = minetest.get_translator("mcl_portals") local SPAWN_MIN = mcl_vars.mg_end_min+70 local SPAWN_MAX = mcl_vars.mg_end_min+98 -local PORTAL_ALPHA = 192 -if minetest.features.use_texture_alpha_string_modes then - PORTAL_ALPHA = nil -end - local mg_name = minetest.get_mapgen_setting("mg_name") local destroy_portal = function(pos) @@ -81,7 +76,6 @@ minetest.register_node("mcl_portals:portal_end", { -- This is 15 in MC. light_source = 14, post_effect_color = {a = 192, r = 0, g = 0, b = 0}, - alpha = PORTAL_ALPHA, after_destruct = destroy_portal, -- This prevents “falling through” collision_box = { @@ -217,6 +211,9 @@ function mcl_portals.end_teleport(obj, pos) -- Look towards the main End island if dim ~= "end" then obj:set_look_horizontal(math.pi/2) + -- Show credits + else + mcl_credits.show(obj) end mcl_worlds.dimension_change(obj, mcl_worlds.pos_to_dimension(target)) minetest.sound_play("mcl_portals_teleport", {pos=target, gain=0.5, max_hear_distance = 16}, true) diff --git a/mods/ITEMS/mcl_portals/portal_gateway.lua b/mods/ITEMS/mcl_portals/portal_gateway.lua new file mode 100644 index 0000000000..c738da1a46 --- /dev/null +++ b/mods/ITEMS/mcl_portals/portal_gateway.lua @@ -0,0 +1,118 @@ +local S = minetest.get_translator("mcl_portals") +local storage = mcl_portals.storage + +local gateway_positions = { + {x = 96, y = -26925, z = 0}, + {x = 91, y = -26925, z = 29}, + {x = 77, y = -26925, z = 56}, + {x = 56, y = -26925, z = 77}, + {x = 29, y = -26925, z = 91}, + {x = 0, y = -26925, z = 96}, + {x = -29, y = -26925, z = 91}, + {x = -56, y = -26925, z = 77}, + {x = -77, y = -26925, z = 56}, + {x = -91, y = -26925, z = 29}, + {x = -96, y = -26925, z = 0}, + {x = -91, y = -26925, z = -29}, + {x = -77, y = -26925, z = -56}, + {x = -56, y = -26925, z = -77}, + {x = -29, y = -26925, z = -91}, + {x = 0, y = -26925, z = -96}, + {x = 29, y = -26925, z = -91}, + {x = 56, y = -26925, z = -77}, + {x = 77, y = -26925, z = -56}, + {x = 91, y = -26925, z = -29}, +} + +local function spawn_gateway_portal(pos, dest_str) + local path = minetest.get_modpath("mcl_structures").."/schematics/mcl_structures_end_gateway_portal.mts" + return mcl_structures.place_schematic(vector.add(pos, vector.new(-1, -2, -1)), path, "0", nil, true, nil, dest_str and function() + minetest.get_meta(pos):set_string("mcl_portals:gateway_destination", dest_str) + end) +end + +function mcl_portals.spawn_gateway_portal() + local id = storage:get_int("gateway_last_id") + 1 + local pos = gateway_positions[id] + if not pos then return end + storage:set_int("gateway_last_id", id) + spawn_gateway_portal(pos) +end + +local gateway_def = table.copy(minetest.registered_nodes["mcl_portals:portal_end"]) +gateway_def.description = S("End Gateway Portal") +gateway_def._tt_help = S("Used to construct end gateway portals") +gateway_def._doc_items_longdesc = S("An End gateway portal teleports creatures and objects to the outer End (and back!).") +gateway_def._doc_items_usagehelp = S("Throw an ender pearl into the portal to teleport. Entering an Gateway portal near the Overworld teleports you to the outer End. At this destination another gateway portal will be constructed, which you can use to get back.") +gateway_def.after_destruct = nil +gateway_def.drawtype = "normal" +gateway_def.node_box = nil +gateway_def.walkable = true +gateway_def.tiles[3] = nil +minetest.register_node("mcl_portals:portal_gateway", gateway_def) + +local function find_destination_pos(minp, maxp) + for y = maxp.y, minp.y, -1 do + for x = maxp.x, minp.x, -1 do + for z = maxp.z, minp.z, -1 do + local pos = vector.new(x, y, z) + local nn = minetest.get_node(pos).name + if nn ~= "ignore" and nn ~= "mcl_portals:portal_gateway" and nn ~= "mcl_core:bedrock" then + local def = minetest.registered_nodes[nn] + if def and def.walkable then + return vector.add(pos, vector.new(0, 1.5, 0)) + end + end + end + end + end +end + +local preparing = {} + +local function teleport(pos, obj) + local meta = minetest.get_meta(pos) + local dest_portal + local dest_str = meta:get_string("mcl_portals:gateway_destination") + local pos_str = minetest.pos_to_string(pos) + if dest_str == "" then + dest_portal = vector.multiply(vector.direction(vector.new(0, pos.y, 0), pos), math.random(768, 1024)) + dest_portal.y = -26970 + spawn_gateway_portal(dest_portal, pos_str) + meta:set_string("mcl_portals:gateway_destination", minetest.pos_to_string(dest_portal)) + else + dest_portal = minetest.string_to_pos(dest_str) + end + local minp = vector.subtract(dest_portal, vector.new(5, 40, 5)) + local maxp = vector.add(dest_portal, vector.new(5, 10, 5)) + preparing[pos_str] = true + minetest.emerge_area(minp, maxp, function(blockpos, action, calls_remaining, param) + if calls_remaining < 1 then + if obj and obj:is_player() or obj:get_luaentity() then + obj:set_pos(find_destination_pos(minp, maxp) or vector.add(dest_portal, vector.new(0, 3.5, 0))) + end + preparing[pos_str] = false + end + end) +end + +minetest.register_abm({ + label = "End gateway portal teleportation", + nodenames = {"mcl_portals:portal_gateway"}, + interval = 0.1, + chance = 1, + action = function(pos) + if preparing[minetest.pos_to_string(pos)] then return end + for _, obj in pairs(minetest.get_objects_inside_radius(pos, 1)) do + if obj:get_hp() > 0 then + local luaentity = obj:get_luaentity() + if luaentity and luaentity.name == "mcl_throwing:ender_pearl" then + obj:remove() + obj = luaentity._thrower + end + teleport(pos, obj) + return + end + end + end, +}) diff --git a/mods/ITEMS/mcl_portals/portal_nether.lua b/mods/ITEMS/mcl_portals/portal_nether.lua index e842edf812..1d9fe2efbe 100644 --- a/mods/ITEMS/mcl_portals/portal_nether.lua +++ b/mods/ITEMS/mcl_portals/portal_nether.lua @@ -1,5 +1,7 @@ local S = minetest.get_translator("mcl_portals") +local SCAN_2_MAP_CHUNKS = true -- slower but helps to find more suitable places + -- Localize functions for better performance local abs = math.abs local ceil = math.ceil @@ -26,11 +28,10 @@ local DISTANCE_MAX = 128 local PORTAL = "mcl_portals:portal" local OBSIDIAN = "mcl_core:obsidian" local O_Y_MIN, O_Y_MAX = max(mcl_vars.mg_overworld_min, -31), min(mcl_vars.mg_overworld_max_official, 2048) -local N_Y_MIN, N_Y_MAX = mcl_vars.mg_bedrock_nether_bottom_min, mcl_vars.mg_bedrock_nether_top_max +local N_Y_MIN, N_Y_MAX = mcl_vars.mg_bedrock_nether_bottom_min, mcl_vars.mg_bedrock_nether_top_max - H_MIN local O_DY, N_DY = O_Y_MAX - O_Y_MIN + 1, N_Y_MAX - N_Y_MIN + 1 -- Alpha and particles -local ALPHA = minetest.features.use_texture_alpha_string_modes and 192 local node_particles_allowed = minetest.settings:get("mcl_node_particles") or "none" local node_particles_levels = { none=0, low=1, medium=2, high=3 } local PARTICLES = node_particles_levels[node_particles_allowed] @@ -48,7 +49,7 @@ local chatter = {} local queue = {} local chunks = {} -local storage = minetest.get_mod_storage() +local storage = mcl_portals.storage local exits = {} local keys = minetest.deserialize(storage:get_string("nether_exits_keys") or "return {}") or {} for _, key in pairs(keys) do @@ -194,7 +195,7 @@ end local function destroy_nether_portal(pos, node) if not node then return end local nn, orientation = node.name, node.param2 - local obsidian = nn == OBSIDIAN + local obsidian = nn == OBSIDIAN local check_remove = function(pos, orientation) local node = get_node(pos) @@ -263,7 +264,6 @@ minetest.register_node(PORTAL, { drop = "", light_source = 11, post_effect_color = {a = 180, r = 51, g = 7, b = 89}, - alpha = ALPHA, node_box = { type = "fixed", fixed = { @@ -488,6 +488,16 @@ local function ecb_scan_area_2(blockpos, action, calls_remaining, param) create_portal_2(pos0, name, obj) return end + + if param.next_chunk_1 and param.next_chunk_2 and param.next_pos then + local pos1, pos2, p = param.next_chunk_1, param.next_chunk_2, param.next_pos + if p.x >= pos1.x and p.x <= pos2.x and p.y >= pos1.y and p.y <= pos2.y and p.z >= pos1.z and p.z <= pos2.z then + log("action", "[mcl_portals] Making additional search in chunk below, because current one doesn't contain any air space for portal, target pos "..pos_to_string(p)) + minetest.emerge_area(pos1, pos2, ecb_scan_area_2, {pos = p, pos1 = pos1, pos2 = pos2, name=name, obj=obj}) + return + end + end + log("action", "[mcl_portals] found no space, reverting to target pos "..pos_to_string(pos).." - creating a portal") if pos.y < lava then pos.y = lava + 1 @@ -509,18 +519,35 @@ local function create_portal(pos, limit1, limit2, name, obj) -- we need to emerge the area here, but currently (mt5.4/mcl20.71) map generation is slow -- so we'll emerge single chunk only: 5x5x5 blocks, 80x80x80 nodes maximum + -- and maybe one more chunk from below if (SCAN_2_MAP_CHUNKS = true) local pos1 = add(mul(mcl_vars.pos_to_chunk(pos), mcl_vars.chunk_size_in_nodes), mcl_vars.central_chunk_offset_in_nodes) local pos2 = add(pos1, mcl_vars.chunk_size_in_nodes - 1) + if not SCAN_2_MAP_CHUNKS then + if limit1 and limit1.x and limit1.y and limit1.z then + pos1 = {x = max(min(limit1.x, pos.x), pos1.x), y = max(min(limit1.y, pos.y), pos1.y), z = max(min(limit1.z, pos.z), pos1.z)} + end + if limit2 and limit2.x and limit2.y and limit2.z then + pos2 = {x = min(max(limit2.x, pos.x), pos2.x), y = min(max(limit2.y, pos.y), pos2.y), z = min(max(limit2.z, pos.z), pos2.z)} + end + minetest.emerge_area(pos1, pos2, ecb_scan_area_2, {pos = vector.new(pos), pos1 = pos1, pos2 = pos2, name=name, obj=obj}) + return + end + + -- Basically the copy of code above, with minor additions to continue the search in single additional chunk below: + local next_chunk_1 = {x = pos1.x, y = pos1.y - mcl_vars.chunk_size_in_nodes, z = pos1.z} + local next_chunk_2 = add(next_chunk_1, mcl_vars.chunk_size_in_nodes - 1) + local next_pos = {x = pos.x, y=max(next_chunk_2.y, limit1.y), z = pos.z} if limit1 and limit1.x and limit1.y and limit1.z then pos1 = {x = max(min(limit1.x, pos.x), pos1.x), y = max(min(limit1.y, pos.y), pos1.y), z = max(min(limit1.z, pos.z), pos1.z)} + next_chunk_1 = {x = max(min(limit1.x, next_pos.x), next_chunk_1.x), y = max(min(limit1.y, next_pos.y), next_chunk_1.y), z = max(min(limit1.z, next_pos.z), next_chunk_1.z)} end if limit2 and limit2.x and limit2.y and limit2.z then pos2 = {x = min(max(limit2.x, pos.x), pos2.x), y = min(max(limit2.y, pos.y), pos2.y), z = min(max(limit2.z, pos.z), pos2.z)} + next_chunk_2 = {x = min(max(limit2.x, next_pos.x), next_chunk_2.x), y = min(max(limit2.y, next_pos.y), next_chunk_2.y), z = min(max(limit2.z, next_pos.z), next_chunk_2.z)} end - - minetest.emerge_area(pos1, pos2, ecb_scan_area_2, {pos = vector.new(pos), pos1 = pos1, pos2 = pos2, name=name, obj=obj}) + minetest.emerge_area(pos1, pos2, ecb_scan_area_2, {pos = vector.new(pos), pos1 = pos1, pos2 = pos2, name=name, obj=obj, next_chunk_1 = next_chunk_1, next_chunk_2 = next_chunk_2, next_pos = next_pos}) end local function available_for_nether_portal(p) diff --git a/mods/ITEMS/mcl_sponges/init.lua b/mods/ITEMS/mcl_sponges/init.lua index b832c01c6c..75a99b0f13 100644 --- a/mods/ITEMS/mcl_sponges/init.lua +++ b/mods/ITEMS/mcl_sponges/init.lua @@ -94,6 +94,35 @@ minetest.register_node("mcl_sponges:sponge", { _mcl_hardness = 0.6, }) +function place_wet_sponge(itemstack, placer, pointed_thing) + if pointed_thing.type ~= "node" then + return itemstack + end + -- Use pointed node's on_rightclick function first, if present + local node = minetest.get_node(pointed_thing.under) + if placer and not placer:get_player_control().sneak then + if minetest.registered_nodes[node.name] and minetest.registered_nodes[node.name].on_rightclick then + return minetest.registered_nodes[node.name].on_rightclick(pointed_thing.under, node, placer, itemstack) or itemstack + end + end + + local name = placer:get_player_name() + + if minetest.is_protected(pointed_thing.above, name) then + return itemstack + end + + if mcl_worlds.pos_to_dimension(pointed_thing.above) == "nether" then + minetest.item_place_node(ItemStack("mcl_sponges:sponge"), placer, pointed_thing) + if not minetest.is_creative_enabled(name) then + itemstack:take_item() + end + return itemstack + end + + return minetest.item_place_node(itemstack, placer, pointed_thing) +end + minetest.register_node("mcl_sponges:sponge_wet", { description = S("Waterlogged Sponge"), _tt_help = S("Can be dried in furnace"), @@ -108,6 +137,7 @@ minetest.register_node("mcl_sponges:sponge_wet", { stack_max = 64, sounds = mcl_sounds.node_sound_dirt_defaults(), groups = {handy=1, hoey=1, building_block=1}, + on_place = place_wet_sponge, _mcl_blast_resistance = 0.6, _mcl_hardness = 0.6, }) @@ -127,6 +157,7 @@ if minetest.get_modpath("mclx_core") then stack_max = 64, sounds = mcl_sounds.node_sound_dirt_defaults(), groups = {handy=1, building_block=1}, + on_place = place_wet_sponge, _mcl_blast_resistance = 0.6, _mcl_hardness = 0.6, }) diff --git a/mods/ITEMS/mcl_throwing/API.md b/mods/ITEMS/mcl_throwing/API.md index f2b1c73741..41a47223ac 100644 --- a/mods/ITEMS/mcl_throwing/API.md +++ b/mods/ITEMS/mcl_throwing/API.md @@ -33,3 +33,9 @@ Handle creative mode, and throw params. * entity_name: the name of the entity to throw * velocity: (optional) velocity overide (can be nil) + +## mcl_throwing.get_staticdata(self) +Must be used in entity def if you want the entity to be saved after unloading mapblock. + +## mcl_throwing.on_activate(self, staticdata, dtime_s) +Must be used in entity def if you want the entity to be saved after unloading mapblock. diff --git a/mods/ITEMS/mcl_throwing/init.lua b/mods/ITEMS/mcl_throwing/init.lua index 4d6dcfe5c9..09a34c12f5 100644 --- a/mods/ITEMS/mcl_throwing/init.lua +++ b/mods/ITEMS/mcl_throwing/init.lua @@ -58,7 +58,7 @@ function mcl_throwing.dispense_function(stack, dispenserpos, droppos, dropnode, end -- Staticdata handling because objects may want to be reloaded -local get_staticdata = function(self) +function mcl_throwing.get_staticdata(self) local thrower -- Only save thrower if it's a player name if type(self._thrower) == "string" then @@ -71,7 +71,7 @@ local get_staticdata = function(self) return minetest.serialize(data) end -local on_activate = function(self, staticdata, dtime_s) +function mcl_throwing.on_activate(self, staticdata, dtime_s) local data = minetest.deserialize(staticdata) if data then self._lastpos = data._lastpos diff --git a/mods/ITEMS/mcl_throwing/register.lua b/mods/ITEMS/mcl_throwing/register.lua index 027ff4e938..3d8cc94cfa 100644 --- a/mods/ITEMS/mcl_throwing/register.lua +++ b/mods/ITEMS/mcl_throwing/register.lua @@ -9,8 +9,8 @@ local snowball_ENTITY={ collisionbox = {0,0,0,0,0,0}, pointable = false, - get_staticdata = get_staticdata, - on_activate = on_activate, + get_staticdata = mcl_throwing.get_staticdata, + on_activate = mcl_throwing.on_activate, _thrower = nil, _lastpos={}, @@ -23,8 +23,8 @@ local egg_ENTITY={ collisionbox = {0,0,0,0,0,0}, pointable = false, - get_staticdata = get_staticdata, - on_activate = on_activate, + get_staticdata = mcl_throwing.get_staticdata, + on_activate = mcl_throwing.on_activate, _thrower = nil, _lastpos={}, @@ -38,8 +38,8 @@ local pearl_ENTITY={ collisionbox = {0,0,0,0,0,0}, pointable = false, - get_staticdata = get_staticdata, - on_activate = on_activate, + get_staticdata = mcl_throwing.get_staticdata, + on_activate = mcl_throwing.on_activate, _lastpos={}, _thrower = nil, -- Player ObjectRef of the player who threw the ender pearl @@ -99,7 +99,7 @@ local snowball_on_step = function(self, dtime) local vel = self.object:get_velocity() local node = minetest.get_node(pos) local def = minetest.registered_nodes[node.name] - + -- Destroy when hitting a solid node if self._lastpos.x~=nil then @@ -203,7 +203,7 @@ local pearl_on_step = function(self, dtime) self.object:remove() -- Activate when hitting a solid node or a plant elseif walkable or nn == "mcl_core:vine" or nn == "mcl_core:deadbush" or minetest.get_item_group(nn, "flower") ~= 0 or minetest.get_item_group(nn, "sapling") ~= 0 or minetest.get_item_group(nn, "plant") ~= 0 or minetest.get_item_group(nn, "mushroom") ~= 0 or not def then - local player = minetest.get_player_by_name(self._thrower) + local player = self._thrower and minetest.get_player_by_name(self._thrower) if player then -- Teleport and hurt player diff --git a/mods/ITEMS/mcl_tools/init.lua b/mods/ITEMS/mcl_tools/init.lua index bc6bed09f2..2d804b9bc7 100644 --- a/mods/ITEMS/mcl_tools/init.lua +++ b/mods/ITEMS/mcl_tools/init.lua @@ -70,7 +70,7 @@ local shovel_use = S("To turn a grass block into a grass path, hold the shovel i local shears_longdesc = S("Shears are tools to shear sheep and to mine a few block types. Shears are a special mining tool and can be used to obtain the original item from grass, leaves and similar blocks that require cutting.") local shears_use = S("To shear sheep or carve faceless pumpkins, use the “place” key on them. Faces can only be carved at the side of faceless pumpkins. Mining works as usual, but the drops are different for a few blocks.") -local wield_scale = { x = 1.8, y = 1.8, z = 1 } +local wield_scale = mcl_vars.tool_wield_scale -- Picks minetest.register_tool("mcl_tools:pick_wood", { @@ -352,6 +352,56 @@ minetest.register_tool("mcl_tools:shovel_diamond", { }) -- Axes + +local make_stripped_trunk = function(itemstack, placer, pointed_thing) + if pointed_thing.type == "node" then + local pos = minetest.get_pointed_thing_position(pointed_thing) + local node = minetest.get_node(pos) + local node_name = node.name + if placer and not placer:get_player_control().sneak then + if minetest.registered_nodes[node_name] and minetest.registered_nodes[node_name].on_rightclick then + return minetest.registered_nodes[node_name].on_rightclick(pointed_thing.under, node, placer, itemstack) or itemstack + end + end + if minetest.is_protected(pointed_thing.under, placer:get_player_name()) then + minetest.record_protection_violation(pointed_thing.under, placer:get_player_name()) + return itemstack + end + if not minetest.is_creative_enabled(placer:get_player_name()) then + -- Add wear (as if digging a axey node) + local toolname = itemstack:get_name() + local wear = mcl_autogroup.get_wear(toolname, "axey") + itemstack:add_wear(wear) + end + if node_name == "mcl_core:tree" then + minetest.swap_node(pointed_thing.under, {name="mcl_core:stripped_oak"}) + elseif node_name == "mcl_core:darktree" then + minetest.swap_node(pointed_thing.under, {name="mcl_core:stripped_dark_oak"}) + elseif node_name == "mcl_core:acaciatree" then + minetest.swap_node(pointed_thing.under, {name="mcl_core:stripped_acacia"}) + elseif node_name == "mcl_core:birchtree" then + minetest.swap_node(pointed_thing.under, {name="mcl_core:stripped_birch"}) + elseif node_name == "mcl_core:sprucetree" then + minetest.swap_node(pointed_thing.under, {name="mcl_core:stripped_spruce"}) + elseif node_name == "mcl_core:jungletree" then + minetest.swap_node(pointed_thing.under, {name="mcl_core:stripped_jungle"}) + elseif node_name == "mcl_core:tree_bark" then + minetest.swap_node(pointed_thing.under, {name="mcl_core:stripped_oak_bark"}) + elseif node_name == "mcl_core:darktree_bark" then + minetest.swap_node(pointed_thing.under, {name="mcl_core:stripped_dark_oak_bark"}) + elseif node_name == "mcl_core:acaciatree_bark" then + minetest.swap_node(pointed_thing.under, {name="mcl_core:stripped_acacia_bark"}) + elseif node_name == "mcl_core:birchtree_bark" then + minetest.swap_node(pointed_thing.under, {name="mcl_core:stripped_birch_bark"}) + elseif node_name == "mcl_core:sprucetree_bark" then + minetest.swap_node(pointed_thing.under, {name="mcl_core:stripped_spruce_bark"}) + elseif node_name == "mcl_core:jungletree_bark" then + minetest.swap_node(pointed_thing.under, {name="mcl_core:stripped_jungle_bark"}) + end + end + return itemstack +end + minetest.register_tool("mcl_tools:axe_wood", { description = S("Wooden Axe"), _doc_items_longdesc = axe_longdesc, @@ -365,6 +415,7 @@ minetest.register_tool("mcl_tools:axe_wood", { damage_groups = {fleshy=7}, punch_attack_uses = 30, }, + on_place = make_stripped_trunk, sound = { breaks = "default_tool_breaks" }, _repair_material = "group:wood", _mcl_toollike_wield = true, @@ -384,6 +435,7 @@ minetest.register_tool("mcl_tools:axe_stone", { damage_groups = {fleshy=9}, punch_attack_uses = 66, }, + on_place = make_stripped_trunk, sound = { breaks = "default_tool_breaks" }, _repair_material = "mcl_core:cobble", _mcl_toollike_wield = true, @@ -404,6 +456,7 @@ minetest.register_tool("mcl_tools:axe_iron", { damage_groups = {fleshy=9}, punch_attack_uses = 126, }, + on_place = make_stripped_trunk, sound = { breaks = "default_tool_breaks" }, _repair_material = "mcl_core:iron_ingot", _mcl_toollike_wield = true, @@ -423,6 +476,7 @@ minetest.register_tool("mcl_tools:axe_gold", { damage_groups = {fleshy=7}, punch_attack_uses = 17, }, + on_place = make_stripped_trunk, sound = { breaks = "default_tool_breaks" }, _repair_material = "mcl_core:gold_ingot", _mcl_toollike_wield = true, @@ -442,6 +496,7 @@ minetest.register_tool("mcl_tools:axe_diamond", { damage_groups = {fleshy=9}, punch_attack_uses = 781, }, + on_place = make_stripped_trunk, sound = { breaks = "default_tool_breaks" }, _repair_material = "mcl_core:diamond", _mcl_toollike_wield = true, diff --git a/mods/ITEMS/mcl_tools/mod.conf b/mods/ITEMS/mcl_tools/mod.conf index f40547c26b..d2d93197b7 100644 --- a/mods/ITEMS/mcl_tools/mod.conf +++ b/mods/ITEMS/mcl_tools/mod.conf @@ -1,2 +1,2 @@ name = mcl_tools -depends = mcl_sounds +depends = mcl_sounds, mcl_init diff --git a/mods/ITEMS/mcl_torches/api.lua b/mods/ITEMS/mcl_torches/api.lua new file mode 100644 index 0000000000..ced566bbd8 --- /dev/null +++ b/mods/ITEMS/mcl_torches/api.lua @@ -0,0 +1,287 @@ +local spawn_flames_floor = function(pos) + -- Flames + mcl_particles.add_node_particlespawner(pos, { + amount = 8, + time = 0, + minpos = vector.add(pos, { x = -0.1, y = 0.05, z = -0.1 }), + maxpos = vector.add(pos, { x = 0.1, y = 0.15, z = 0.1 }), + minvel = { x = -0.01, y = 0, z = -0.01 }, + maxvel = { x = 0.01, y = 0.1, z = 0.01 }, + minexptime = 0.3, + maxexptime = 0.6, + minsize = 0.7, + maxsize = 2, + texture = "mcl_particles_flame.png", + glow = minetest.registered_nodes[minetest.get_node(pos).name].light_source, + }, "low") + -- Smoke + mcl_particles.add_node_particlespawner(pos, { + amount = 0.5, + time = 0, + minpos = vector.add(pos, { x = -1/16, y = 0.04, z = -1/16 }), + maxpos = vector.add(pos, { x = -1/16, y = 0.06, z = -1/16 }), + minvel = { x = 0, y = 0.5, z = 0 }, + maxvel = { x = 0, y = 0.6, z = 0 }, + minexptime = 2.0, + maxexptime = 2.0, + minsize = 1.5, + maxsize = 1.5, + texture = "mcl_particles_smoke_anim.png", + animation = { + type = "vertical_frames", + aspect_w = 8, + aspect_h = 8, + length = 2.05, + }, + }, "medium") +end + +local spawn_flames_wall = function(pos) + local minrelpos, maxrelpos + local node = minetest.get_node(pos) + local dir = minetest.wallmounted_to_dir(node.param2) + if dir.x < 0 then + minrelpos = { x = -0.38, y = 0.04, z = -0.1 } + maxrelpos = { x = -0.2, y = 0.14, z = 0.1 } + elseif dir.x > 0 then + minrelpos = { x = 0.2, y = 0.04, z = -0.1 } + maxrelpos = { x = 0.38, y = 0.14, z = 0.1 } + elseif dir.z < 0 then + minrelpos = { x = -0.1, y = 0.04, z = -0.38 } + maxrelpos = { x = 0.1, y = 0.14, z = -0.2 } + elseif dir.z > 0 then + minrelpos = { x = -0.1, y = 0.04, z = 0.2 } + maxrelpos = { x = 0.1, y = 0.14, z = 0.38 } + else + return + end + -- Flames + mcl_particles.add_node_particlespawner(pos, { + amount = 8, + time = 0, + minpos = vector.add(pos, minrelpos), + maxpos = vector.add(pos, maxrelpos), + minvel = { x = -0.01, y = 0, z = -0.01 }, + maxvel = { x = 0.01, y = 0.1, z = 0.01 }, + minexptime = 0.3, + maxexptime = 0.6, + minsize = 0.7, + maxsize = 2, + texture = "mcl_particles_flame.png", + glow = minetest.registered_nodes[node.name].light_source, + }, "low") + -- Smoke + mcl_particles.add_node_particlespawner(pos, { + amount = 0.5, + time = 0, + minpos = vector.add(pos, minrelpos), + maxpos = vector.add(pos, maxrelpos), + minvel = { x = 0, y = 0.5, z = 0 }, + maxvel = { x = 0, y = 0.6, z = 0 }, + minexptime = 2.0, + maxexptime = 2.0, + minsize = 1.5, + maxsize = 1.5, + texture = "mcl_particles_smoke_anim.png", + animation = { + type = "vertical_frames", + aspect_w = 8, + aspect_h = 8, + length = 2.05, + }, + }, "medium") +end + +local remove_flames = function(pos) + mcl_particles.delete_node_particlespawners(pos) +end + +-- +-- 3d torch part +-- + +-- Check if placement at given node is allowed +local function check_placement_allowed(node, wdir) + -- Torch placement rules: Disallow placement on some nodes. General rule: Solid, opaque, full cube collision box nodes are allowed. + -- Special allowed nodes: + -- * soul sand + -- * mob spawner + -- * chorus flower + -- * glass, barrier, ice + -- * Fence, wall, end portal frame with ender eye: Only on top + -- * Slab, stairs: Only on top if upside down + + -- Special forbidden nodes: + -- * Piston, sticky piston + local def = minetest.registered_nodes[node.name] + if not def then + return false + -- No ceiling torches + elseif wdir == 0 then + return false + elseif not def.buildable_to then + if node.name ~= "mcl_core:ice" and node.name ~= "mcl_nether:soul_sand" and node.name ~= "mcl_mobspawners:spawner" and node.name ~= "mcl_core:barrier" and node.name ~= "mcl_end:chorus_flower" and node.name ~= "mcl_end:chorus_flower_dead" and (not def.groups.glass) and + ((not def.groups.solid) or (not def.groups.opaque)) then + -- Only allow top placement on these nodes + if node.name == "mcl_end:dragon_egg" or node.name == "mcl_portals:end_portal_frame_eye" or def.groups.fence == 1 or def.groups.wall or def.groups.slab_top == 1 or def.groups.anvil or def.groups.pane or (def.groups.stair == 1 and minetest.facedir_to_dir(node.param2).y ~= 0) then + if wdir ~= 1 then + return false + end + else + return false + end + elseif minetest.get_item_group(node.name, "piston") >= 1 then + return false + end + end + return true +end + +function mcl_torches.register_torch(def) + local itemstring = minetest.get_current_modname() .. ":" .. def.name + local itemstring_wall = itemstring .. "_wall" + + def.light = def.light or minetest.LIGHT_MAX + def.mesh_floor = def.mesh_floor or "mcl_torches_torch_floor.obj" + def.mesh_wall = def.mesh_wall or "mcl_torches_torch_wall.obj" + + local groups = def.groups or {} + + groups.attached_node = 1 + groups.torch = 1 + groups.torch_particles = def.particles and 1 + groups.dig_by_water = 1 + groups.destroy_by_lava_flow = 1 + groups.dig_by_piston = 1 + + local floordef = { + description = def.description, + _doc_items_longdesc = def.doc_items_longdesc, + _doc_items_usagehelp = def.doc_items_usagehelp, + _doc_items_hidden = def.doc_items_hidden, + _doc_items_create_entry = def._doc_items_create_entry, + drawtype = "mesh", + mesh = def.mesh_floor, + inventory_image = def.icon, + wield_image = def.icon, + tiles = def.tiles, + use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "opaque" or false, + paramtype = "light", + paramtype2 = "wallmounted", + sunlight_propagates = true, + is_ground_content = false, + walkable = false, + liquids_pointable = false, + light_source = def.light, + groups = groups, + drop = def.drop or itemstring, + selection_box = { + type = "wallmounted", + wall_top = {-1/16, -1/16, -1/16, 1/16, 0.5, 1/16}, + wall_bottom = {-1/16, -0.5, -1/16, 1/16, 1/16, 1/16}, + }, + sounds = def.sounds, + node_placement_prediction = "", + on_place = function(itemstack, placer, pointed_thing) + if pointed_thing.type ~= "node" then + -- no interaction possible with entities, for now. + return itemstack + end + + local under = pointed_thing.under + local node = minetest.get_node(under) + local def = minetest.registered_nodes[node.name] + if not def then return itemstack end + + -- Call on_rightclick if the pointed node defines it + if placer and not placer:get_player_control().sneak then + if minetest.registered_nodes[node.name] and minetest.registered_nodes[node.name].on_rightclick then + return minetest.registered_nodes[node.name].on_rightclick(under, node, placer, itemstack) or itemstack + end + end + + local above = pointed_thing.above + local wdir = minetest.dir_to_wallmounted({x = under.x - above.x, y = under.y - above.y, z = under.z - above.z}) + + if check_placement_allowed(node, wdir) == false then + return itemstack + end + + local itemstring = itemstack:get_name() + local fakestack = ItemStack(itemstack) + local idef = fakestack:get_definition() + local retval + + if wdir == 1 then + retval = fakestack:set_name(itemstring) + else + retval = fakestack:set_name(itemstring_wall) + end + if not retval then + return itemstack + end + + local success + itemstack, success = minetest.item_place(fakestack, placer, pointed_thing, wdir) + itemstack:set_name(itemstring) + + if success and idef.sounds and idef.sounds.place then + minetest.sound_play(idef.sounds.place, {pos=under, gain=1}, true) + end + return itemstack + end, + on_rotate = false, + on_construct = def.particles and spawn_flames_floor, + on_destruct = def.particles and remove_flames, + } + minetest.register_node(itemstring, floordef) + + local groups_wall = table.copy(groups) + groups_wall.torch = 2 + + local walldef = { + drawtype = "mesh", + mesh = def.mesh_wall, + tiles = def.tiles, + use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "opaque" or false, + paramtype = "light", + paramtype2 = "wallmounted", + sunlight_propagates = true, + is_ground_content = false, + walkable = false, + light_source = def.light, + groups = groups_wall, + drop = def.drop or itemstring, + selection_box = { + type = "wallmounted", + wall_top = {-0.1, -0.1, -0.1, 0.1, 0.5, 0.1}, + wall_bottom = {-0.1, -0.5, -0.1, 0.1, 0.1, 0.1}, + wall_side = {-0.5, -0.5, -0.1, -0.2, 0.1, 0.1}, + }, + sounds = def.sounds, + on_rotate = false, + on_construct = def.particles and spawn_flames_wall, + on_destruct = def.particles and remove_flames, + } + minetest.register_node(itemstring_wall, walldef) + + -- Add entry alias for the Help + if minetest.get_modpath("doc") then + doc.add_entry_alias("nodes", itemstring, "nodes", itemstring_wall) + end +end + +minetest.register_lbm({ + label = "Torch flame particles", + name = "mcl_torches:flames", + nodenames = {"group:torch_particles"}, + run_at_every_load = true, + action = function(pos, node) + local torch_group = minetest.get_node_group(node.name, "torch") + if torch_group == 1 then + spawn_flames_floor(pos) + elseif torch_group == 2 then + spawn_flames_wall(pos) + end + end, +}) diff --git a/mods/ITEMS/mcl_torches/init.lua b/mods/ITEMS/mcl_torches/init.lua index 451a8dfad6..1102731c1f 100644 --- a/mods/ITEMS/mcl_torches/init.lua +++ b/mods/ITEMS/mcl_torches/init.lua @@ -1,338 +1,6 @@ -local S = minetest.get_translator("mcl_torches") -local LIGHT_TORCH = minetest.LIGHT_MAX - -local spawn_flames_floor = function(pos) - -- Flames - mcl_particles.add_node_particlespawner(pos, { - amount = 8, - time = 0, - minpos = vector.add(pos, { x = -0.1, y = 0.05, z = -0.1 }), - maxpos = vector.add(pos, { x = 0.1, y = 0.15, z = 0.1 }), - minvel = { x = -0.01, y = 0, z = -0.01 }, - maxvel = { x = 0.01, y = 0.1, z = 0.01 }, - minexptime = 0.3, - maxexptime = 0.6, - minsize = 0.7, - maxsize = 2, - texture = "mcl_particles_flame.png", - glow = LIGHT_TORCH, - }, "low") - -- Smoke - mcl_particles.add_node_particlespawner(pos, { - amount = 0.5, - time = 0, - minpos = vector.add(pos, { x = -1/16, y = 0.04, z = -1/16 }), - maxpos = vector.add(pos, { x = -1/16, y = 0.06, z = -1/16 }), - minvel = { x = 0, y = 0.5, z = 0 }, - maxvel = { x = 0, y = 0.6, z = 0 }, - minexptime = 2.0, - maxexptime = 2.0, - minsize = 1.5, - maxsize = 1.5, - texture = "mcl_particles_smoke_anim.png", - animation = { - type = "vertical_frames", - aspect_w = 8, - aspect_h = 8, - length = 2.05, - }, - }, "medium") -end - -local spawn_flames_wall = function(pos, param2) - local minrelpos, maxrelpos - local dir = minetest.wallmounted_to_dir(param2) - if dir.x < 0 then - minrelpos = { x = -0.38, y = 0.04, z = -0.1 } - maxrelpos = { x = -0.2, y = 0.14, z = 0.1 } - elseif dir.x > 0 then - minrelpos = { x = 0.2, y = 0.04, z = -0.1 } - maxrelpos = { x = 0.38, y = 0.14, z = 0.1 } - elseif dir.z < 0 then - minrelpos = { x = -0.1, y = 0.04, z = -0.38 } - maxrelpos = { x = 0.1, y = 0.14, z = -0.2 } - elseif dir.z > 0 then - minrelpos = { x = -0.1, y = 0.04, z = 0.2 } - maxrelpos = { x = 0.1, y = 0.14, z = 0.38 } - else - return - end - -- Flames - mcl_particles.add_node_particlespawner(pos, { - amount = 8, - time = 0, - minpos = vector.add(pos, minrelpos), - maxpos = vector.add(pos, maxrelpos), - minvel = { x = -0.01, y = 0, z = -0.01 }, - maxvel = { x = 0.01, y = 0.1, z = 0.01 }, - minexptime = 0.3, - maxexptime = 0.6, - minsize = 0.7, - maxsize = 2, - texture = "mcl_particles_flame.png", - glow = LIGHT_TORCH, - }, "low") - -- Smoke - mcl_particles.add_node_particlespawner(pos, { - amount = 0.5, - time = 0, - minpos = vector.add(pos, minrelpos), - maxpos = vector.add(pos, maxrelpos), - minvel = { x = 0, y = 0.5, z = 0 }, - maxvel = { x = 0, y = 0.6, z = 0 }, - minexptime = 2.0, - maxexptime = 2.0, - minsize = 1.5, - maxsize = 1.5, - texture = "mcl_particles_smoke_anim.png", - animation = { - type = "vertical_frames", - aspect_w = 8, - aspect_h = 8, - length = 2.05, - }, - }, "medium") -end - -local remove_flames = function(pos) - mcl_particles.delete_node_particlespawners(pos) -end - --- --- 3d torch part --- - --- Check if placement at given node is allowed -local function check_placement_allowed(node, wdir) - -- Torch placement rules: Disallow placement on some nodes. General rule: Solid, opaque, full cube collision box nodes are allowed. - -- Special allowed nodes: - -- * soul sand - -- * mob spawner - -- * chorus flower - -- * glass, barrier, ice - -- * Fence, wall, end portal frame with ender eye: Only on top - -- * Slab, stairs: Only on top if upside down - - -- Special forbidden nodes: - -- * Piston, sticky piston - local def = minetest.registered_nodes[node.name] - if not def then - return false - -- No ceiling torches - elseif wdir == 0 then - return false - elseif not def.buildable_to then - if node.name ~= "mcl_core:ice" and node.name ~= "mcl_nether:soul_sand" and node.name ~= "mcl_mobspawners:spawner" and node.name ~= "mcl_core:barrier" and node.name ~= "mcl_end:chorus_flower" and node.name ~= "mcl_end:chorus_flower_dead" and (not def.groups.glass) and - ((not def.groups.solid) or (not def.groups.opaque)) then - -- Only allow top placement on these nodes - if node.name == "mcl_end:dragon_egg" or node.name == "mcl_portals:end_portal_frame_eye" or def.groups.fence == 1 or def.groups.wall or def.groups.slab_top == 1 or def.groups.anvil or def.groups.pane or (def.groups.stair == 1 and minetest.facedir_to_dir(node.param2).y ~= 0) then - if wdir ~= 1 then - return false - end - else - return false - end - elseif minetest.get_item_group(node.name, "piston") >= 1 then - return false - end - end - return true -end - mcl_torches = {} -mcl_torches.register_torch = function(substring, description, doc_items_longdesc, doc_items_usagehelp, icon, mesh_floor, mesh_wall, tiles, light, groups, sounds, moredef, moredef_floor, moredef_wall) - local itemstring = minetest.get_current_modname()..":"..substring - local itemstring_wall = minetest.get_current_modname()..":"..substring.."_wall" - - if light == nil then light = minetest.LIGHT_MAX end - if mesh_floor == nil then mesh_floor = "mcl_torches_torch_floor.obj" end - if mesh_wall == nil then mesh_wall = "mcl_torches_torch_wall.obj" end - if groups == nil then groups = {} end - - groups.attached_node = 1 - groups.torch = 1 - groups.dig_by_water = 1 - groups.destroy_by_lava_flow = 1 - groups.dig_by_piston = 1 - - local floordef = { - description = description, - _doc_items_longdesc = doc_items_longdesc, - _doc_items_usagehelp = doc_items_usagehelp, - drawtype = "mesh", - mesh = mesh_floor, - inventory_image = icon, - wield_image = icon, - tiles = tiles, - use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "opaque" or false, - paramtype = "light", - paramtype2 = "wallmounted", - sunlight_propagates = true, - is_ground_content = false, - walkable = false, - liquids_pointable = false, - light_source = light, - groups = groups, - drop = itemstring, - selection_box = { - type = "wallmounted", - wall_top = {-1/16, -1/16, -1/16, 1/16, 0.5, 1/16}, - wall_bottom = {-1/16, -0.5, -1/16, 1/16, 1/16, 1/16}, - }, - sounds = sounds, - node_placement_prediction = "", - on_place = function(itemstack, placer, pointed_thing) - if pointed_thing.type ~= "node" then - -- no interaction possible with entities, for now. - return itemstack - end - - local under = pointed_thing.under - local node = minetest.get_node(under) - local def = minetest.registered_nodes[node.name] - if not def then return itemstack end - - -- Call on_rightclick if the pointed node defines it - if placer and not placer:get_player_control().sneak then - if minetest.registered_nodes[node.name] and minetest.registered_nodes[node.name].on_rightclick then - return minetest.registered_nodes[node.name].on_rightclick(under, node, placer, itemstack) or itemstack - end - end - - local above = pointed_thing.above - local wdir = minetest.dir_to_wallmounted({x = under.x - above.x, y = under.y - above.y, z = under.z - above.z}) - - if check_placement_allowed(node, wdir) == false then - return itemstack - end - - local itemstring = itemstack:get_name() - local fakestack = ItemStack(itemstack) - local idef = fakestack:get_definition() - local retval - - if wdir == 1 then - retval = fakestack:set_name(itemstring) - else - retval = fakestack:set_name(itemstring_wall) - end - if not retval then - return itemstack - end - - local success - itemstack, success = minetest.item_place(fakestack, placer, pointed_thing, wdir) - itemstack:set_name(itemstring) - - if success and idef.sounds and idef.sounds.place then - minetest.sound_play(idef.sounds.place, {pos=under, gain=1}, true) - end - return itemstack - end, - on_rotate = false, - } - if moredef ~= nil then - for k,v in pairs(moredef) do - floordef[k] = v - end - end - if moredef_floor ~= nil then - for k,v in pairs(moredef_floor) do - floordef[k] = v - end - end - minetest.register_node(itemstring, floordef) - - local groups_wall = table.copy(groups) - groups_wall.torch = 2 - - local walldef = { - drawtype = "mesh", - mesh = mesh_wall, - tiles = tiles, - use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "opaque" or false, - paramtype = "light", - paramtype2 = "wallmounted", - sunlight_propagates = true, - is_ground_content = false, - walkable = false, - light_source = light, - groups = groups_wall, - drop = itemstring, - selection_box = { - type = "wallmounted", - wall_top = {-0.1, -0.1, -0.1, 0.1, 0.5, 0.1}, - wall_bottom = {-0.1, -0.5, -0.1, 0.1, 0.1, 0.1}, - wall_side = {-0.5, -0.5, -0.1, -0.2, 0.1, 0.1}, - }, - sounds = sounds, - on_rotate = false, - } - if moredef ~= nil then - for k,v in pairs(moredef) do - walldef[k] = v - end - end - if moredef_wall ~= nil then - for k,v in pairs(moredef_wall) do - walldef[k] = v - end - end - minetest.register_node(itemstring_wall, walldef) - - - -- Add entry alias for the Help - if minetest.get_modpath("doc") then - doc.add_entry_alias("nodes", itemstring, "nodes", itemstring_wall) - end - -end - -mcl_torches.register_torch("torch", - S("Torch"), - S("Torches are light sources which can be placed at the side or on the top of most blocks."), - nil, - "default_torch_on_floor.png", - "mcl_torches_torch_floor.obj", "mcl_torches_torch_wall.obj", - {{ - name = "default_torch_on_floor_animated.png", - animation = {type = "vertical_frames", aspect_w = 16, aspect_h = 16, length = 3.3} - }}, - LIGHT_TORCH, - {dig_immediate=3, torch=1, deco_block=1}, - mcl_sounds.node_sound_wood_defaults(), - {_doc_items_hidden = false, - on_destruct = function(pos) - remove_flames(pos) - end}, - {on_construct = function(pos) - spawn_flames_floor(pos) - end}, - {on_construct = function(pos) - local node = minetest.get_node(pos) - spawn_flames_wall(pos, node.param2) - end}) - -minetest.register_craft({ - output = "mcl_torches:torch 4", - recipe = { - { "group:coal" }, - { "mcl_core:stick" }, - } -}) - -minetest.register_lbm({ - label = "Torch flame particles", - name = "mcl_torches:flames", - nodenames = {"mcl_torches:torch", "mcl_torches:torch_wall"}, - run_at_every_load = true, - action = function(pos, node) - if node.name == "mcl_torches:torch" then - spawn_flames_floor(pos) - elseif node.name == "mcl_torches:torch_wall" then - spawn_flames_wall(pos, node.param2) - end - end, -}) +local modpath = minetest.get_modpath("mcl_torches") +dofile(modpath .. "/api.lua") +dofile(modpath .. "/register.lua") diff --git a/mods/ITEMS/mcl_torches/register.lua b/mods/ITEMS/mcl_torches/register.lua new file mode 100644 index 0000000000..4218889d94 --- /dev/null +++ b/mods/ITEMS/mcl_torches/register.lua @@ -0,0 +1,27 @@ +local S = minetest.get_translator("mcl_torches") + +mcl_torches.register_torch({ + name = "torch", + description = S("Torch"), + doc_items_longdesc = S("Torches are light sources which can be placed at the side or on the top of most blocks."), + doc_items_hidden = false, + icon = "default_torch_on_floor.png", + tiles = {{ + name = "default_torch_on_floor_animated.png", + animation = {type = "vertical_frames", aspect_w = 16, aspect_h = 16, length = 3.3} + }}, + -- this is 15 in minecraft + light = 14, + groups = {dig_immediate = 3, deco_block = 1}, + sounds = mcl_sounds.node_sound_wood_defaults(), + particles = true, +}) + +minetest.register_craft({ + output = "mcl_torches:torch 4", + recipe = { + {"group:coal"}, + {"mcl_core:stick"}, + } +}) + diff --git a/mods/MAPGEN/mcl_biomes/init.lua b/mods/MAPGEN/mcl_biomes/init.lua index 66de6c13a7..5f0510344b 100644 --- a/mods/MAPGEN/mcl_biomes/init.lua +++ b/mods/MAPGEN/mcl_biomes/init.lua @@ -1484,6 +1484,7 @@ local function register_dimension_biomes() node_stone = "mcl_nether:netherrack", node_water = "air", node_river_water = "air", + node_cave_liquid = "air", y_min = mcl_vars.mg_nether_min, -- FIXME: For some reason the Nether stops generating early if this constant is not added. -- Figure out why. @@ -1501,6 +1502,7 @@ local function register_dimension_biomes() node_filler = "air", node_water = "air", node_river_water = "air", + node_cave_liquid = "air", -- FIXME: For some reason the End stops generating early if this constant is not added. -- Figure out why. y_min = mcl_vars.mg_end_min, diff --git a/mods/MAPGEN/mcl_end_island/init.lua b/mods/MAPGEN/mcl_end_island/init.lua new file mode 100644 index 0000000000..7301762572 --- /dev/null +++ b/mods/MAPGEN/mcl_end_island/init.lua @@ -0,0 +1,34 @@ +local noisemap = PerlinNoiseMap({ + offset = 0.5, + scale = 0.5, + spread = {x = 84, y = 84, z = 84}, + seed = minetest.get_mapgen_setting("seed") + 99999, + octaves = 4, + persist = 0.85, +}, {x = 151, y = 30, z = 151}):get_3d_map({x = 0, y = 0, z = 0}) + +local c_end_stone = minetest.get_content_id("mcl_end:end_stone") +local y_offset = -2 + +minetest.register_on_generated(function(minp, maxp) + if maxp.y < (-27025 + y_offset) or minp.y > (-27000 + y_offset + 4) or maxp.x < -75 or minp.x > 75 or maxp.z < -75 or minp.z > 75 then + return + end + + local vm, emin, emax = minetest.get_mapgen_object("voxelmanip") + local data = vm:get_data() + local area = VoxelArea:new({MinEdge = emin, MaxEdge = emax}) + + for idx in area:iter(math.max(minp.x, -75), math.max(minp.y, -27025 + y_offset + 4), math.max(minp.z, -75), math.min(maxp.x, 75), math.min(maxp.y, -27000 + y_offset), math.min(maxp.z, 75)) do + local pos = area:position(idx) + local y = 27025 + pos.y - y_offset + if noisemap[pos.x + 75 + 1][y + 1][pos.z + 75 + 1] > (math.abs(1 - y / 25) ^ 2 + math.abs(pos.x / 75) ^ 2 + math.abs(pos.z / 75) ^ 2) then + data[idx] = c_end_stone + end + end + + vm:set_data(data) + vm:calc_lighting() + vm:update_liquids() + vm:write_to_map() +end) diff --git a/mods/MAPGEN/mcl_end_island/mod.conf b/mods/MAPGEN/mcl_end_island/mod.conf new file mode 100644 index 0000000000..90432792ca --- /dev/null +++ b/mods/MAPGEN/mcl_end_island/mod.conf @@ -0,0 +1,4 @@ +name = mcl_end_island +author = Fleckenstein +depends = mcl_mapgen_core, mcl_end +description = Generate the end main island for MCL2 diff --git a/mods/MAPGEN/mcl_mapgen_core/init.lua b/mods/MAPGEN/mcl_mapgen_core/init.lua index e08b55ba30..1ee861e4a2 100644 --- a/mods/MAPGEN/mcl_mapgen_core/init.lua +++ b/mods/MAPGEN/mcl_mapgen_core/init.lua @@ -54,12 +54,8 @@ local superflat = mg_name == "flat" and minetest.get_mapgen_setting("mcl_superfl local WITCH_HUT_HEIGHT = 3 -- Exact Y level to spawn witch huts at. This height refers to the height of the floor --- End exit portal position. This is temporary. --- TODO: Remove the exit portal generation when the ender dragon has been implemented. -local END_EXIT_PORTAL_POS = table.copy(mcl_vars.mg_end_platform_pos) -END_EXIT_PORTAL_POS.x = END_EXIT_PORTAL_POS.x - 30 -END_EXIT_PORTAL_POS.z = END_EXIT_PORTAL_POS.z - 3 -END_EXIT_PORTAL_POS.y = END_EXIT_PORTAL_POS.y - 3 +-- End exit portal position +local END_EXIT_PORTAL_POS = vector.new(-3, -27003, -3) -- Content IDs local c_bedrock = minetest.get_content_id("mcl_core:bedrock") @@ -1251,6 +1247,13 @@ local function generate_clay(minp, maxp, blockseed, voxelmanip_data, voxelmanip_ return lvm_used end +local function generate_end_exit_portal(pos) + local dragon_entity = minetest.add_entity(vector.add(pos, vector.new(3, 11, 3)), "mobs_mc:enderdragon"):get_luaentity() + dragon_entity._initial = true + dragon_entity._portal_pos = pos + mcl_structures.call_struct(pos, "end_exit_portal") +end + -- TODO: Try to use more efficient structure generating code local function generate_structures(minp, maxp, blockseed, biomemap) local chunk_has_desert_well = false @@ -1490,11 +1493,11 @@ local function generate_structures(minp, maxp, blockseed, biomemap) for y=maxp.y, minp.y, -1 do local p = {x=END_EXIT_PORTAL_POS.x, y=y, z=END_EXIT_PORTAL_POS.z} if minetest.get_node(p).name == "mcl_end:end_stone" then - mcl_structures.call_struct(p, "end_exit_portal") + generate_end_exit_portal(p) return end end - mcl_structures.call_struct(END_EXIT_PORTAL_POS, "end_exit_portal") + generate_end_exit_portal(END_EXIT_PORTAL_POS) end end diff --git a/mods/MAPGEN/mcl_structures/init.lua b/mods/MAPGEN/mcl_structures/init.lua index f6317bdeb3..b7afd18bbe 100644 --- a/mods/MAPGEN/mcl_structures/init.lua +++ b/mods/MAPGEN/mcl_structures/init.lua @@ -11,10 +11,10 @@ local function ecb_place(blockpos, action, calls_remaining, param) if calls_remaining >= 1 then return end minetest.place_schematic(param.pos, param.schematic, param.rotation, param.replacements, param.force_placement, param.flags) if param.after_placement_callback and param.p1 and param.p2 then - param.after_placement_callback(param.p1, param.p2, param.size, param.rotation, param.pr) + param.after_placement_callback(param.p1, param.p2, param.size, param.rotation, param.pr, param.callback_param) end end -mcl_structures.place_schematic = function(pos, schematic, rotation, replacements, force_placement, flags, after_placement_callback, pr) +mcl_structures.place_schematic = function(pos, schematic, rotation, replacements, force_placement, flags, after_placement_callback, pr, callback_param) local s = loadstring(minetest.serialize_schematic(schematic, "lua", {lua_use_comments = false, lua_num_indent_spaces = 0}) .. " return(schematic)")() if s and s.size then local x, z = s.size.x, s.size.z @@ -32,7 +32,7 @@ mcl_structures.place_schematic = function(pos, schematic, rotation, replacements local p1 = {x=pos.x , y=pos.y , z=pos.z } local p2 = {x=pos.x+x-1, y=pos.y+s.size.y-1, z=pos.z+z-1} minetest.log("verbose","[mcl_structures] size=" ..minetest.pos_to_string(s.size) .. ", rotation=" .. tostring(rotation) .. ", emerge from "..minetest.pos_to_string(p1) .. " to " .. minetest.pos_to_string(p2)) - local param = {pos=vector.new(pos), schematic=s, rotation=rotation, replacements=replacements, force_placement=force_placement, flags=flags, p1=p1, p2=p2, after_placement_callback = after_placement_callback, size=vector.new(s.size), pr=pr} + local param = {pos=vector.new(pos), schematic=s, rotation=rotation, replacements=replacements, force_placement=force_placement, flags=flags, p1=p1, p2=p2, after_placement_callback = after_placement_callback, size=vector.new(s.size), pr=pr, callback_param=callback_param} minetest.emerge_area(p1, p2, ecb_place, param) end end @@ -87,6 +87,10 @@ mcl_structures.call_struct = function(pos, struct_style, rotation, pr) return mcl_structures.generate_fossil(pos, rotation, pr) elseif struct_style == "end_exit_portal" then return mcl_structures.generate_end_exit_portal(pos, rotation) + elseif struct_style == "end_exit_portal_open" then + return mcl_structures.generate_end_exit_portal_open(pos, rotation) + elseif struct_style == "end_gateway_portal" then + return mcl_structures.generate_end_gateway_portal(pos, rotation) elseif struct_style == "end_portal_shrine" then return mcl_structures.generate_end_portal_shrine(pos, rotation, pr) end @@ -314,6 +318,16 @@ end mcl_structures.generate_end_exit_portal = function(pos, rot) local path = minetest.get_modpath("mcl_structures").."/schematics/mcl_structures_end_exit_portal.mts" + return mcl_structures.place_schematic(pos, path, rot or "0", {["mcl_portals:portal_end"] = "air"}, true) +end + +mcl_structures.generate_end_exit_portal_open = function(pos, rot) + local path = minetest.get_modpath("mcl_structures").."/schematics/mcl_structures_end_exit_portal.mts" + return mcl_structures.place_schematic(pos, path, rot or "0", nil, true) +end + +mcl_structures.generate_end_gateway_portal = function(pos, rot) + local path = minetest.get_modpath("mcl_structures").."/schematics/mcl_structures_end_gateway_portal.mts" return mcl_structures.place_schematic(pos, path, rot or "0", nil, true) end @@ -534,7 +548,7 @@ end -- Debug command minetest.register_chatcommand("spawnstruct", { - params = "desert_temple | desert_well | igloo | witch_hut | boulder | ice_spike_small | ice_spike_large | fossil | end_exit_portal | end_portal_shrine | nether_portal | dungeon", + params = "desert_temple | desert_well | igloo | witch_hut | boulder | ice_spike_small | ice_spike_large | fossil | end_exit_portal | end_exit_portal_open | end_gateway_portal | end_portal_shrine | nether_portal | dungeon", description = S("Generate a pre-defined structure near your position."), privs = {debug = true}, func = function(name, param) @@ -566,6 +580,10 @@ minetest.register_chatcommand("spawnstruct", { mcl_structures.generate_ice_spike_large(pos, rot, pr) elseif param == "end_exit_portal" then mcl_structures.generate_end_exit_portal(pos, rot, pr) + elseif param == "end_exit_portal_open" then + mcl_structures.generate_end_exit_portal_open(pos, rot, pr) + elseif param == "end_gateway_portal" then + mcl_structures.generate_end_gateway_portal(pos, rot, pr) elseif param == "end_portal_shrine" then mcl_structures.generate_end_portal_shrine(pos, rot, pr) elseif param == "dungeon" and mcl_dungeons and mcl_dungeons.spawn_dungeon then diff --git a/mods/MAPGEN/mcl_structures/schematics/mcl_structures_end_gateway_portal.mts b/mods/MAPGEN/mcl_structures/schematics/mcl_structures_end_gateway_portal.mts new file mode 100644 index 0000000000..24b06a1c8f Binary files /dev/null and b/mods/MAPGEN/mcl_structures/schematics/mcl_structures_end_gateway_portal.mts differ diff --git a/mods/PLAYER/mcl_hunger/init.lua b/mods/PLAYER/mcl_hunger/init.lua index 5ae45591c2..b640dfdc9b 100644 --- a/mods/PLAYER/mcl_hunger/init.lua +++ b/mods/PLAYER/mcl_hunger/init.lua @@ -89,10 +89,10 @@ function mcl_hunger.update_exhaustion_hud(player, exhaustion) end -- register saturation hudbar -hb.register_hudbar("hunger", 0xFFFFFF, S("Food"), { icon = "hbhunger_icon.png", bgicon = "hbhunger_bgicon.png", bar = "hbhunger_bar.png" }, 20, 20, false) +hb.register_hudbar("hunger", 0xFFFFFF, S("Food"), { icon = "hbhunger_icon.png", bgicon = "hbhunger_bgicon.png", bar = "hbhunger_bar.png" }, 1, 20, 20, false) if mcl_hunger.debug then - hb.register_hudbar("saturation", 0xFFFFFF, S("Saturation"), { icon = "mcl_hunger_icon_saturation.png", bgicon = "mcl_hunger_bgicon_saturation.png", bar = "mcl_hunger_bar_saturation.png" }, mcl_hunger.SATURATION_INIT, 200, false, S("%s: %.1f/%d")) - hb.register_hudbar("exhaustion", 0xFFFFFF, S("Exhaust."), { icon = "mcl_hunger_icon_exhaustion.png", bgicon = "mcl_hunger_bgicon_exhaustion.png", bar = "mcl_hunger_bar_exhaustion.png" }, 0, mcl_hunger.EXHAUST_LVL, false, S("%s: %d/%d")) + hb.register_hudbar("saturation", 0xFFFFFF, S("Saturation"), { icon = "mcl_hunger_icon_saturation.png", bgicon = "mcl_hunger_bgicon_saturation.png", bar = "mcl_hunger_bar_saturation.png" }, 1, mcl_hunger.SATURATION_INIT, 200, false, S("%s: %.1f/%d")) + hb.register_hudbar("exhaustion", 0xFFFFFF, S("Exhaust."), { icon = "mcl_hunger_icon_exhaustion.png", bgicon = "mcl_hunger_bgicon_exhaustion.png", bar = "mcl_hunger_bar_exhaustion.png" }, 1, 0, mcl_hunger.EXHAUST_LVL, false, S("%s: %d/%d")) end minetest.register_on_joinplayer(function(player) diff --git a/mods/PLAYER/mcl_playerplus/init.lua b/mods/PLAYER/mcl_playerplus/init.lua index 767b275e40..5ba73cd600 100644 --- a/mods/PLAYER/mcl_playerplus/init.lua +++ b/mods/PLAYER/mcl_playerplus/init.lua @@ -1,5 +1,8 @@ local S = minetest.get_translator("mcl_playerplus") +local elytra = {} + +local node_stand_return = ":air" local get_connected_players = minetest.get_connected_players local dir_to_yaw = minetest.dir_to_yaw local get_item_group = minetest.get_item_group @@ -22,11 +25,48 @@ local mcl_playerplus_internal = {} local def = {} local time = 0 +local player_collision = function(player) + + local pos = player:get_pos() + local vel = player:get_velocity() + local x = 0 + local z = 0 + local width = .75 + + for _,object in pairs(minetest.get_objects_inside_radius(pos, width)) do + + if object and (object:is_player() + or (object:get_luaentity()._cmi_is_mob == true and object ~= player)) then + + local pos2 = object:get_pos() + local vec = {x = pos.x - pos2.x, z = pos.z - pos2.z} + local force = (width + 0.5) - vector.distance( + {x = pos.x, y = 0, z = pos.z}, + {x = pos2.x, y = 0, z = pos2.z}) + + x = x + (vec.x * force) + z = z + (vec.z * force) + end + end + + return({x,z}) +end + -- converts yaw to degrees local function degrees(rad) return rad * 180.0 / math.pi end +local pi = math.pi +local atann = math.atan +local atan = function(x) + if not x or x ~= x then + return 0 + else + return atann(x) + end +end + local dir_to_pitch = function(dir) local dir2 = vector.normalize(dir) local xz = math.abs(dir.x) + math.abs(dir.z) @@ -82,21 +122,65 @@ end local pitch, name, node_stand, node_stand_below, node_head, node_feet, pos + +minetest.register_on_punchplayer(function(player, hitter, damage) + if hitter:is_player() then + if hitter:get_player_control().aux1 then + player:add_velocity(hitter:get_velocity()) + end + if hitter:get_velocity().y < -6 then + player:set_hp(player:get_hp() - (damage * math.random(0.50 , 0.75))) + local pos = player:get_pos() + minetest.add_particlespawner({ + amount = 15, + time = 0.1, + minpos = {x=pos.x-0.5, y=pos.y-0.5, z=pos.z-0.5}, + maxpos = {x=pos.x+0.5, y=pos.y+0.5, z=pos.z+0.5}, + minvel = {x=-0.1, y=-0.1, z=-0.1}, + maxvel = {x=0.1, y=0.1, z=0.1}, + minacc = {x=0, y=0, z=0}, + maxacc = {x=0, y=0, z=0}, + minexptime = 1, + maxexptime = 2, + minsize = 1.5, + maxsize = 1.5, + collisiondetection = false, + vertical = false, + texture = "mcl_particles_crit.png^[colorize:#bc7a57:127", + }) + end + end +end) + + minetest.register_globalstep(function(dtime) time = time + dtime - -- Update jump status immediately since we need this info in real time. - -- WARNING: This section is HACKY as hell since it is all just based on heuristics. for _,player in pairs(get_connected_players()) do + + local c_x, c_y = unpack(player_collision(player)) + + if player:get_velocity().x + player:get_velocity().y < .5 and c_x + c_y > 0 then + --minetest.chat_send_player(player:get_player_name(), "pushed at " .. c_x + c_y .. " parsecs.") + player:add_velocity({x=c_x, y=0, z=c_y}) + end + + --[[ + _ _ _ + __ _ _ __ (_)_ __ ___ __ _| |_(_) ___ _ __ ___ + / _` | '_ \| | '_ ` _ \ / _` | __| |/ _ \| '_ \/ __| + | (_| | | | | | | | | | | (_| | |_| | (_) | | | \__ \ + \__,_|_| |_|_|_| |_| |_|\__,_|\__|_|\___/|_| |_|___/ + + ]]-- + local controls = player:get_player_control() - name = player:get_player_name() - + local name = player:get_player_name() local meta = player:get_meta() - - local player_velocity = player:get_velocity() or player:get_player_velocity() - + local parent = player:get_attach() local wielded = player:get_wielded_item() + local player_velocity = player:get_velocity() or player:get_player_velocity() -- controls head bone local pitch = - degrees(player:get_look_vertical()) @@ -109,12 +193,43 @@ minetest.register_globalstep(function(dtime) player_vel_yaw = limit_vel_yaw(player_vel_yaw, yaw) player_vel_yaws[name] = player_vel_yaw + if minetest.get_node_or_nil({x=player:get_pos().x, y=player:get_pos().y - 0.5, z=player:get_pos().z}) then + node_stand_return = minetest.get_node_or_nil({x=player:get_pos().x, y=player:get_pos().y - 0.5, z=player:get_pos().z}).name + else + minetest.log("action", "somehow player got of loaded areas") + end + + if player:get_inventory():get_stack("armor", 3):get_name() == "mcl_armor:elytra" and player_velocity.y < -6 and elytra[player] ~= true and is_sprinting(name) then + elytra[player] = true + elseif elytra[player] == true and node_stand_return ~= "air" or elytra[player] == true and player:get_inventory():get_stack("armor", 3):get_name() ~= "mcl_armor:elytra" or player:get_attach() ~= nil then + elytra[player] = false + end + + if elytra[player] == true then + mcl_player.player_set_animation(player, "fly") + playerphysics.add_physics_factor(player, "gravity", "mcl_playerplus:elytra", 0.1) + if player_velocity.y < -1.5 then + player:add_velocity({x=0, y=0.17, z=0}) + end + if math.abs(player_velocity.x) + math.abs(player_velocity.z) < 20 then + local dir = minetest.yaw_to_dir(player:get_look_horizontal()) + player:add_velocity({x=dir.x, y=0, z=dir.z}) + end + if controls.sneak then + if player_velocity.y > -5 then + player:add_velocity({x=0, y=-2, z=0}) + end + end + else + playerphysics.remove_physics_factor(player, "gravity", "mcl_playerplus:elytra") + end + -- controls right and left arms pitch when shooting a bow if string.find(wielded:get_name(), "mcl_bows:bow") and controls.RMB and not controls.LMB and not controls.up and not controls.down and not controls.left and not controls.right then player:set_bone_position("Arm_Right_Pitch_Control", vector.new(-3,5.785,0), vector.new(pitch+90,-30,pitch * -1 * .35)) player:set_bone_position("Arm_Left_Pitch_Control", vector.new(3.5,5.785,0), vector.new(pitch+90,43,pitch * .35)) -- when punching - elseif controls.LMB and player:get_attach() == nil then + elseif controls.LMB and not parent then player:set_bone_position("Arm_Right_Pitch_Control", vector.new(-3,5.785,0), vector.new(pitch,0,0)) player:set_bone_position("Arm_Left_Pitch_Control", vector.new(3,5.785,0), vector.new(0,0,0)) -- when holding an item. @@ -127,38 +242,47 @@ minetest.register_globalstep(function(dtime) player:set_bone_position("Arm_Right_Pitch_Control", vector.new(-3,5.785,0), vector.new(0,0,0)) end - if controls.sneak and player:get_attach() == nil then - -- controls head pitch when sneaking - player:set_bone_position("Head", vector.new(0,6.3,0), vector.new(pitch+36,0,0)) - -- sets eye height, and nametag color accordingly - player:set_properties({collisionbox = {-0.35,0,-0.35,0.35,1.8,0.35}, eye_height = 1.35, nametag_color = { r = 225, b = 225, a = 0, g = 225 }}) - -- sneaking body conrols - player:set_bone_position("Body_Control", vector.new(0,6.3,0), vector.new(0,0,0)) - elseif get_item_group(mcl_playerinfo[name].node_head, "water") ~= 0 and player:get_attach() == nil and is_sprinting(name) == true then + if elytra[player] == true then -- set head pitch and yaw when swimming player:set_bone_position("Head", vector.new(0,6.3,0), vector.new(pitch+90-degrees(dir_to_pitch(player_velocity)),player_vel_yaw - yaw,0)) -- sets eye height, and nametag color accordingly player:set_properties({collisionbox = {-0.35,0,-0.35,0.35,0.8,0.35}, eye_height = 0.5, nametag_color = { r = 225, b = 225, a = 225, g = 225 }}) -- control body bone when swimming player:set_bone_position("Body_Control", vector.new(0,6.3,0), vector.new(degrees(dir_to_pitch(player_velocity)) - 90,-player_vel_yaw + yaw + 180,0)) - - elseif player:get_attach() == nil then + elseif parent then + local parent_yaw = degrees(parent:get_yaw()) + player:set_properties({collisionbox = {-0.312,0,-0.312,0.312,1.8,0.312}, eye_height = 1.5, nametag_color = { r = 225, b = 225, a = 225, g = 225 }}) + player:set_bone_position("Head", vector.new(0,6.3,0), vector.new(pitch, -limit_vel_yaw(yaw, parent_yaw) + parent_yaw, 0)) + player:set_bone_position("Body_Control", vector.new(0,6.3,0), vector.new(0,0,0)) + elseif controls.sneak then + -- controls head pitch when sneaking + player:set_bone_position("Head", vector.new(0,6.3,0), vector.new(pitch+36,0,0)) -- sets eye height, and nametag color accordingly - player:set_properties({collisionbox = {-0.35,0,-0.35,0.35,1.8,0.35}, eye_height = 1.5, nametag_color = { r = 225, b = 225, a = 225, g = 225 }}) + player:set_properties({collisionbox = {-0.312,0,-0.312,0.312,1.8,0.312}, eye_height = 1.35, nametag_color = { r = 225, b = 225, a = 0, g = 225 }}) + -- sneaking body conrols + player:set_bone_position("Body_Control", vector.new(0,6.3,0), vector.new(0,0,0)) + elseif get_item_group(mcl_playerinfo[name].node_head, "water") ~= 0 and is_sprinting(name) == true then + -- set head pitch and yaw when swimming + player:set_bone_position("Head", vector.new(0,6.3,0), vector.new(pitch+90-degrees(dir_to_pitch(player_velocity)),player_vel_yaw - yaw,0)) + -- sets eye height, and nametag color accordingly + player:set_properties({collisionbox = {-0.312,0,-0.312,0.312,0.8,0.312}, eye_height = 0.5, nametag_color = { r = 225, b = 225, a = 225, g = 225 }}) + -- control body bone when swimming + player:set_bone_position("Body_Control", vector.new(0,6.3,0), vector.new(degrees(dir_to_pitch(player_velocity)) - 90,-player_vel_yaw + yaw + 180,0)) + else + -- sets eye height, and nametag color accordingly + player:set_properties({collisionbox = {-0.312,0,-0.312,0.312,1.8,0.312}, eye_height = 1.5, nametag_color = { r = 225, b = 225, a = 225, g = 225 }}) player:set_bone_position("Head", vector.new(0,6.3,0), vector.new(pitch, player_vel_yaw - yaw, 0)) player:set_bone_position("Body_Control", vector.new(0,6.3,0), vector.new(0, -player_vel_yaw + yaw, 0)) - else - local attached = player:get_attach(parent) - local attached_yaw = degrees(attached:get_yaw()) - player:set_properties({collisionbox = {-0.35,0,-0.35,0.35,1.8,0.35}, eye_height = 1.5, nametag_color = { r = 225, b = 225, a = 225, g = 225 }}) - player:set_bone_position("Head", vector.new(0,6.3,0), vector.new(pitch, -limit_vel_yaw(yaw, attached_yaw) + attached_yaw, 0)) - player:set_bone_position("Body_Control", vector.new(0,6.3,0), vector.new(0,0,0)) end + -- Update jump status immediately since we need this info in real time. + -- WARNING: This section is HACKY as hell since it is all just based on heuristics. + if mcl_playerplus_internal[name].jump_cooldown > 0 then mcl_playerplus_internal[name].jump_cooldown = mcl_playerplus_internal[name].jump_cooldown - dtime end + if controls.jump and mcl_playerplus_internal[name].jump_cooldown <= 0 then pos = player:get_pos() diff --git a/mods/PLAYER/wieldview/init.lua b/mods/PLAYER/wieldview/init.lua index 48f3f99bd9..7a349f2f37 100644 --- a/mods/PLAYER/wieldview/init.lua +++ b/mods/PLAYER/wieldview/init.lua @@ -70,6 +70,10 @@ minetest.register_on_joinplayer(function(player) local name = player:get_player_name() wieldview.wielded_item[name] = "" minetest.after(0, function(player) + -- if the player left :is_player() will return nil + if not player:is_player() then + return + end wieldview:update_wielded_item(player) local itementity = minetest.add_entity(player:get_pos(), "wieldview:wieldnode") itementity:set_attach(player, "Hand_Right", vector.new(0, 1, 0), vector.new(90, 0, 45)) @@ -111,10 +115,11 @@ minetest.register_entity("wieldview:wieldnode", { local def = minetest.registered_items[itemstring] self.object:set_properties({glow = def and def.light_source or 0}) - -- wield item as cubic + -- wield item as cubic if armor.textures[self.wielder].wielditem == "blank.png" then self.object:set_properties({textures = {itemstring}}) - else -- wield item as flat + -- wield item as flat + else self.object:set_properties({textures = {""}}) end diff --git a/settingtypes.txt b/settingtypes.txt index 67e686d1eb..bfda9b3ba8 100644 --- a/settingtypes.txt +++ b/settingtypes.txt @@ -97,6 +97,9 @@ animated_chests (Animated chests) bool true # Whether to preview the player in inventory in 3D (requires Minetest 5.4) 3d_player_preview (3D Player preview) bool true +# The maximum number of boss bars to simultaniously display on the screen +max_bossbars (Maximum Boss bars) int 4 + [Experimental] # Whether ice is translucent. If disabled, ice is fully opaque. # diff --git a/tools/remove_end.py b/tools/remove_end.py new file mode 100644 index 0000000000..3b73e55753 --- /dev/null +++ b/tools/remove_end.py @@ -0,0 +1,46 @@ +world_name = "world" +path_to_map_sqlite = "../../../worlds/" + world_name + "/map.sqlite" + +import sqlite3, sys + +try: + conn = sqlite3.connect(path_to_map_sqlite) +except Error as e: + print(e) + sys.exit() + +def unsignedToSigned(i, max_positive): + if i < max_positive: + return i + else: + return i - 2*max_positive + +cursor = conn.cursor() +cursor.execute("SELECT pos FROM blocks") +poses = cursor.fetchall() +end_blocks = [] +for i0 in (poses): + i = int(i0[0]) + blockpos = i + x = unsignedToSigned(i % 4096, 2048) + i = int((i - x) / 4096) + y = unsignedToSigned(i % 4096, 2048) + i = int((i - y) / 4096) + z = unsignedToSigned(i % 4096, 2048) + + node_pos_y = y * 16 + if node_pos_y > -28811 and node_pos_y + 15 < -67: + end_blocks.append(blockpos) + +if len(end_blocks) < 1: + print ("End blocks not found") + sys.exit() + +counter = 0 +for blockpos in end_blocks: + print("Deleting ", blockpos) + cursor.execute("DELETE FROM blocks WHERE pos=" + str(blockpos)) + counter += 1 +conn.commit() + +print(counter, " block(s) deleted")