diff --git a/README.md b/README.md new file mode 100644 index 0000000..2b44c72 --- /dev/null +++ b/README.md @@ -0,0 +1,17 @@ +Minetest Defense [minetest_defense] +=================================== + +To use this game with Minetest, insert this repository as + /games/minetest_defense +in the Minetest Engine. + +The Minetest Engine can be found in: + https://github.com/minetest/minetest/ + +Compatibility +-------------- +Minetest Defense is based on minetest_game 0.4.11, and should be compatible with Minetest 0.4.11. + +License +------- +Most of the default minetest_game files are untouched. License of these files is in minetest_game-license.md. \ No newline at end of file diff --git a/game.conf b/game.conf index 8b819bb..bdda077 100644 --- a/game.conf +++ b/game.conf @@ -1 +1 @@ -name = Minetest +name = Minetest Defense diff --git a/minetest.conf b/minetest.conf index cda1589..0568377 100644 --- a/minetest.conf +++ b/minetest.conf @@ -4,3 +4,6 @@ mgv6_spflags = biomeblend, jungles movement_liquid_sink = 25 movement_liquid_fluidity = 0.8 movement_liquid_fluidity_smooth = 2 + +creative_mode = false +time_speed = 144 \ No newline at end of file diff --git a/README.txt b/minetest_game-license.md similarity index 60% rename from README.txt rename to minetest_game-license.md index 9456f81..b3641d7 100644 --- a/README.txt +++ b/minetest_game-license.md @@ -1,25 +1,7 @@ -The main game for the Minetest game engine [minetest_game] -========================================================== +License of minetest_game files +============================== -To use this game with Minetest, insert this repository as - /games/minetest_game -in the Minetest Engine. - -The Minetest Engine can be found in: - https://github.com/minetest/minetest/ - -Compatibility --------------- -The minetest_game github master HEAD is generally compatible with the github -master HEAD of minetest. - -Additionally, when the minetest engine is tagged to be a certain version (eg. -0.4.10), minetest_game is tagged with the version too. - -When stable releases are made, minetest_game is packaged and made available in - http://minetest.net/download.php -and in case the repository has grown too much, it may be reset. In that sense, -this is not a "real" git repository. (Package maintainers please note!) +minetest_game files include everything except mods/defense*/* License of source code ---------------------- diff --git a/mods/defense/depends.txt b/mods/defense/depends.txt new file mode 100644 index 0000000..db9e5bd --- /dev/null +++ b/mods/defense/depends.txt @@ -0,0 +1 @@ +defense_mobs \ No newline at end of file diff --git a/mods/defense/director.lua b/mods/defense/director.lua new file mode 100644 index 0000000..e69de29 diff --git a/mods/defense/init.lua b/mods/defense/init.lua new file mode 100644 index 0000000..7ffeede --- /dev/null +++ b/mods/defense/init.lua @@ -0,0 +1,7 @@ +defense = {} + +local function dofile2(file) + dofile(minetest.get_modpath("defense") .. "/" .. file) +end + +dofile2("director.lua") \ No newline at end of file diff --git a/mods/defense_mobs/depends.txt b/mods/defense_mobs/depends.txt new file mode 100644 index 0000000..e69de29 diff --git a/mods/defense_mobs/init.lua b/mods/defense_mobs/init.lua new file mode 100644 index 0000000..29443dc --- /dev/null +++ b/mods/defense_mobs/init.lua @@ -0,0 +1,9 @@ +defense_mobs = {} +defense_mobs.gravity = -9.81 + +local function dofile2(file) + dofile(minetest.get_modpath("defense_mobs") .. "/" .. file) +end + +dofile2("mob.lua") +dofile2("unggoy.lua") \ No newline at end of file diff --git a/mods/defense_mobs/mob.lua b/mods/defense_mobs/mob.lua new file mode 100644 index 0000000..872a0f6 --- /dev/null +++ b/mods/defense_mobs/mob.lua @@ -0,0 +1,270 @@ +defense_mobs.move_method = { + air = function(self, dtime, destination) + local delta = vector.subtract(destination, self.object:getpos()) + local dist = vector.length(delta) + local speed = self.move_speed * math.max(0, math.min(1, 2 * dist - 0.5)) + if speed > 0.01 then + local t = math.pow(0.1, dtime) + self.object:setvelocity(vector.add( + vector.multiply(self.object:getvelocity(), t), + vector.multiply(vector.normalize(delta), speed * (1-t)) + )) + + local yaw = self.object:getyaw() + local yaw_delta = math.atan2(delta.z, delta.x) - yaw + if yaw_delta < -math.pi then + yaw_delta = yaw_delta + math.pi * 2 + elseif yaw_delta > math.pi then + yaw_delta = yaw_delta - math.pi * 2 + end + self.object:setyaw(yaw + yaw_delta * (1-t)) + + self:set_animation("move", {"move_attack"}) + else + self.object:setvelocity({x=0, y=0, z=0}) + self:set_animation("idle", {"attack", "move_attack"}) + end + end, + + ground = function(self, dtime, destination) + local delta = vector.subtract(destination, self.object:getpos()) + local dy = delta.y + delta.y = 0 + local dist = vector.length(delta) + local speed = self.move_speed * math.max(0, math.min(1, 3 * dist - 0.5)) + if speed > 0.01 then + local t + if self:is_standing() then + t = math.pow(0.001, dtime) + else + t = 0.9 + end + local dir = vector.normalize(delta) + local v = self.object:getvelocity() + local v2 = vector.add( + vector.multiply(v, t), + vector.multiply(dir, speed * (1-t)) + ) + v2.y = v.y + self.object:setvelocity(v2) + + local yaw = self.object:getyaw() + local yaw_delta = math.atan2(dir.z, dir.x) - yaw + if yaw_delta < -math.pi then + yaw_delta = yaw_delta + math.pi * 2 + elseif yaw_delta > math.pi then + yaw_delta = yaw_delta - math.pi * 2 + end + self.object:setyaw(yaw + yaw_delta * (1-t)) + + -- Check for obstacle to jump + local jump = false + if dist > 1 then + local p = self.object:getpos() + p.y = p.y + self.collisionbox[2] + 0.5 + local sx = self.collisionbox[4] - self.collisionbox[1] + local sz = self.collisionbox[6] - self.collisionbox[3] + local r = math.sqrt(sx*sx + sz*sz) + local node = minetest.get_node_or_nil(vector.add(p, vector.multiply(dir, r))) + if not node or minetest.registered_nodes[node.name].walkable then + jump = true + end + end + + if jump then + self:jump(dir) + elseif self:is_standing() then + self:set_animation("move", {"move_attack"}) + end + else + local v = self.object:getvelocity() + v.x = 0 + v.z = 0 + self.object:setvelocity(v) + self:set_animation("idle", {"attack", "move_attack"}) + end + end +} + +function defense_mobs.register_mob(name, def) + local prototype = { + -- minetest properties & defaults + physical = true, + collide_with_objects = true, + makes_footstep_sound = true, + visual = "mesh", + automatic_face_movement_dir = false, + stepheight = 0.6, + -- custom properties + movement = "ground", -- "ground"/"air" + move_speed = 1, + jump_height = 1, + armor = 100, + attack_range = 1, + attack_damage = 1, + attack_interval = 1, + + destination = nil, -- position + current_animation = nil, + current_animation_end = 0, + last_attack_time = 0, + timer = 0, + } + for k,v in pairs(def) do + prototype[k] = v + end + + -- + -- Callbacks + -- + + -- extendable + function prototype:on_activate(staticdata) + self.object:set_armor_groups({fleshy=self.armor}) + if self.movement == "ground" then + self.object:setacceleration({x=0, y=defense_mobs.gravity, z=0}) + end + self.timer = math.random() * 16 + + if def.on_activate then + def.on_activate(self, staticdata) + end + end + + -- extendable + function prototype:on_step(dtime) + if self.destination then + self:move(dtime, self.destination) + else + self:move(dtime, self.object:getpos()) + end + + if self.movement ~= "air" and not self:is_standing() then + self:set_animation("fall", {"jump", "attack", "move_attack"}) + end + + if def.on_step then + def.on_step(self, dtime) + end + + self.timer = self.timer + dtime + end + + -- + -- Overridable methods + -- + + -- overridable + prototype.attack = def.attack or function(self, obj) + local delta = vector.subtract(obj:getpos(), self.object:getpos()) + obj:punch(self.object, self.timer - self.last_attack_time, { + full_punch_interval=self.attack_interval, + damage_groups = {fleshy=self.attack_damage} + }, delta) + self.object:setyaw(math.atan2(delta.z, delta.x)) + end + + -- overridable + prototype.move = def.move or defense_mobs.move_method[prototype.movement] + + -- + -- Methods + -- + + function prototype:hunt(radius) + local p = self.object:getpos() + local nearest_player = nil + local nearest_dist = radius + 1 + for _,obj in ipairs(minetest.env:get_objects_inside_radius(p, radius)) do + if obj:is_player() then + if nearest_player then + local d = vector.distance(nearest_player:getpos(), p) + if d < nearest_dist then + nearest_player = obj + nearest_dist = d + end + else + nearest_player = obj + nearest_dist = vector.distance(obj:getpos(), p) + end + end + end + + if nearest_player then + local nearest_pos = nearest_player:getpos() + local dir = vector.direction(nearest_pos, self.object:getpos()) + self.destination = vector.add(nearest_pos, vector.multiply(dir, self.attack_range/2)) + if nearest_dist < self.attack_range then + self:do_attack(nearest_player) + end + end + end + + function prototype:do_attack(obj) + if self.last_attack_time + self.attack_interval < self.timer then + self:attack(obj) + self.last_attack_time = self.timer + if self.current_animation == "move" then + self:set_animation("move_attack") + else + self:set_animation("attack") + end + end + end + + function prototype:jump(direction) + if self:is_standing() then + direction = vector.normalize(direction) + local v = self.object:getvelocity() + v.y = math.sqrt(2 * -defense_mobs.gravity * (self.jump_height + 0.2)) + v.x = direction.x * v.y + v.z = direction.z * v.y + self.object:setvelocity(v) + self:set_animation("jump") + end + end + + function prototype:is_standing() + if self.movement == "air" then + return false + end + + local p = self.object:getpos() + p.y = p.y + self.collisionbox[2] - 0.5 + local corners = { + vector.add(p, {x=self.collisionbox[1], y=0, z=self.collisionbox[3]}), + vector.add(p, {x=self.collisionbox[1], y=0, z=self.collisionbox[6]}), + vector.add(p, {x=self.collisionbox[4], y=0, z=self.collisionbox[3]}), + vector.add(p, {x=self.collisionbox[4], y=0, z=self.collisionbox[6]}), + } + for _,c in ipairs(corners) do + local node = minetest.get_node_or_nil(c) + if not node or minetest.registered_nodes[node.name].walkable and self.object:getvelocity().y == 0 then + return true + end + end + return false + end + + function prototype:set_animation(name, inhibit) + if self.current_animation == name then + return + end + if inhibit then + for _,p in ipairs(inhibit) do + if self.current_animation == p and self.timer < self.current_animation_end then + return + end + end + end + + local anim_prop = self.animation[name] + if anim_prop then + self.current_animation = name + self.current_animation_end = self.timer + (anim_prop.b - anim_prop.a - 1) / anim_prop.rate + self.object:set_animation({x=anim_prop.a, y=anim_prop.b}, anim_prop.rate, 0) + end + end + + minetest.register_entity(name, prototype) +end \ No newline at end of file diff --git a/mods/defense_mobs/models/defense_mobs_unggoy.b3d b/mods/defense_mobs/models/defense_mobs_unggoy.b3d new file mode 100644 index 0000000..c1c8d72 Binary files /dev/null and b/mods/defense_mobs/models/defense_mobs_unggoy.b3d differ diff --git a/mods/defense_mobs/models/defense_mobs_unggoy.png b/mods/defense_mobs/models/defense_mobs_unggoy.png new file mode 100644 index 0000000..a0257a5 Binary files /dev/null and b/mods/defense_mobs/models/defense_mobs_unggoy.png differ diff --git a/mods/defense_mobs/models/unggoy.blend b/mods/defense_mobs/models/unggoy.blend new file mode 100644 index 0000000..7e56977 Binary files /dev/null and b/mods/defense_mobs/models/unggoy.blend differ diff --git a/mods/defense_mobs/models/unggoy.blend1 b/mods/defense_mobs/models/unggoy.blend1 new file mode 100644 index 0000000..eddc6c0 Binary files /dev/null and b/mods/defense_mobs/models/unggoy.blend1 differ diff --git a/mods/defense_mobs/models/unggoy.xcf b/mods/defense_mobs/models/unggoy.xcf new file mode 100644 index 0000000..b109944 Binary files /dev/null and b/mods/defense_mobs/models/unggoy.xcf differ diff --git a/mods/defense_mobs/unggoy.lua b/mods/defense_mobs/unggoy.lua new file mode 100644 index 0000000..1a905c7 --- /dev/null +++ b/mods/defense_mobs/unggoy.lua @@ -0,0 +1,31 @@ +defense_mobs.register_mob("defense_mobs:unggoy", { + hp_max = 1, + weight = 6, + collisionbox = {-0.4,-0.01,-0.4, 0.4,1.5,0.4}, + visual_size = {x=2.5, y=2.5}, + mesh = "defense_mobs_unggoy.b3d", + textures = {"defense_mobs_unggoy.png"}, + makes_footstep_sound = true, + + animation = { + idle = {a=0, b=39, rate=30}, + jump = {a=40, b=49, rate=15}, + fall = {a=50, b=64, rate=20}, + attack = {a=65, b=72, rate=15}, + move = {a=75, b=99, rate=40}, + move_attack = {a=100, b=113, rate=20}, + }, + + move_speed = 5, + jump_height = 2, + attack_damage = 1, + attack_interval = 0.5, + + on_activate = function(self, staticdata) + self:hunt(70) + end, + + on_step = function(self, dtime) + self:hunt(20) + end, +}) \ No newline at end of file