diff --git a/focuses.lua b/focuses.lua index e4faee6..ad03a90 100644 --- a/focuses.lua +++ b/focuses.lua @@ -1,5 +1,12 @@ -- Wand Focuses +-- Constants +-- TODO: make settings +magicalities.magic_spray_count = 16 +magicalities.elemental_focus_velocity = 16 +magicalities.elemental_focus_consumption = 5 + +-- Teleportation minetest.register_craftitem("magicalities:focus_teleport", { description = "Wand Focus of Teleportation", groups = {wand_focus = 1}, @@ -40,6 +47,7 @@ minetest.register_craftitem("magicalities:focus_teleport", { end }) +-- Node swapper minetest.register_craftitem("magicalities:focus_swap", { description = "Wand Focus of Swapping", groups = {wand_focus = 1}, @@ -74,7 +82,7 @@ minetest.register_craftitem("magicalities:focus_swap", { return itemstack end - local drops = minetest.get_node_drops(pos) + local drops = minetest.get_node_drops(node.name) if ndef.can_dig ~= nil and not ndef.can_dig(pos, user) then return itemstack @@ -114,12 +122,15 @@ minetest.register_craftitem("magicalities:focus_swap", { end }) +--------------- +-- Tunneling -- +--------------- local tunneler_memory = {} local tunneler_depth = 8 local function reset_tunnel(tid) - local infos = tunneler_memory['t' .. tid] + local infos = tunneler_memory[tid] if not infos then return end local manip = minetest.get_voxel_manip() @@ -138,15 +149,13 @@ local function reset_tunnel(tid) manip:write_to_map() tunneler_memory['t' .. tid] = nil - - t = false end local function create_tunnel(pos, dir, owner) -- Ensure no double tunnels for id,data in pairs(tunneler_memory) do if data.owner == owner then - return + return false end end @@ -207,7 +216,7 @@ local function create_tunnel(pos, dir, owner) end end - if abort then return end + if abort then return false end -- Set nodes in map manip:set_data(data) @@ -226,7 +235,8 @@ local function create_tunnel(pos, dir, owner) owner = owner, } - minetest.after(10, reset_tunnel, cnum) + minetest.after(10, reset_tunnel, 't' .. cnum) + return true end minetest.register_node("magicalities:tunnel_node", { @@ -246,7 +256,9 @@ minetest.register_craftitem("magicalities:focus_tunnel", { inventory_image = "magicalities_focus_tunnel.png", stack_max = 1, _wand_requirements = { - ["air"] = 1 + ["dark"] = 10, + ["light"] = 10, + ["earth"] = 10, }, _wand_use = function (itemstack, user, pointed_thing) if not pointed_thing.above or pointed_thing.type ~= "node" then return itemstack end @@ -256,6 +268,12 @@ minetest.register_craftitem("magicalities:focus_tunnel", { dir = minetest.wallmounted_to_dir(wm) minetest.after(0.1, create_tunnel, pointed_thing.above, dir, user:get_player_name()) + itemstack = magicalities.wands.wand_take_contents(itemstack, { + ["dark"] = 10, + ["light"] = 10, + ["earth"] = 10, + }) + magicalities.wands.update_wand_desc(itemstack) return itemstack end @@ -266,3 +284,231 @@ minetest.register_on_shutdown(function () reset_tunnel(id) end end) + +----------------------- +-- Elemental Attacks -- +----------------------- + +local special_fn = {} + +-- Particles +local randparticles = PcgRandom(os.clock()) +local function shoot_particles (user, velocity, color) + if not color then + color = "" + else + color = "^[multiply:"..color + end + + -- Calculate velocity + local dir = user:get_look_dir() + local vel = {x=0,y=0,z=0} + vel.x = dir.x * velocity + vel.y = dir.y * velocity + vel.z = dir.z * velocity + + -- Calculate position + local pos = user:get_pos() + pos.x = pos.x + (dir.x * 2) + pos.y = pos.y + (dir.y * 2) + 1.5 + pos.z = pos.z + (dir.z * 2) + + for i = 1, magicalities.magic_spray_count do + -- Deviation + local relvel = {x=0,y=0,z=0} + relvel.x = vel.x + (randparticles:next((-i/2.5) * 1000, (i/2.5) * 1000) / 1000) + relvel.y = vel.y + (randparticles:next((-i/2.5) * 1000, (i/2.5) * 1000) / 1000) + relvel.z = vel.z + (randparticles:next((-i/2.5) * 1000, (i/2.5) * 1000) / 1000) + minetest.add_particle({ + pos = pos, + velocity = relvel, + acceleration = relvel, + expirationtime = 1, + size = 4, + collisiondetection = true, + collision_removal = true, + texture = "magicalities_spark.png"..color, + -- animation = {Tile Animation definition}, + glow = 2 + }) + end +end + +local function shoot_spray(user, dmg, vel, color, hit_fn) + shoot_particles(user, vel, color) + + minetest.after(0.05, function() + local pos = user:get_pos() + local dir = user:get_look_dir() + + local x = math.random(-1,1)*0.1 + local y = math.random(-1,1)*0.1 + local z = math.random(-1,1)*0.1 + local scatternum = math.random(2, magicalities.magic_spray_count / 2) + + for i = 1, scatternum do + local relvel = {x=0,y=0,z=0} + relvel.x = dir.x * vel + (randparticles:next((-i/2.5) * 1000, (i/2.5) * 1000) / 1000) + relvel.y = dir.y * vel + (randparticles:next((-i/2.5) * 1000, (i/2.5) * 1000) / 1000) + relvel.z = dir.z * vel + (randparticles:next((-i/2.5) * 1000, (i/2.5) * 1000) / 1000) + + local dmglow = dmg - math.floor(dmg / scatternum) + local reldmg = math.random(dmglow, dmg) + + local e=minetest.add_entity({x=pos.x+x,y=pos.y+1.5+y,z=pos.z+z}, "magicalities:magic_spray") + e:set_velocity(relvel) + e:set_yaw(user:get_look_yaw()+math.pi) + e:get_luaentity():set_dmg(reldmg) + e:get_luaentity():set_user(user) + if hit_fn then + e:get_luaentity():set_hit_function(hit_fn) + end + end + end) +end + +-- Attack +local on_hit_object = function(self, target, hp, user) + target:punch(user, 1, {full_punch_interval = 1, damage_groups = {fleshy = hp, magic = hp * 2}}, nil) + return self +end + +local magic_remove = function(self) + if self.object:get_attach() then self.object:set_detach() end + if self.target then self.target:punch(self.object, 1,{full_punch_interval=1,damage_groups={fleshy=4}}, nil) end + self.object:set_hp(0) + self.object:punch(self.object, 1,{full_punch_interval=1.0,damage_groups={fleshy=4}}, nil) + return self +end + +local magic_spray = { + initial_properties = { + hp_max = 1, + physical = false, + collide_with_objects = false, + collisionbox = {-0.3, -0.3, -0.3, 0.3, 0.3, 0.3}, + visual = "sprite", + visual_size = {x = 0.4, y = 0.4}, + textures = {"[combine:16x16"}, + pointable = false, + }, + struck = false, + timer = 0, + hit_fn = nil, + on_step = function(self, dtime) + self.timer = self.timer + 1 + if self.timer > 80 or self.struck then + magic_remove(self) + end + local pos=self.object:get_pos() + local no=minetest.registered_nodes[minetest.get_node(pos).name] + if no.walkable and not self.struck then + if self.hit_fn and special_fn[self.hit_fn] and special_fn[self.hit_fn].on_hit_node then + special_fn[self.hit_fn].on_hit_node(self, pos, minetest.get_node(pos), self.user) + end + + self.struck = true + return self + end + for i, ob in pairs(minetest.get_objects_inside_radius(pos, 1)) do + if (ob and not self.struck) and ((ob:is_player() and ob:get_player_name() ~= self.user:get_player_name()) or (ob:get_luaentity() and ob:get_luaentity().physical and ob:get_luaentity().name~="__builtin:item" )) then + self.object:set_velocity({x=0, y=0, z=0}) + on_hit_object(self, ob, self.dmg / 2, self.user) + if self.hit_fn and special_fn[self.hit_fn] and special_fn[self.hit_fn].on_hit_object then + special_fn[self.hit_fn].on_hit_object(self, ob, self.dmg / 2, self.user) + end + + self.struck = true + return self + end + end + return self + end, + on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir) + if not self.target then return self end + if not self.hp then self.hp = self.object:get_hp() end + local hp = self.object:get_hp() + local hurt = self.hp-self.object:get_hp() + self.hp = self.object:get_hp() + self.target:set_hp(self.target:get_hp() - hurt) + self.target:punch(self.object, hurt, {full_punch_interval = 1.0, damage_groups = {fleshy=4}}, "default:sword_wood", nil) + if hurt > 100 or hp <= hurt then + self.target:set_detach() + self.target:set_velocity({x=0, y=4, z=0}) + self.on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir) end + magic_remove(self) + end + return self + end +} + +function magic_spray:set_dmg(dmg) + self.dmg = dmg +end + +function magic_spray:set_user(user) + self.user = user +end + +function magic_spray:set_hit_function(hit_fn) + self.hit_fn = hit_fn +end + +function magicalities.register_elemental_focus (element, description, damage, hit_fn) + local el = magicalities.elements[element] + minetest.register_craftitem("magicalities:focus_atk_"..element, { + description = "Wand Focus of "..el.description.."\n"..description, + groups = {wand_focus = 1}, + inventory_image = "magicalities_focus_atk_"..element..".png", + stack_max = 1, + _wand_requirements = { + [element] = magicalities.elemental_focus_consumption + }, + _wand_use = function (itemstack, user, pointed_thing) + if not user or user:get_player_name() == "" then return itemstack end + + itemstack = magicalities.wands.wand_take_contents(itemstack, {[element] = magicalities.elemental_focus_consumption}) + magicalities.wands.update_wand_desc(itemstack) + shoot_spray(user, damage, magicalities.elemental_focus_velocity, el.color, hit_fn) + + return itemstack + end + }) +end + +function magicalities.register_focus_atk_special(name, fns) + special_fn[name] = fns +end + +-- Register everything + +minetest.register_entity("magicalities:magic_spray", magic_spray) + +magicalities.register_elemental_focus("air", "Deals some damage to enemies", 2) +magicalities.register_elemental_focus("earth", "Deals some damage to enemies", 4) +magicalities.register_elemental_focus("water", "Spawns water sources", 3, "setwater") +magicalities.register_elemental_focus("fire", "Lights things on fire", 8, "setfire") + +magicalities.register_focus_atk_special("setfire", { + on_hit_node = function (self, pos, node, user) + local toppos = vector.add(pos, {x=0,y=1,z=0}) + local topnode = minetest.get_node_or_nil(toppos) + if not topnode or topnode.name ~= "air" then return end + if minetest.is_protected(toppos, user:get_player_name()) then return end + minetest.set_node(toppos, {name="fire:basic_flame"}) + end +}) + +local function set_water(self, _, __, user) + local pos = self.object:get_pos() + local toppos = vector.add(pos, {x=0,y=1,z=0}) + local topnode = minetest.get_node_or_nil(toppos) + if not topnode or topnode.name ~= "air" then return end + if minetest.is_protected(toppos, user:get_player_name()) then return end + minetest.set_node(toppos, {name="default:water_source"}) +end + +magicalities.register_focus_atk_special("setwater", { + on_hit_object = set_water, + on_hit_node = set_water, +}) diff --git a/textures/magicalities_crystal_shard.png b/textures/magicalities_crystal_shard.png index bbba3dc..056ddc4 100644 Binary files a/textures/magicalities_crystal_shard.png and b/textures/magicalities_crystal_shard.png differ diff --git a/textures/magicalities_focus_atk_air.png b/textures/magicalities_focus_atk_air.png new file mode 100644 index 0000000..947342b Binary files /dev/null and b/textures/magicalities_focus_atk_air.png differ diff --git a/textures/magicalities_focus_atk_earth.png b/textures/magicalities_focus_atk_earth.png new file mode 100644 index 0000000..5cea6a3 Binary files /dev/null and b/textures/magicalities_focus_atk_earth.png differ diff --git a/textures/magicalities_focus_atk_fire.png b/textures/magicalities_focus_atk_fire.png new file mode 100644 index 0000000..ff16167 Binary files /dev/null and b/textures/magicalities_focus_atk_fire.png differ diff --git a/textures/magicalities_focus_atk_water.png b/textures/magicalities_focus_atk_water.png new file mode 100644 index 0000000..31f2936 Binary files /dev/null and b/textures/magicalities_focus_atk_water.png differ diff --git a/wands.lua b/wands.lua index f134a36..0e359bc 100644 --- a/wands.lua +++ b/wands.lua @@ -13,8 +13,6 @@ local wandcaps = { damage_groups = {fleshy = 2}, } -local randparticles = PcgRandom(os.clock()) - local function align(len) local str = "" for i = 1, len do @@ -48,8 +46,10 @@ local function focuses_formspec(available, focusname) local x = 0 local fsp = "" for focus in pairs(available) do - fsp = fsp .. "item_image_button["..x..",2.8;1,1;"..focus..";"..focus..";]" - x = x + 1 + if x < 5 then + fsp = fsp .. "item_image_button["..x..",2.8;1,1;"..focus..";"..focus..";]" + x = x + 1 + end end local current = "" @@ -281,39 +281,6 @@ local function use_wand(itemstack, user, pointed_thing) end end - -- Calculate velocity - local dir = user:get_look_dir() - local vel = {x=0,y=0,z=0} - vel.x = dir.x * 16 - vel.y = dir.y * 16 - vel.z = dir.z * 16 - - -- Calculate position - local pos = user:get_pos() - pos.x = pos.x + (dir.x * 2) - pos.y = pos.y + (dir.y * 2) + 1.5 - pos.z = pos.z + (dir.z * 2) - - for i = 1, 16 do - -- Deviation - local relvel = {x=0,y=0,z=0} - relvel.x = vel.x + (randparticles:next((-i/2.5) * 1000, (i/2.5) * 1000) / 1000) - relvel.y = vel.y + (randparticles:next((-i/2.5) * 1000, (i/2.5) * 1000) / 1000) - relvel.z = vel.z + (randparticles:next((-i/2.5) * 1000, (i/2.5) * 1000) / 1000) - minetest.add_particle({ - pos = pos, - velocity = relvel, - acceleration = relvel, - expirationtime = 1, - size = 4, - collisiondetection = true, - collision_removal = true, - texture = "magicalities_spark.png", - -- animation = {Tile Animation definition}, - glow = 2 - }) - end - magicalities.wands.update_wand_desc(itemstack) return itemstack end