commit 1da3049808e9bc9abc17ae7e475957ccaaa308fc Author: AntumDeluge Date: Sat May 13 03:35:54 2017 -0700 Add Rui's creeper mod code: Forked from Git commit 036666e. Original repo & forum thread appear to have been deleted. diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..5c93f45 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,13 @@ + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + Version 2, December 2004 + + Copyright (C) 2004 Sam Hocevar + + Everyone is permitted to copy and distribute verbatim or modified + copies of this license document, and changing it is allowed as long + as the name is changed. + + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. You just DO WHAT THE FUCK YOU WANT TO. diff --git a/README.md b/README.md new file mode 100644 index 0000000..67a9684 --- /dev/null +++ b/README.md @@ -0,0 +1,8 @@ +# creeper +Adds some explosive nuisance. + +## Forum Topic +- https://forum.minetest.net/viewtopic.php?t=11891 + +## License +- **Code:** WTFPL diff --git a/depends.txt b/depends.txt new file mode 100644 index 0000000..4ad96d5 --- /dev/null +++ b/depends.txt @@ -0,0 +1 @@ +default diff --git a/description.txt b/description.txt new file mode 100644 index 0000000..d95903d --- /dev/null +++ b/description.txt @@ -0,0 +1 @@ +Adds some explosive nuisance. diff --git a/init.lua b/init.lua new file mode 100644 index 0000000..594dcec --- /dev/null +++ b/init.lua @@ -0,0 +1,343 @@ +creeper = {} + +--[[ +-- DISABLED!!! +do return end +--]] + +dofile(minetest.get_modpath("creeper").."/tnt_function.lua") +dofile(minetest.get_modpath("creeper").."/spawn.lua") + +local function jump(self,pos,direction) + local velocity = self.object:getvelocity() + if minetest.registered_nodes[minetest.get_node(pos).name].climbable then + self.object:setvelocity({x=velocity.x,y=4,z=velocity.z}) + return + end + + local spos = {x=pos.x+direction.x,y=pos.y,z=pos.z+direction.z} + local node = minetest.get_node_or_nil(spos) + spos.y = spos.y+1 + local node2 = minetest.get_node_or_nil(spos) + local def,def2 = {} + if node and node.name then + def = minetest.registered_items[node.name] + end + if node2 and node2.name then + def2 = minetest.registered_items[node2.name] + end + if def and def.walkable + and def2 and not def2.walkable + and def.drawtype ~= "fencelike" then + self.object:setvelocity({ + x=velocity.x*2.2, + y=self.jump_height, + z=velocity.z*2.2 + }) + end +end + +local function random_turn(self) + if self.turn_timer > math.random(2,5) then + local select_turn = math.random(1,3) + if select_turn == 1 then + self.turn = "left" + elseif select_turn == 2 then + self.turn = "right" + elseif select_turn == 3 then + self.turn = "straight" + end + self.turn_timer = 0 + self.turn_speed = 0.05*math.random() + end +end + +local def = { + hp_max = 20, + physical = true, + collisionbox = {-0.25,-0.7,-0.25, 0.25,0.8,0.25}, + visual = "mesh", + mesh = "character.b3d", + textures = {"creeper.png"}, + makes_footstep_sound = false, + + -- Original + animation = { + stand_START = 0, + stand_END = 79, + walk_START = 168, + walk_END = 187 + }, + walk_speed = 1.5, + jump_height = 5, + animation_speed = 30, + knockback_level = 2 +} + +def.on_activate = function(self,staticdata) + self.yaw = 0 + self.anim = 1 + self.timer = 0 + self.visualx = 1 + self.jump_timer = 0 + self.turn_timer = 0 + self.turn_speed = 0 + self.powered = false + self.knockback = false + self.state = math.random(1,2) + self.old_y = self.object:getpos().y + + local data = minetest.deserialize(staticdata) + if data and type(data) == "table" then + if data.powered == true then + self.powered = true + self.object:set_properties({textures = {"creeper_powered.png"}}) + end + else + if math.random(0,20) == 20 then + self.powered = true + self.object:set_properties({textures = {"creeper_powered.png"}}) + end + end +end + +def.on_step = function(self, dtime) + if self.knockback then + return + end + + local ANIM_STAND = 1 + local ANIM_WALK = 2 + + local pos = self.object:getpos() + local yaw = self.object:getyaw() + local inside = minetest.get_objects_inside_radius(pos,10) + local walk_speed = self.walk_speed + local animation = self.animation + local anim_speed = self.animation_speed + local velocity = self.object:getvelocity() + + self.timer = self.timer+0.01 + self.turn_timer = self.turn_timer+0.01 + self.jump_timer = self.jump_timer+0.01 + + if not self.chase + and self.timer > math.random(2,5) then + if math.random() > 0.8 then + self.state = "stand" + else + self.state = "walk" + end + self.timer = 0 + end + + if self.turn == "right" then + self.yaw = self.yaw+self.turn_speed + self.object:setyaw(self.yaw) + elseif self.turn == "left" then + self.yaw = self.yaw-self.turn_speed + self.object:setyaw(self.yaw) + end + + if self.chase and self.visualx < 2 then + if self.hiss == false then + minetest.sound_play("creeper_hiss",{pos=pos,gain=1.5,max_hear_distance=2*64}) + end + self.visualx = self.visualx+0.05 + self.object:set_properties({ + visual_size = {x=self.visualx,y=1} + }) + self.hiss = true + elseif self.visualx > 1 then + self.visualx = self.visualx-0.05 + self.object:set_properties({ + visual_size = {x=self.visualx,y=1} + }) + self.hiss = false + end + + self.chase = false + + for _,object in ipairs(inside) do + if object:is_player() then + self.state = "chase" + end + end + + if self.state == "stand" then + if self.anim ~= ANIM_STAND then + self.object:set_animation({x=animation.stand_START,y=animation.stand_END},anim_speed,0) + self.anim = ANIM_STAND + end + + random_turn(self) + + if velocity.x ~= 0 + or velocity.z ~= 0 then + self.object:setvelocity({x=0,y=velocity.y,z=0}) + end + end + + if self.state == "walk" then + if self.anim ~= ANIM_WALK then + self.object:set_animation({x=animation.walk_START,y=animation.walk_END},anim_speed,0) + self.anim = ANIM_WALK + end + + self.direction = {x=math.sin(yaw)*-1,y=-10,z=math.cos(yaw)} + if self.direction then + self.object:setvelocity({x=self.direction.x*walk_speed,y=velocity.y,z=self.direction.z*walk_speed}) + end + + random_turn(self) + + local velocity = self.object:getvelocity() + + if self.turn_timer > 1 then + local direction = self.direction + local npos = {x=pos.x+direction.x,y=pos.y+0.2,z=pos.z+direction.z} + if velocity.x == 0 or velocity.z == 0 + or minetest.registered_nodes[minetest.get_node(npos).name].walkable then + local select_turn = math.random(1,2) + if select_turn == 1 then + self.turn = "left" + elseif select_turn == 2 then + self.turn = "right" + end + self.turn_timer = 0 + self.turn_speed = 0.05*math.random() + end + end + + -- Jump + if self.jump_timer > 0.2 then + jump(self,pos,self.direction) + end + end + + if self.state == "chase" then + if self.anim ~= ANIM_WALK then + self.object:set_animation({x=animation.walk_START,y=animation.walk_END},anim_speed,0) + self.anim = ANIM_WALK + end + + self.turn = "straight" + + local inside_2 = minetest.get_objects_inside_radius(pos,2) + + -- Boom + if #inside_2 ~= 0 then + for _,object in ipairs(inside_2) do + if object:is_player() and object:get_hp() ~= 0 then + self.chase = true + if self.visualx >= 2 then + self.object:remove() + creeper.boom(pos,self.powered) + minetest.sound_play("creeper_explode",{pos=pos,gain=1.5,max_hear_distance=2*64}) + end + end + end + end + + if #inside ~= 0 then + for _,object in ipairs(inside) do + if object:is_player() and object:get_hp() ~= 0 then + if #inside_2 ~= 0 then + for _,object in ipairs(inside_2) do + -- Stop move + if object:is_player() then + if self.anim ~= ANIM_STAND then + self.object:set_animation({x=animation.stand_START,y=animation.stand_END},anim_speed,0) + self.anim = ANIM_STAND + end + self.object:setvelocity({x=0,y=velocity.y,z=0}) + return + end + end + end + + local ppos = object:getpos() + self.vec = {x=ppos.x-pos.x,y=ppos.y-pos.y,z=ppos.z-pos.z} + self.yaw = math.atan(self.vec.z/self.vec.x)+math.pi^2 + if ppos.x > pos.x then + self.yaw = self.yaw+math.pi + end + self.yaw = self.yaw-2 + self.object:setyaw(self.yaw) + self.direction = {x=math.sin(self.yaw)*-1,y=0,z=math.cos(self.yaw)} + + local direction = self.direction + self.object:setvelocity({x=direction.x*2.5,y=velocity.y,z=direction.z*2.5}) + + -- Jump + if self.jump_timer > 0.2 then + jump(self,pos,direction) + end + end + end + else + self.state = "stand" + end + end + + -- Swim + local node = minetest.get_node(pos) + if minetest.get_item_group(node.name,"water") ~= 0 then + self.object:setacceleration({x=0,y=1,z=0}) + local velocity = self.object:getvelocity() + if self.object:getvelocity().y > 5 then + self.object:setvelocity({x=0,y=velocity.y-velocity.y/2,z=0}) + else + self.object:setvelocity({x=0,y=velocity.y+1,z=0}) + end + else + self.object:setacceleration({x=0,y=-10,z=0}) + end +end + +def.on_punch = function(self,puncher,time_from_last_punch,tool_capabilities,dir) + if self.knockback == false then + local knockback_level = self.knockback_level + self.object:setvelocity({x=dir.x*knockback_level,y=3,z=dir.z*knockback_level}) + self.knockback = true + minetest.after(0.6,function() + self.knockback = false + end) + end + if self.object:get_hp() < 1 then + local pos = self.object:getpos() + local x = 1/math.random(1,5)*dir.x + local z = 1/math.random(1,5)*dir.z + local p = {x=pos.x+x,y=pos.y,z=pos.z+z} + local node = minetest.get_node_or_nil(p) + if node == nil or not node.name or node.name ~= "air" then + p = pos + end + local obj = minetest.add_item(p, {name="tnt:gunpowder",count=math.random(0,2)}) + end +end + +def.get_staticdata = function(self) + return minetest.serialize({ + powered = self.powered + }) +end + +minetest.register_entity("creeper:creeper",def) + +minetest.register_craftitem("creeper:spawnegg",{ + description = "Creeper Spawn Egg", + inventory_image = "creeper_spawnegg.png", + stack_max = 64, + on_place = function(itemstack,placer,pointed_thing) + if pointed_thing.type == "node" then + local pos = pointed_thing.above + pos.y = pos.y+1 + minetest.add_entity(pos,"creeper:creeper") + if not minetest.setting_getbool("creative_mode") then + itemstack:take_item() + end + return itemstack + end + end +}) diff --git a/screenshot.png b/screenshot.png new file mode 100644 index 0000000..1029b7c Binary files /dev/null and b/screenshot.png differ diff --git a/sounds/creeper_explode.ogg b/sounds/creeper_explode.ogg new file mode 100644 index 0000000..a414ea0 Binary files /dev/null and b/sounds/creeper_explode.ogg differ diff --git a/sounds/creeper_hiss.ogg b/sounds/creeper_hiss.ogg new file mode 100644 index 0000000..199f206 Binary files /dev/null and b/sounds/creeper_hiss.ogg differ diff --git a/spawn.lua b/spawn.lua new file mode 100644 index 0000000..1e66db9 --- /dev/null +++ b/spawn.lua @@ -0,0 +1,32 @@ +minetest.register_abm({ + nodenames = {"default:dirt_with_grass","default:stone"}, + neighbors = {"air"}, + interval = 30, + chance = 9000, + action = function(pos, node, _, active_object_count_wider) + if active_object_count_wider > 5 then + return + end + pos.y = pos.y+1 + if not minetest.get_node_light(pos) then + return + end + if minetest.get_node_light(pos) > 5 then + return + end + if minetest.get_node_light(pos) < -1 then + return + end + if pos.y > 31000 then + return + end + if minetest.get_node(pos).name ~= "air" then + return + end + pos.y = pos.y+1 + if minetest.get_node(pos).name ~= "air" then + return + end + minetest.add_entity(pos,"creeper:creeper") + end +}) diff --git a/textures/creeper.png b/textures/creeper.png new file mode 100644 index 0000000..063084a Binary files /dev/null and b/textures/creeper.png differ diff --git a/textures/creeper_powered.png b/textures/creeper_powered.png new file mode 100644 index 0000000..b73d2be Binary files /dev/null and b/textures/creeper_powered.png differ diff --git a/textures/creeper_smoke.png b/textures/creeper_smoke.png new file mode 100644 index 0000000..0d3d834 Binary files /dev/null and b/textures/creeper_smoke.png differ diff --git a/textures/creeper_spawnegg.png b/textures/creeper_spawnegg.png new file mode 100644 index 0000000..087425c Binary files /dev/null and b/textures/creeper_spawnegg.png differ diff --git a/tnt_function.lua b/tnt_function.lua new file mode 100644 index 0000000..fa933d0 --- /dev/null +++ b/tnt_function.lua @@ -0,0 +1,195 @@ +-- From TNT +local cid_data = {} +local radius = tonumber(minetest.setting_get("tnt_radius") or 3) +local large_radius = 5 +local loss_prob = { + ["default:cobble"] = 3, + ["default:dirt"] = 4, +} +minetest.after(0, function() + for name, def in pairs(minetest.registered_nodes) do + cid_data[minetest.get_content_id(name)] = { + name = name, + drops = def.drops, + flammable = def.groups.flammable, + } + end +end) + +local function rand_pos(center, pos, radius) + pos.x = center.x + math.random(-radius, radius) + pos.z = center.z + math.random(-radius, radius) +end + +local function eject_drops(drops, pos, radius) + local drop_pos = vector.new(pos) + for _, item in pairs(drops) do + local count = item:get_count() + local max = item:get_stack_max() + if count > max then + item:set_count(max) + end + while count > 0 do + if count < max then + item:set_count(count) + end + rand_pos(pos, drop_pos, radius) + local obj = minetest.add_item(drop_pos, item) + if obj then + obj:get_luaentity().collect = true + obj:setacceleration({x=0, y=-10, z=0}) + obj:setvelocity({x=math.random(-3, 3), y=10, + z=math.random(-3, 3)}) + end + count = count - max + end + end +end + +local function add_drop(drops, item) + item = ItemStack(item) + local name = item:get_name() + if loss_prob[name] ~= nil and math.random(1, loss_prob[name]) == 1 then + return + end + + local drop = drops[name] + if drop == nil then + drops[name] = item + else + drop:set_count(drop:get_count() + item:get_count()) + end +end + +local function destroy(drops, pos, cid) + if minetest.is_protected(pos, "") then + return + end + local def = cid_data[cid] + if def and def.on_blast then + def.on_blast(vector.new(pos), 1) + return + end + minetest.remove_node(pos) + if def then + local node_drops = minetest.get_node_drops(def.name, "") + for _, item in ipairs(node_drops) do + add_drop(drops, item) + end + end +end + + +local function calc_velocity(pos1, pos2, old_vel, power) + local vel = vector.direction(pos1, pos2) + vel = vector.normalize(vel) + vel = vector.multiply(vel, power) + + -- Divide by distance + local dist = vector.distance(pos1, pos2) + dist = math.max(dist, 1) + vel = vector.divide(vel, dist) + + -- Add old velocity + vel = vector.add(vel, old_vel) + return vel +end + +local function entity_physics(pos, radius) + -- Make the damage radius larger than the destruction radius + radius = radius * 2 + local objs = minetest.get_objects_inside_radius(pos, radius) + for _, obj in pairs(objs) do + local obj_pos = obj:getpos() + local obj_vel = obj:getvelocity() + local dist = math.max(1, vector.distance(pos, obj_pos)) + + if obj_vel ~= nil then + obj:setvelocity(calc_velocity(pos, obj_pos, + obj_vel, radius * 10)) + end + + local damage = (5 / dist) * radius + obj:set_hp(obj:get_hp() - damage) + end +end + +local function add_effects(pos, radius) + minetest.add_particlespawner({ + amount = 128, + time = 1, + minpos = vector.subtract(pos, radius / 2), + maxpos = vector.add(pos, radius / 2), + minvel = {x=-20, y=-20, z=-20}, + maxvel = {x=20, y=20, z=20}, + minacc = vector.new(), + maxacc = vector.new(), + minexptime = 1, + maxexptime = 3, + minsize = 8, + maxsize = 16, + texture = "creeper_smoke.png", + }) +end + + +local function explode(pos, radius) + local pos = vector.round(pos) + local vm = VoxelManip() + local pr = PseudoRandom(os.time()) + local p1 = vector.subtract(pos, radius) + local p2 = vector.add(pos, radius) + local minp, maxp = vm:read_from_map(p1, p2) + local a = VoxelArea:new({MinEdge = minp, MaxEdge = maxp}) + local data = vm:get_data() + + local drops = {} + local p = {} + + local c_air = minetest.get_content_id("air") + local c_tnt = minetest.get_content_id("tnt:tnt") + local c_tnt_burning = minetest.get_content_id("tnt:tnt_burning") + local c_gunpowder = minetest.get_content_id("tnt:gunpowder") + local c_gunpowder_burning = minetest.get_content_id("tnt:gunpowder_burning") + local c_boom = minetest.get_content_id("tnt:boom") + + for z = -radius, radius do + for y = -radius, radius do + local vi = a:index(pos.x + (-radius), pos.y + y, pos.z + z) + for x = -radius, radius do + if (x * x) + (y * y) + (z * z) <= + (radius * radius) + pr:next(-radius, radius) then + local cid = data[vi] + p.x = pos.x + x + p.y = pos.y + y + p.z = pos.z + z + if cid == c_tnt or cid == c_gunpowder then + burn(p) + elseif cid ~= c_tnt_burning and + cid ~= c_gunpowder_burning and + cid ~= c_air and + cid ~= c_boom then + destroy(drops, p, cid) + end + end + vi = vi + 1 + end + end + end + + return drops +end + +function creeper.boom(pos,large) + local radius = radius + if large then + radius = large_radius + end + minetest.sound_play("creeper_explode", {pos=pos, gain=1.5, max_hear_distance=2*64}) + minetest.set_node(pos, {name="tnt:boom"}) + minetest.get_node_timer(pos):start(0.5) + local drops = explode(pos, radius) + entity_physics(pos, radius) + eject_drops(drops, pos, radius) + add_effects(pos, radius) +end