summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTenPlus1 <kinsellaja@yahoo.com>2016-12-29 12:28:25 +0000
committerTenPlus1 <kinsellaja@yahoo.com>2016-12-29 12:28:25 +0000
commitef3217d77f6cb5fb5259b673eea99e5af6da8fee (patch)
tree13dba8c0c355ee0229f66c83c973f62f6ca8e001
parent671fab54eb9a63362b017ac30a9a60e77c65cb03 (diff)
Added rideable mob functions (thanks blert2112)
-rw-r--r--api.txt148
-rw-r--r--crafts.lua15
-rw-r--r--init.lua3
-rw-r--r--mount.lua343
-rw-r--r--readme.MD1
-rw-r--r--textures/mobs_saddle.pngbin0 -> 166 bytes
6 files changed, 509 insertions, 1 deletions
diff --git a/api.txt b/api.txt
index a9a1e51..de137f2 100644
--- a/api.txt
+++ b/api.txt
@@ -1,5 +1,5 @@
-MOB API (27th December 2016)
+MOB API (29th December 2016)
The mob api is a function that can be called on by other mods to add new animals or monsters into minetest.
@@ -260,3 +260,149 @@ Useful Internal Variables
'self.gotten' true when sheep have been sheared or cows have been milked, a toggle switch which can be used for many functions
'self.child' true when mob is currently a child (when two mobs have bred and current mob is the outcome)
'self.hornytimer' background timer that controls breeding functions and mob childhood timings
+
+
+Mobs can now be ridden by players and the following shows the functions and usage:
+
+
+mobs:attach(self, player)
+
+This function attaches a player to the mob so it can be ridden.
+
+ 'self' mob information
+ 'player' player information
+
+
+mobs:detach(player, offset)
+
+This function will detach the player currently riding a mob to an offset position.
+
+ 'player' player information
+ 'offset' position table containing offset values
+
+
+mobs:drive(self, move_animation, stand_animation, can_fly)
+
+This function allows an attached player to move the mob around and animate it at same time.
+
+ 'self' mob information
+ 'move_animation' string containing movement animation e.g. "walk"
+ 'stand_animation' string containing standing animation e.g. "stand"
+ 'can_fly' if true then jump and sneak controls will allow mob to fly up and down
+
+
+Certain variables need to be set before using the above functions:
+
+ 'self.v2' toggle switch
+ 'self.max_speed_forward' max speed mob can move forward
+ 'self.max_speed_reverse' max speed mob can move backwards
+ 'self.accel' acceleration speed
+ 'self.terrain_type' integer containing terrain mob can walk on (1 = water, 2 or 3 = land)
+ 'self.driver_attach_at' position offset for attaching player to mob
+ 'self.driver_eye_offset' position offset for attached player view
+
+
+Here is an example mob to show how the above functions work:
+
+
+-- rideable horse
+mobs:register_mob("mob_horse:horse", {
+ type = "animal",
+ visual = "mesh",
+ visual_size = {x = 1.20, y = 1.20},
+ mesh = "mobs_horse.x",
+ collisionbox = {-0.4, -0.01, -0.4, 0.4, 1.25, 0.4},
+ animation = {
+ speed_normal = 15, speed_run = 30,
+ stand_start = 25, stand_end = 75,
+ walk_start = 75, walk_end = 100,
+ run_start = 75, run_end = 100,
+ },
+ textures = {
+ {"mobs_horse.png"},
+ {"mobs_horsepeg.png"},
+ {"mobs_horseara.png"}
+ },
+ fear_height = 3,
+ runaway = true,
+ fly = false,
+ walk_chance = 60,
+ view_range = 5,
+ follow = {"farming:wheat"},
+ passive = true,
+ hp_min = 12,
+ hp_max = 16,
+ armor = 200,
+ lava_damage = 5,
+ fall_damage = 5,
+ water_damage = 1,
+ makes_footstep_sound = true,
+ drops = {
+ {name = "mobs:meat_raw", chance = 1, min = 2, max = 3}
+ },
+
+ -- custom function uses self.v2 toggle to set ride variables
+ do_custom = function(self, dtime)
+
+ if not self.v2 then
+ self.v2 = 0
+ self.max_speed_forward = 6
+ self.max_speed_reverse = 2
+ self.accel = 6
+ self.terrain_type = 3
+ self.driver_attach_at = {x = 0, y = 20, z = -2}
+ self.driver_eye_offset = {x = 0, y = 3, z = 0}
+ end
+
+ -- when riding mob call drive function to control
+ if self.driver then
+ mobs.drive(self, "walk", "stand", false)
+ return false -- skip rest of mob functions
+ end
+
+ return true
+ end,
+
+ on_rightclick = function(self, clicker)
+
+ -- check for actual player
+ if not clicker or not clicker:is_player() then
+ return
+ end
+
+ -- used to feed, tame and heal mob
+ if mobs:feed_tame(self, clicker, 10, true, true) then
+ return
+ end
+
+ -- check if mob has been tamed and player is owner
+ if self.tamed and self.owner == clicker:get_player_name() then
+
+ local inv = clicker:get_inventory()
+
+ -- detach player when riding mob (add saddle to inventory)
+ if self.driver and clicker == self.driver then
+
+ mobs.detach(clicker, {x = 1, y = 0, z = 1})
+
+ if inv:room_for_item("main", "mobs:saddle") then
+ inv:add_item("main", "mobs:saddle")
+ else
+ minetest.add_item(clicker.getpos(), "mobs:saddle")
+ end
+
+ -- attach player to mob if not riding (take saddle from inventory)
+ elseif not self.driver then
+
+ if clicker:get_wielded_item():get_name() == "mobs:saddle" then
+
+ self.object:set_properties({stepheight = 1.1})
+ mobs.attach(self, clicker)
+ inv:remove_item("main", "mobs:saddle")
+ end
+ end
+ end
+
+ mobs:capture_mob(self, clicker, 0, 0, 80, false, nil)
+ end
+})
diff --git a/crafts.lua b/crafts.lua
index 4d32326..b0ac728 100644
--- a/crafts.lua
+++ b/crafts.lua
@@ -98,3 +98,18 @@ minetest.register_craft({
{"default:stone", "default:stone", "default:stone"},
}
})
+
+-- saddle
+minetest.register_craftitem("mobs:saddle", {
+ description = "Saddle",
+ inventory_image = "mobs_saddle.png"
+})
+
+minetest.register_craft({
+ output = "mobs:saddle",
+ recipe = {
+ {"mobs:leather", "mobs:leather", "mobs:leather"},
+ {"mobs:leather", "default:steel_ingot", "mobs:leather"},
+ {"mobs:leather", "default:steel_ingot", "mobs:leather"},
+ }
+})
diff --git a/init.lua b/init.lua
index 52dadee..8a625b6 100644
--- a/init.lua
+++ b/init.lua
@@ -4,6 +4,9 @@ local path = minetest.get_modpath("mobs")
-- Mob API
dofile(path .. "/api.lua")
+-- Rideable Mobs
+dofile(path .. "/mount.lua")
+
-- Mob Items
dofile(path .. "/crafts.lua")
diff --git a/mount.lua b/mount.lua
new file mode 100644
index 0000000..9bbfc67
--- /dev/null
+++ b/mount.lua
@@ -0,0 +1,343 @@
+
+-- lib_mount by Blert2112 (edited by TenPlus1)
+
+local enable_crash = true
+local crash_threshold = 6.5 -- ignored if enable_crash=false
+
+------------------------------------------------------------------------------
+
+--
+-- Helper functions
+--
+
+local function node_is(pos)
+
+ local node = minetest.get_node(pos)
+
+ if node.name == "air" then
+ return "air"
+ end
+
+ if minetest.get_item_group(node.name, "liquid") ~= 0 then
+ return "liquid"
+ end
+
+ if minetest.get_item_group(node.name, "walkable") ~= 0 then
+ return "walkable"
+ end
+
+ return "other"
+end
+
+
+local function get_sign(i)
+
+ i = i or 0
+
+ if i == 0 then
+ return 0
+ else
+ return i / math.abs(i)
+ end
+end
+
+
+local function get_velocity(v, yaw, y)
+
+ local x = -math.sin(yaw) * v
+ local z = math.cos(yaw) * v
+
+ return {x = x, y = y, z = z}
+end
+
+
+local function get_v(v)
+ return math.sqrt(v.x * v.x + v.z * v.z)
+end
+
+
+local function force_detach(player)
+
+ local attached_to = player:get_attach()
+
+ if not attached_to then
+ return
+ end
+
+ local entity = attached_to:get_luaentity()
+
+ if entity.driver
+ and entity.driver == player then
+
+ entity.driver = nil
+ end
+
+ player:set_detach()
+ default.player_attached[player:get_player_name()] = false
+ player:set_eye_offset({x = 0, y = 0, z = 0}, {x = 0, y = 0, z = 0})
+ default.player_set_animation(player, "stand" , 30)
+
+end
+
+-------------------------------------------------------------------------------
+
+
+minetest.register_on_leaveplayer(function(player)
+ force_detach(player)
+end)
+
+minetest.register_on_shutdown(function()
+ local players = minetest.get_connected_players()
+ for i = 1, #players do
+ force_detach(players[i])
+ end
+end)
+
+minetest.register_on_dieplayer(function(player)
+ force_detach(player)
+ return true
+end)
+
+-------------------------------------------------------------------------------
+
+function mobs.attach(entity, player)
+
+ local attach_at, eye_offset = {}, {}
+
+ if not entity.player_rotation then
+ entity.player_rotation = {x = 0, y = 0, z = 0}
+ end
+
+ local rot_view = 0
+
+ if entity.player_rotation.y == 90 then
+ rot_view = math.pi/2
+ end
+
+ if not entity.driver_attach_at then
+ entity.driver_attach_at = {x = 0, y = 0, z = 0}
+ end
+
+ if not entity.driver_eye_offset then
+ entity.driver_eye_offset = {x = 0, y = 0, z = 0}
+ end
+
+ attach_at = entity.driver_attach_at
+ eye_offset = entity.driver_eye_offset
+ entity.driver = player
+
+ force_detach(player)
+
+ player:set_attach(entity.object, "", attach_at, entity.player_rotation)
+ default.player_attached[player:get_player_name()] = true
+ player:set_eye_offset(eye_offset, {x = 0, y = 0, z = 0})
+
+ minetest.after(0.2, function()
+ default.player_set_animation(player, "sit" , 30)
+ end)
+
+ player:set_look_yaw(entity.object:getyaw() - rot_view)
+end
+
+
+function mobs.detach(player, offset)
+
+ force_detach(player)
+ default.player_set_animation(player, "stand" , 30)
+
+ local pos = player:getpos()
+
+ pos = {x = pos.x + offset.x, y = pos.y + 0.2 + offset.y, z = pos.z + offset.z}
+
+ minetest.after(0.1, function()
+ player:setpos(pos)
+ end)
+end
+
+
+function mobs.drive(entity, moving_anim, stand_anim, can_fly)
+
+ local rot_steer, rot_view = math.pi/2, 0
+
+ if entity.player_rotation.y == 90 then
+ rot_steer, rot_view = 0, math.pi/2
+ end
+
+ local acce_y = 0
+ local velo = entity.object:getvelocity()
+
+ entity.v = get_v(velo) * get_sign(entity.v)
+
+ -- process controls
+ if entity.driver then
+
+--print ("---velo", get_v(velo))
+
+ local ctrl = entity.driver:get_player_control()
+
+ -- move forwards
+ if ctrl.up then
+
+ entity.v = entity.v + entity.accel / 10
+
+ -- move backwards
+ elseif ctrl.down then
+
+ if entity.max_speed_reverse == 0 and entity.v == 0 then
+ return
+ end
+
+ entity.v = entity.v - entity.accel / 10
+ end
+
+ --entity.object:setyaw(entity.driver:get_look_yaw() - rot_steer)
+ entity.object:setyaw(entity.driver:get_look_horizontal())-- - rot_steer)
+
+ if can_fly then
+
+ -- fly up
+ if ctrl.jump then
+ velo.y = velo.y + 1
+ if velo.y > entity.accel then velo.y = entity.accel end
+
+ elseif velo.y > 0 then
+ velo.y = velo.y - 0.1
+ if velo.y < 0 then velo.y = 0 end
+ end
+
+ -- fly down
+ if ctrl.sneak then
+ velo.y = velo.y - 1
+ if velo.y < -entity.accel then velo.y = -entity.accel end
+
+ elseif velo.y < 0 then
+ velo.y = velo.y + 0.1
+ if velo.y > 0 then velo.y = 0 end
+ end
+
+ else
+
+ -- jump
+ if ctrl.jump then
+
+ if velo.y == 0 then
+ velo.y = velo.y + entity.jump_height
+ acce_y = acce_y + (acce_y * 3) + 1
+ end
+ end
+
+ end
+ end
+
+ -- if not moving then set animation and return
+ if entity.v == 0 and velo.x == 0 and velo.y == 0 and velo.z == 0 then
+
+ if stand_anim then
+ set_animation(entity, stand_anim)
+ end
+
+ return
+ end
+
+ -- set moving animation
+ if moving_anim then
+ set_animation(entity, moving_anim)
+ end
+
+ -- Stop!
+ local s = get_sign(entity.v)
+
+ entity.v = entity.v - 0.02 * s
+
+ if s ~= get_sign(entity.v) then
+
+ entity.object:setvelocity({x = 0, y = 0, z = 0})
+ entity.v = 0
+ return
+ end
+
+ -- enforce speed limit forward and reverse
+ local max_spd = entity.max_speed_reverse
+
+ if get_sign(entity.v) >= 0 then
+ max_spd = entity.max_speed_forward
+ end
+
+ if math.abs(entity.v) > max_spd then
+ entity.v = entity.v - get_sign(entity.v)
+ end
+
+ -- Set position, velocity and acceleration
+ local p = entity.object:getpos()
+ local new_velo = {x = 0, y = 0, z = 0}
+ local new_acce = {x = 0, y = -9.8, z = 0}
+
+ p.y = p.y - 0.5
+
+ local ni = node_is(p)
+ local v = entity.v
+
+ if ni == "air" then
+
+ if can_fly == true then
+ new_acce.y = 0
+ end
+
+ elseif ni == "liquid" then
+
+ if entity.terrain_type == 2
+ or entity.terrain_type == 3 then
+
+ new_acce.y = 0
+ p.y = p.y + 1
+
+ if node_is(p) == "liquid" then
+
+ if velo.y >= 5 then
+ velo.y = 5
+ elseif velo.y < 0 then
+ new_acce.y = 20
+ else
+ new_acce.y = 5
+ end
+ else
+ if math.abs(velo.y) < 1 then
+ local pos = entity.object:getpos()
+ pos.y = math.floor(pos.y) + 0.5
+ entity.object:setpos(pos)
+ velo.y = 0
+ end
+ end
+ else
+ v = v*0.25
+ end
+-- elseif ni == "walkable" then
+-- v = 0
+-- new_acce.y = 1
+ end
+
+ new_velo = get_velocity(v, entity.object:getyaw() - rot_view, velo.y)
+ new_acce.y = new_acce.y + acce_y
+
+ entity.object:setvelocity(new_velo)
+ entity.object:setacceleration(new_acce)
+
+ -- CRASH!
+ if enable_crash then
+
+ local intensity = entity.v2 - v
+
+ if intensity >= crash_threshold then
+
+--print("----------- crash", intensity)
+
+ entity.object:punch(entity.object, 1.0, {
+ full_punch_interval = 1.0,
+ damage_groups = {fleshy = intensity}
+ }, nil)
+
+ end
+ end
+
+ entity.v2 = v
+end
diff --git a/readme.MD b/readme.MD
index e48c9a5..487d7fa 100644
--- a/readme.MD
+++ b/readme.MD
@@ -23,6 +23,7 @@ Lucky Blocks: 9
Changelog:
+- 1.33- Added functions to mount ride mobs (mobs.attach, mobs.detach, mobs.drive) many thanks to Blert2112
- 1.32- Added new spawn check to count specific mobs AND new minetest.conf setting to chance spawn chance and numbers, added ability to protect tamed mobs
- 1.31- Added 'attack_animals' and 'specific_attack' flags for custom monster attacks, also 'mob_difficulty' .conf setting to make mobs harder.
- 1.30- Added support for invisibility mod (mobs cant attack what they cant see), tweaked and tidied code
diff --git a/textures/mobs_saddle.png b/textures/mobs_saddle.png
new file mode 100644
index 0000000..e9d42f8
--- /dev/null
+++ b/textures/mobs_saddle.png
Binary files differ