diff --git a/0_gameconfig.lua b/0_gameconfig.lua index 8b83b3f..17eaf7c 100644 --- a/0_gameconfig.lua +++ b/0_gameconfig.lua @@ -48,6 +48,7 @@ mobs_mc.items = { shulker_shell = "mobs_mc:shulker_shell", magma_cream = "mobs_mc:magma_cream", spider_eye = "mobs_mc:spider_eye", + snowball = "mobs_mc:snowball", totem = "mobs_mc:totem", rotten_flesh = "mobs_mc:rotten_flesh", nether_star = "mobs_mc:nether_star", @@ -61,6 +62,8 @@ mobs_mc.items = { shears = "mobs:shears", -- Minetest Game + top_snow = "default:snow", + snow_block = "default:snowblock", mushroom_red = "flowers:mushroom_red", bucket = "bucket:bucket_empty", grass_block = "default:dirt_with_grass", @@ -68,6 +71,7 @@ mobs_mc.items = { stick = "default:stick", flint = "default:flint", iron_ingot = "default:steel_ingot", + iron_block = "default:steelblock", fire = "fire:basic_flame", gunpowder = "tnt:gunpowder", flint_and_steel = "fire:flint_and_steel", @@ -135,6 +139,7 @@ mobs_mc.items = { wool_black = "wool:black", -- Light blue intentionally missing + -- Special items music_discs = {}, -- No music discs by default; used by creeper. Override this if your subgame has music discs. } @@ -244,9 +249,13 @@ mobs_mc.spawn = { water = { mobs_mc.items.water_source, "mcl_core:water_source", "default:water_source" }, } +mobs_mc.misc = { + shears_wear = 276, -- Wear to add per shears usage (238 uses) +} + -- Item name overrides from mobs_mc_gameconfig (if present) if minetest.get_modpath("mobs_mc_gameconfig") and mobs_mc.override then - local tables = {"items", "follow", "replace", "spawn"} + local tables = {"items", "follow", "replace", "spawn", "misc"} for t=1, #tables do local tbl = tables[t] if mobs_mc.override[tbl] then diff --git a/1_items_default.lua b/1_items_default.lua index 5719503..2ed8e09 100644 --- a/1_items_default.lua +++ b/1_items_default.lua @@ -495,3 +495,23 @@ if c("nether_star") then }) end +if c("snowball") and minetest.get_modpath("default") then + minetest.register_craft({ + output = "mobs_mc:snowball 2", + recipe = { + {"default:snow"}, + }, + }) + minetest.register_craft({ + output = "default:snow 2", + recipe = { + {"mobs_mc:snowball", "mobs_mc:snowball"}, + {"mobs_mc:snowball", "mobs_mc:snowball"}, + }, + }) + -- Change the appearance of default snow to avoid confusion with snowball + minetest.override_item("default:snow", { + inventory_image = "", + wield_image = "", + }) +end diff --git a/2_throwing.lua b/2_throwing.lua index 823b099..8a8db2a 100644 --- a/2_throwing.lua +++ b/2_throwing.lua @@ -173,11 +173,14 @@ end -- egg throwing item -- egg entity if c("egg") then + local egg_GRAVITY = 9 + local egg_VELOCITY = 19 + mobs:register_arrow("mobs_mc:egg_entity", { visual = "sprite", visual_size = {x=.5, y=.5}, textures = {"mobs_chicken_egg.png"}, - velocity = 6, + velocity = egg_velocity, hit_player = function(self, player) player:punch(minetest.get_player_by_name(self.playername) or self.object, 1.0, { @@ -233,9 +236,6 @@ if c("egg") then end }) - local egg_GRAVITY = 9 - local egg_VELOCITY = 19 - -- shoot egg local mobs_shoot_egg = function (item, player, pointed_thing) @@ -275,7 +275,9 @@ if c("egg") then local ent2 = obj:get_luaentity() ent2.playername = player:get_player_name() - item:take_item() + if not minetest.settings:get_bool("creative_mode") then + item:take_item() + end return item end @@ -287,6 +289,90 @@ if c("egg") then }) end +if c("snowball") then + local snowball_GRAVITY = 9 + local snowball_VELOCITY = 19 + + mobs:register_arrow("mobs_mc:snowball_entity", { + visual = "sprite", + visual_size = {x=.5, y=.5}, + textures = {"mcl_throwing_snowball.png"}, + velocity = snowball_VELOCITY, + + hit_player = function(self, player) + -- FIXME: No knockback + player:punch(self.object, 1.0, { + full_punch_interval = 1.0, + damage_groups = {}, + }, nil) + end, + + hit_mob = function(self, mob) + -- Hurt blazes, but not damage to anything else + local dmg = {} + minetest.log("error", dump(mob)) + if mob:get_luaentity().name == "mobs_mc:blaze" then + dmg = {fleshy = 3} + end + -- FIXME: No knockback + mob:punch(self.object, 1.0, { + full_punch_interval = 1.0, + damage_groups = dmg, + }, nil) + end, + + }) + + -- shoot snowball + local mobs_shoot_snowball = function (item, player, pointed_thing) + + local playerpos = player:getpos() + + local obj = minetest.add_entity({ + x = playerpos.x, + y = playerpos.y +1.5, + z = playerpos.z + }, "mobs_mc:snowball_entity") + + local ent = obj:get_luaentity() + local dir = player:get_look_dir() + + ent.velocity = snowball_VELOCITY -- needed for api internal timing + ent.switch = 1 -- needed so that egg doesn't despawn straight away + + obj:setvelocity({ + x = dir.x * snowball_VELOCITY, + y = dir.y * snowball_VELOCITY, + z = dir.z * snowball_VELOCITY + }) + + obj:setacceleration({ + x = dir.x * -3, + y = -snowball_GRAVITY, + z = dir.z * -3 + }) + + -- pass player name to egg for chick ownership + local ent2 = obj:get_luaentity() + ent2.playername = player:get_player_name() + + if not minetest.settings:get_bool("creative_mode") then + item:take_item() + end + + return item + end + + + -- Snowball + minetest.register_craftitem("mobs_mc:snowball", { + description = "Snowball", + _doc_items_longdesc = "Snowballs can be thrown for fun. A snowball deals 3 damage to blazes, but is harmless to anything else.", + inventory_image = "mcl_throwing_snowball.png", + on_use = mobs_shoot_snowball, + }) +end + --end maikerumine code if minetest.settings:get_bool("log_mods") then diff --git a/cow+mooshroom.lua b/cow+mooshroom.lua index e396447..da62e5e 100644 --- a/cow+mooshroom.lua +++ b/cow+mooshroom.lua @@ -88,7 +88,7 @@ mooshroom_def.on_rightclick = function(self, clicker) cow:setyaw(oldyaw) if not minetest.setting_getbool("creative_mode") then - item:add_wear(300) + item:add_wear(mobs_mc.misc.shears_wear) clicker:get_inventory():set_stack("main", clicker:get_wield_index(), item) end -- Use bucket to milk diff --git a/gameconfig.md b/gameconfig.md index 3090b69..dabfb93 100644 --- a/gameconfig.md +++ b/gameconfig.md @@ -2,7 +2,7 @@ This mod has been designed to make subgame integration rather easy. Ideally, it should be possible to include this mod verbatim in your subgame, with modifications only done by an external mod. -To integrate this mod in a subgame, you have to do 2 things: Adding the mod, and adding another mod which tells `mobs_mc` which items to use. The idea is that `mobs_mc` should work with any items. Specifically, theres are the steps you need to follow +To integrate this mod in a subgame, you have to do 2 things: Adding the mod, and adding another mod which tells `mobs_mc` which items to use. The idea is that `mobs_mc` should work with any items. Specifically, these are the steps you need to follow: * Add the `mobs_mc` mod and its dependencies * Add a mod with name “`mobs_mc_gameconfig`” @@ -12,6 +12,10 @@ To integrate this mod in a subgame, you have to do 2 things: Adding the mod, and * Create the table `mobs_mc.override` * In `mobs_mc.override`, create subtables (`items`, `spawn`, etc.) like in `0_gameconfig.lua`, defining the na * Read `0_gameconfig.lua` to see which items you can override (and more explanations) +* In `on_construct` of a pumpkin or jack'o lantern node, call: + * `mobs_mc.tools.check_iron_golem_summon(pos)` + * `mobs_mc.tools.check_snow_golem_summon(pos)` + * For more information, see `snowman.lua` and `iron_golem.lua` Some things to note: diff --git a/init.lua b/init.lua index fcabbd1..d9291b4 100644 --- a/init.lua +++ b/init.lua @@ -9,6 +9,9 @@ if not minetest.get_modpath("mobs_mc_gameconfig") then mobs_mc = {} end +-- For utility functions +mobs_mc.tools = {} + -- This function checks if the item ID has been overwritten and returns true if it is unchanged if minetest.get_modpath("mobs_mc_gameconfig") and mobs_mc.override and mobs_mc.override.items then mobs_mc.is_item_variable_overridden = function(id) @@ -87,6 +90,7 @@ dofile(path .. "/villager_illusioner.lua") -- Mesh and animation by toby109tt / dofile(path .. "/ghast.lua") -- maikerumine dofile(path .. "/guardian.lua") -- maikerumine Mesh and animation by toby109tt / https://github.com/22i dofile(path .. "/guardian_elder.lua") -- maikerumine Mesh and animation by toby109tt / https://github.com/22i +dofile(path .. "/snowman.lua") dofile(path .. "/iron_golem.lua") -- maikerumine Mesh and animation by toby109tt / https://github.com/22i dofile(path .. "/shulker.lua") -- maikerumine Mesh and animation by toby109tt / https://github.com/22i dofile(path .. "/silverfish.lua") -- maikerumine Mesh and animation by toby109tt / https://github.com/22i diff --git a/iron_golem.lua b/iron_golem.lua index 42150c6..72fff85 100644 --- a/iron_golem.lua +++ b/iron_golem.lua @@ -70,6 +70,114 @@ mobs:register_mob("mobs_mc:iron_golem", { mobs:register_egg("mobs_mc:iron_golem", "Iron Golem", "mobs_mc_spawn_icon_iron_golem.png", 0) +--[[ This is to be called when a pumpkin or jack'o lantern has been placed. Recommended: In the on_construct function of the node. +This summons an iron golen if placing the pumpkin created an iron golem summon pattern: + +.P. +III +.I. + +P = Pumpkin or jack'o lantern +I = Iron block +. = Air +]] + +mobs_mc.tools.check_iron_golem_summon = function(pos) + local checks = { + -- These are the possible placement patterns, with offset from the pumpkin block. + -- These tables include the positions of the iron blocks (1-4) and air blocks (5-8) + -- 4th element is used to determine spawn position. + -- If a 9th element is present, that one is used for the spawn position instead. + -- Standing (x axis) + { + {x=-1, y=-1, z=0}, {x=1, y=-1, z=0}, {x=0, y=-1, z=0}, {x=0, y=-2, z=0}, -- iron blocks + {x=-1, y=0, z=0}, {x=1, y=0, z=0}, {x=-1, y=-2, z=0}, {x=1, y=-2, z=0}, -- air + }, + -- Upside down standing (x axis) + { + {x=-1, y=1, z=0}, {x=1, y=1, z=0}, {x=0, y=1, z=0}, {x=0, y=2, z=0}, + {x=-1, y=0, z=0}, {x=1, y=0, z=0}, {x=-1, y=2, z=0}, {x=1, y=2, z=0}, + {x=0, y=0, z=0}, -- Different offset for upside down pattern + }, + + -- Standing (z axis) + { + {x=0, y=-1, z=-1}, {x=0, y=-1, z=1}, {x=0, y=-1, z=0}, {x=0, y=-2, z=0}, + {x=0, y=0, z=-1}, {x=0, y=0, z=1}, {x=0, y=-2, z=-1}, {x=0, y=-2, z=1}, + }, + -- Upside down standing (z axis) + { + {x=0, y=1, z=-1}, {x=0, y=1, z=1}, {x=0, y=1, z=0}, {x=0, y=2, z=0}, + {x=0, y=0, z=-1}, {x=0, y=0, z=1}, {x=0, y=2, z=-1}, {x=0, y=2, z=1}, + {x=0, y=0, z=0}, + }, + + -- Lying + { + {x=-1, y=0, z=-1}, {x=0, y=0, z=-1}, {x=1, y=0, z=-1}, {x=0, y=0, z=-2}, + {x=-1, y=0, z=0}, {x=1, y=0, z=0}, {x=-1, y=0, z=-2}, {x=1, y=0, z=-2}, + }, + { + {x=-1, y=0, z=1}, {x=0, y=0, z=1}, {x=1, y=0, z=1}, {x=0, y=0, z=2}, + {x=-1, y=0, z=0}, {x=1, y=0, z=0}, {x=-1, y=0, z=2}, {x=1, y=0, z=2}, + }, + { + {x=-1, y=0, z=-1}, {x=-1, y=0, z=0}, {x=-1, y=0, z=1}, {x=-2, y=0, z=0}, + {x=0, y=0, z=-1}, {x=0, y=0, z=1}, {x=-2, y=0, z=-1}, {x=-2, y=0, z=1}, + }, + { + {x=1, y=0, z=-1}, {x=1, y=0, z=0}, {x=1, y=0, z=1}, {x=2, y=0, z=0}, + {x=0, y=0, z=-1}, {x=0, y=0, z=1}, {x=2, y=0, z=-1}, {x=2, y=0, z=1}, + }, + + + } + + for c=1, #checks do + -- Check all possible patterns + local ok = true + -- Check iron block nodes + for i=1, 4 do + local cpos = vector.add(pos, checks[c][i]) + local node = minetest.get_node(cpos) + if node.name ~= mobs_mc.items.iron_block then + ok = false + break + end + end + -- Check air nodes + for a=5, 8 do + local cpos = vector.add(pos, checks[c][a]) + local node = minetest.get_node(cpos) + if node.name ~= "air" then + ok = false + break + end + end + -- Pattern found! + if ok then + -- Remove the nodes + minetest.remove_node(pos) + core.check_for_falling(pos) + for i=1, 4 do + local cpos = vector.add(pos, checks[c][i]) + minetest.remove_node(cpos) + core.check_for_falling(cpos) + end + -- Summon iron golem + local place + if checks[c][9] then + place = vector.add(pos, checks[c][9]) + else + place = vector.add(pos, checks[c][4]) + end + place.y = place.y - 0.5 + minetest.add_entity(place, "mobs_mc:iron_golem") + break + end + end +end + if minetest.settings:get_bool("log_mods") then minetest.log("action", "MC Iron Golem loaded") end diff --git a/sheep.lua b/sheep.lua index ba26a51..6201de0 100644 --- a/sheep.lua +++ b/sheep.lua @@ -176,7 +176,7 @@ mobs:register_mob("mobs_mc:sheep", { textures = self.base_texture, }) if not minetest.settings:get_bool("creative_mode") then - item:add_wear(300) + item:add_wear(mobs_mc.misc.shears_wear) clicker:get_inventory():set_stack("main", clicker:get_wield_index(), item) end self.drops = { diff --git a/snowman.lua b/snowman.lua index 6c3eca4..94c5929 100644 --- a/snowman.lua +++ b/snowman.lua @@ -3,109 +3,135 @@ --made for MC like Survival game --License for code WTFPL and otherwise stated in readmes +local snow_trail_frequency = 0.5 -- Time in seconds for checking to add a new snow trail ---dofile(minetest.get_modpath("mobs").."/api.lua") - ---################### ---################### SNOWMAN ---################### ---[[ -mobs:register_mob("mobs_mc:26snowman", { - type = "animal", +mobs:register_mob("mobs_mc:snowman", { + type = "npc", passive = true, - runaway = true, - stepheight = 1.2, - hp_min = 30, - hp_max = 60, - armor = 150, - collisionbox = {-0.35, -0.01, -0.35, 0.35, 2, 0.35}, + hp_min = 4, + hp_max = 4, + pathfinding = 1, + view_range = 10, + fall_damage = 0, + water_damage = 4, + lava_damage = 20, + attacks_monsters = true, + collisionbox = {-0.35, -0.01, -0.35, 0.35, 1.89, 0.35}, visual = "mesh", - mesh = "snowman.b3d", + mesh = "mobs_mc_snowman.b3d", textures = { - {"snowman.png"}, + {"mobs_mc_snowman.png^mobs_mc_snowman_pumpkin.png"}, }, + gotten_texture = { "mobs_mc_snowman.png" }, + drops = {{ name = mobs_mc.items.snowball, chance = 1, min = 0, max = 15 }}, visual_size = {x=3, y=3}, walk_velocity = 0.6, run_velocity = 2, jump = true, - animation = { - speed_normal = 25, speed_run = 50, - stand_start = 40, stand_end = 80, - walk_start = 0, walk_end = 40, - run_start = 0, run_end = 40, - }, -}) - -mobs:register_egg("mobs_mc:26snowman", "Snowman", "snowman_inv.png", 0) -]] - -mobs:register_mob("mobs_mc:enderman", { - type = "monster", - hp_max = 79, - collisionbox = {-0.4, -2.4, -0.4, 0.4, 1.8, 0.4}, - - visual = "mesh", - mesh = "mobs_mc_snowman.b3d", - textures = { - {"mobs_mc_snowman.png"} - }, - visual_size = {x=1.2, y=2.5}, makes_footstep_sound = true, - sounds = { - -- TODO - distance = 16, - }, - walk_velocity = 3.2, - run_velocity = 5.4, - damage = 3, - armor = 200, - drops = { - {name = "default:obsidian", - chance = 40, - min = 0, - max = 2,}, - {name = "default:diamond", - chance = 61, - min = 1, - max = 1,}, - {name = "farorb:farorb", - chance = 3, - min = 0, - max = 1,}, - {name = "mobs_mc:enderman_head", - chance = 50, - min = 0, - max = 1,}, - }, + attack_type = "shoot", + arrow = "mobs_mc:snowball_entity", + shoot_interval = 1, + shoot_offset = 1, animation = { - speed_normal = 45, - speed_run = 15, - stand_start = 0, - stand_end = 39, - walk_start = 41, - walk_end = 72, - run_start = 74, - run_end = 105, - punch_start = 74, - punch_end = 105, + speed_normal = 25, + speed_run = 50, + stand_start = 20, + stand_end = 40, + walk_start = 0, + walk_end = 20, + run_start = 0, + run_end = 20, + die_start = 40, + die_end = 50, + die_loop = false, }, - water_damage = 1, - lava_damage = 5, - light_damage = 0, - view_range = 16, - attack_type = "dogfight", - replace_rate = 1, - replace_what = {"default:torch","default:sand","default:desert_sand","default:cobble","default:dirt","default:dirt_with_glass","default:dirt_with_dry_grass","default:wood","default:stone","default:sandstone"}, - replace_with = "air", - replace_offset = -1, + blood_amount = 0, + do_custom = function(self, dtime) + -- Leave a trail of top snow behind. + -- This is done in do_custom instead of just using replace_what because with replace_what, + -- the top snop may end up floating in the air. + if not self._snowtimer then + self._snowtimer = 0 + return + end + self._snowtimer = self._snowtimer + dtime + if self.health > 0 and self._snowtimer > snow_trail_frequency then + self._snowtimer = 0 + local pos = self.object:getpos() + local below = {x=pos.x, y=pos.y-1, z=pos.z} + local def = minetest.registered_nodes[minetest.get_node(pos).name] + -- Node at snow golem's position must be replacable + if def and def.buildable_to then + -- Node below must be walkable + -- and a full cube (this prevents oddities like top snow on top snow, lower slabs, etc.) + local belowdef = minetest.registered_nodes[minetest.get_node(below).name] + if belowdef and belowdef.walkable and (belowdef.node_box == nil or belowdef.node_box.type == "regular") then + -- Place top snow + minetest.set_node(pos, {name = mobs_mc.items.top_snow}) + end + end + end + end, + -- Remove pumpkin if using shears + on_rightclick = function(self, clicker) + local item = clicker:get_wielded_item() + if self.gotten ~= true and item:get_name() == mobs_mc.items.shears then + -- Remove pumpkin + self.gotten = true + self.object:set_properties({ + textures = {"mobs_mc_snowman.png"}, + }) + local pos = self.object:getpos() + minetest.sound_play("shears", {pos = pos}) + + -- Wear out + if not minetest.settings:get_bool("creative_mode") then + item:add_wear(mobs_mc.misc.shears_wear) + clicker:get_inventory():set_stack("main", clicker:get_wield_index(), item) + end + end + end, }) +-- This is to be called when a pumpkin or jack'o lantern has been placed. Recommended: In the on_construct function +-- of the node. +-- This summons a snow golen when pos is next to a row of two snow blocks. +mobs_mc.tools.check_snow_golem_summon = function(pos) + local checks = { + -- These are the possible placement patterns + -- { snow block pos. 1, snow block pos. 2, snow golem spawn position } + { {x=pos.x, y=pos.y-1, z=pos.z}, {x=pos.x, y=pos.y-2, z=pos.z}, {x=pos.x, y=pos.y-2.5, z=pos.z} }, + { {x=pos.x, y=pos.y+1, z=pos.z}, {x=pos.x, y=pos.y+2, z=pos.z}, {x=pos.x, y=pos.y-0.5, z=pos.z} }, + { {x=pos.x-1, y=pos.y, z=pos.z}, {x=pos.x-2, y=pos.y, z=pos.z}, {x=pos.x-2, y=pos.y-0.5, z=pos.z} }, + { {x=pos.x+1, y=pos.y, z=pos.z}, {x=pos.x+2, y=pos.y, z=pos.z}, {x=pos.x+2, y=pos.y-0.5, z=pos.z} }, + { {x=pos.x, y=pos.y, z=pos.z-1}, {x=pos.x, y=pos.y, z=pos.z-2}, {x=pos.x, y=pos.y-0.5, z=pos.z-2} }, + { {x=pos.x, y=pos.y, z=pos.z+1}, {x=pos.x, y=pos.y, z=pos.z+2}, {x=pos.x, y=pos.y-0.5, z=pos.z+2} }, + } + + for c=1, #checks do + local b1 = checks[c][1] + local b2 = checks[c][2] + local place = checks[c][3] + local b1n = minetest.get_node(b1) + local b2n = minetest.get_node(b2) + if b1n.name == mobs_mc.items.snow_block and b2n.name == mobs_mc.items.snow_block then + -- Remove the pumpkin and both snow blocks and summon the snow golem + minetest.remove_node(pos) + minetest.remove_node(b1) + minetest.remove_node(b2) + core.check_for_falling(pos) + core.check_for_falling(b1) + core.check_for_falling(b2) + minetest.add_entity(place, "mobs_mc:snowman") + break + end + end +end --- spawn eggs mobs:register_egg("mobs_mc:snowman", "Snow Golem", "mobs_mc_spawn_icon_snowman.png", 0) - if minetest.settings:get_bool("log_mods") then - minetest.log("action", "MC Enderman loaded") + minetest.log("action", "MC Snow Golem loaded") end diff --git a/textures/mcl_throwing_snowball.png b/textures/mcl_throwing_snowball.png new file mode 100644 index 0000000..5fcc76f Binary files /dev/null and b/textures/mcl_throwing_snowball.png differ diff --git a/textures/mobs_mc_snowman.png b/textures/mobs_mc_snowman.png index 1bd733e..47b2820 100644 Binary files a/textures/mobs_mc_snowman.png and b/textures/mobs_mc_snowman.png differ diff --git a/textures/mobs_mc_snowman_pumpkin.png b/textures/mobs_mc_snowman_pumpkin.png new file mode 100644 index 0000000..e9db35a Binary files /dev/null and b/textures/mobs_mc_snowman_pumpkin.png differ