7e9a151a4d
now they will be able to go through forest slightly easier (still should be fairly hard though.)
341 lines
11 KiB
Lua
341 lines
11 KiB
Lua
local function is_ground(pos)
|
|
local nn = minetest.get_node(pos).name
|
|
return minetest.get_item_group(nn, "crumbly") ~= 0 or
|
|
minetest.get_item_group(nn, "cracky") ~= 0 or
|
|
minetest.get_item_group(nn, "choppy") ~= 0 or
|
|
minetest.get_item_group(nn, "snappy") ~= 0
|
|
end
|
|
|
|
local function get_sign(i)
|
|
if i == 0 then
|
|
return 0
|
|
else
|
|
return i/math.abs(i)
|
|
end
|
|
end
|
|
|
|
local function get_velocity(speed, yaw, y)
|
|
local x = math.cos(yaw)*speed
|
|
local z = math.sin(yaw)*speed
|
|
return {x=x, y=y, z=z}
|
|
end
|
|
|
|
local function get_speed(velocity)
|
|
return math.sqrt(velocity.x^2+velocity.z^2)
|
|
end
|
|
|
|
-- ===================================================================
|
|
|
|
local function register_wildhorse (basename)
|
|
whinny:register_mob ("whinny:horse"..basename, {
|
|
type = "animal",
|
|
hp_min = 10,
|
|
hp_max = 10,
|
|
collisionbox = {-.45, -0.01, -.45, .45, 1.4, .45},
|
|
available_textures = {
|
|
total = 1,
|
|
texture_1 = {"whinny_horse"..basename..".png"},
|
|
},
|
|
visual = "mesh",
|
|
drops = {
|
|
{name = "creatures:flesh",
|
|
chance = 1,
|
|
min = 2,
|
|
max = 3,},
|
|
},
|
|
mesh = "horsemob.x",
|
|
makes_footstep_sound = true,
|
|
walk_velocity = 1,
|
|
armor = 100,
|
|
drawtype = "front",
|
|
water_damage = 1,
|
|
lava_damage = 5,
|
|
light_damage = 0,
|
|
sounds = {
|
|
random = "",
|
|
},
|
|
animation = {
|
|
speed_normal = 20,
|
|
stand_start = 300,
|
|
stand_end = 460,
|
|
walk_start = 10,
|
|
walk_end = 60
|
|
},
|
|
follow = "farming:wheat",
|
|
view_range = 5,
|
|
on_rightclick = function(self, clicker)
|
|
local item = clicker:get_wielded_item()
|
|
if item:get_name() == "farming:wheat" then
|
|
minetest.add_entity (self.object:getpos(),
|
|
"whinny:horse"..basename.."h1")
|
|
if not minetest.setting_getbool("creative_mode") then
|
|
item:take_item()
|
|
clicker:set_wielded_item(item)
|
|
end
|
|
self.object:remove()
|
|
end
|
|
end,
|
|
jump = true,
|
|
step=1,
|
|
passive = true,
|
|
})
|
|
end
|
|
|
|
-- ===================================================================
|
|
|
|
local function register_basehorse(name, craftitem, horse)
|
|
if craftitem ~= nil then
|
|
function craftitem.on_place(itemstack, placer, pointed_thing)
|
|
if pointed_thing.above then
|
|
minetest.env:add_entity(pointed_thing.above, name)
|
|
if not minetest.setting_getbool("creative_mode") then
|
|
itemstack:take_item()
|
|
end
|
|
end
|
|
return itemstack
|
|
end
|
|
minetest.register_craftitem(name, craftitem)
|
|
end
|
|
|
|
function horse:set_animation(type)
|
|
if type == self.animation_current then
|
|
return
|
|
end
|
|
if type == self.animation.mode_stand then
|
|
if
|
|
self.animation.stand_start
|
|
and self.animation.stand_end
|
|
and self.animation.speed_normal
|
|
then
|
|
self.object:set_animation(
|
|
{x=self.animation.stand_start,y=self.animation.stand_end},
|
|
self.animation.speed_normal * 0.6, 0
|
|
)
|
|
self.animation_current = self.animation.mode_stand
|
|
end
|
|
elseif type == self.animation.mode_walk then
|
|
if
|
|
self.animation.walk_start
|
|
and self.animation.walk_end
|
|
and self.animation.speed_normal
|
|
then
|
|
self.object:set_animation(
|
|
{x=self.animation.walk_start,y=self.animation.walk_end},
|
|
self.animation.speed_normal * 3, 0
|
|
)
|
|
self.animation_current = self.animation.mode_walk
|
|
end
|
|
elseif type == self.animation.mode_gallop then
|
|
if
|
|
self.animation.gallop_start
|
|
and self.animation.gallop_end
|
|
and self.animation.speed_normal
|
|
then
|
|
self.object:set_animation(
|
|
{x=self.animation.gallop_start,y=self.animation.gallop_end},
|
|
self.animation.speed_normal * 2, 0
|
|
)
|
|
self.animation_current = self.animation.mode_gallop
|
|
end
|
|
end
|
|
end
|
|
|
|
function horse:on_step(dtime)
|
|
local p = self.object:getpos()
|
|
p.y = p.y - 0.1
|
|
local on_ground = is_ground(p)
|
|
local inside_block = self.object:getpos()
|
|
inside_block.y = inside_block.y + 1
|
|
|
|
self.speed = get_speed(self.object:getvelocity())*get_sign(self.speed)
|
|
|
|
-- driver controls
|
|
if self.driver then
|
|
local ctrl = self.driver:get_player_control()
|
|
|
|
-- rotation (the faster we go, the less we rotate)
|
|
if ctrl.left then
|
|
self.object:setyaw(self.object:getyaw()+2*(1.5-math.abs(self.speed/self.max_speed))*math.pi/90 +dtime*math.pi/90)
|
|
end
|
|
if ctrl.right then
|
|
self.object:setyaw(self.object:getyaw()-2*(1.5-math.abs(self.speed/self.max_speed))*math.pi/90 -dtime*math.pi/90)
|
|
end
|
|
-- jumping (only if on ground)
|
|
|
|
if ctrl.jump then
|
|
if on_ground then
|
|
local v = self.object:getvelocity()
|
|
local vel = 3
|
|
-- v.y = (self.jump_speed or 3)
|
|
v.y = vel
|
|
self.object:setvelocity(v)
|
|
end
|
|
end
|
|
|
|
-- forwards/backwards
|
|
if ctrl.up then
|
|
self.speed = self.speed + self.forward_boost
|
|
elseif ctrl.down then
|
|
if self.speed >= -2.9 then
|
|
self.speed = self.speed - self.forward_boost
|
|
end
|
|
elseif self.speed < 3 then
|
|
--decay speed if not going fast
|
|
self.speed = self.speed * 0.85
|
|
end
|
|
else
|
|
if math.abs(self.speed) < 1 then
|
|
self.speed = 0
|
|
else
|
|
self.speed = self.speed * 0.90
|
|
end
|
|
end
|
|
|
|
if math.abs(self.speed) < 1 then
|
|
self.object:setvelocity({x=0,y=0,z=0})
|
|
self:set_animation(self.animation.mode_stand)
|
|
elseif self.speed > 5 then
|
|
self:set_animation(self.animation.mode_gallop)
|
|
else
|
|
self:set_animation(self.animation.mode_walk)
|
|
end
|
|
|
|
-- make sure we don't go past the limit
|
|
if minetest.get_item_group(minetest.get_node(inside_block).name, "water") ~= 0 then
|
|
if math.abs(self.speed) > self.max_speed * .2 then
|
|
self.speed = self.max_speed*get_sign(self.speed)*.2
|
|
end
|
|
else
|
|
if math.abs(self.speed) > self.max_speed then
|
|
self.speed = self.max_speed*get_sign(self.speed)
|
|
end
|
|
end
|
|
|
|
local p = self.object:getpos()
|
|
p.y = p.y+1
|
|
if not is_ground(p) then
|
|
if minetest.registered_nodes[minetest.get_node(p).name].walkable then
|
|
self.speed = 0
|
|
end
|
|
self.object:setacceleration({x=0, y=-10, z=0})
|
|
self.object:setvelocity(get_velocity(self.speed, self.object:getyaw(), self.object:getvelocity().y))
|
|
else
|
|
self.object:setacceleration({x=0, y=0, z=0})
|
|
-- falling
|
|
if math.abs(self.object:getvelocity().y) < 1 then
|
|
local pos = self.object:getpos()
|
|
pos.y = math.floor(pos.y)+0.5
|
|
self.object:setpos(pos)
|
|
self.object:setvelocity(get_velocity(self.speed, self.object:getyaw(), 0))
|
|
else
|
|
self.object:setvelocity(get_velocity(self.speed, self.object:getyaw(), self.object:getvelocity().y))
|
|
end
|
|
end
|
|
|
|
if self.object:getvelocity().y > 0.1 then
|
|
local yaw = self.object:getyaw()
|
|
if self.drawtype == "side" then
|
|
yaw = yaw+(math.pi/2)
|
|
end
|
|
local x = math.sin(yaw) * -2
|
|
local z = math.cos(yaw) * 2
|
|
if minetest.get_item_group(minetest.get_node(inside_block).name, "water") ~= 0 then
|
|
self.object:setacceleration({x = x, y = .1, z = z})
|
|
else
|
|
self.object:setacceleration({x = x, y = -10, z = z})
|
|
end
|
|
else
|
|
if minetest.get_item_group(minetest.get_node(inside_block).name, "water") ~= 0 then
|
|
self.object:setacceleration({x = 0, y = .1, z = 0})
|
|
else
|
|
self.object:setacceleration({x = 0, y = -10, z = 0})
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
function horse:on_rightclick(clicker)
|
|
if not clicker or not clicker:is_player() then
|
|
return
|
|
end
|
|
if self.driver and clicker == self.driver then
|
|
self.driver = nil
|
|
clicker:set_detach()
|
|
clicker:set_eye_offset({x=0, y=0, z=0}, {x=0, y=0, z=0})
|
|
elseif not self.driver then
|
|
self.driver = clicker
|
|
clicker:set_attach(self.object, "", {x=0,y=18,z=0}, {x=0,y=90,z=0})
|
|
clicker:set_eye_offset({x=0, y=8, z=0}, {x=0, y=0, z=0})
|
|
--self.object:setyaw(clicker:get_look_yaw())
|
|
end
|
|
end
|
|
|
|
function horse:on_activate(staticdata, dtime_s)
|
|
self.object:set_armor_groups({fleshy=100})
|
|
if staticdata then
|
|
self.speed = tonumber(staticdata)
|
|
end
|
|
end
|
|
|
|
function horse:get_staticdata()
|
|
return tostring(self.speed)
|
|
end
|
|
|
|
function horse:on_punch(puncher, time_from_last_punch, tool_capabilities, direction)
|
|
if self.driver then
|
|
if self.object:get_hp() <= 5 then
|
|
self.driver:set_detach()
|
|
self.driver:set_eye_offset({x=0, y=0, z=0}, {x=0, y=0, z=0})
|
|
self.driver = nil
|
|
end
|
|
end
|
|
end
|
|
|
|
minetest.register_entity(name, horse)
|
|
end
|
|
|
|
local function register_tamehorse (basename, description)
|
|
register_basehorse("whinny:horse"..basename.."h1", {
|
|
description = description,
|
|
inventory_image = "whinny_horse"..basename.."_inventory.png",},{
|
|
physical = true,
|
|
collisionbox = {-.45, -0.01, -.45, .45, 1.4, .45},
|
|
visual = "mesh",
|
|
stepheight = 1.1,
|
|
visual_size = {x=1,y=1},
|
|
mesh = "horse.x",
|
|
textures = {"whinny_horse"..basename..".png"},
|
|
animation = {
|
|
speed_normal = 20,
|
|
stand_start = 300,
|
|
stand_end = 460,
|
|
walk_start = 10,
|
|
walk_end = 59,
|
|
gallop_start = 70,
|
|
gallop_end = 119,
|
|
mode_stand = 1,
|
|
mode_walk = 2,
|
|
mode_gallop = 3,
|
|
},
|
|
animation_current = 0,
|
|
max_speed = 7,
|
|
forward_boost = .2,
|
|
jump_boost = 4,
|
|
speed = 0,
|
|
driver = nil
|
|
})
|
|
end
|
|
|
|
register_tamehorse ("", "Brown Horse")
|
|
register_wildhorse ("")
|
|
register_tamehorse ("peg", "White Horse")
|
|
register_wildhorse ("peg")
|
|
register_tamehorse ("ara", "Black Horse")
|
|
register_wildhorse ("ara")
|
|
|
|
--function whinny:register_spawn(name, nodes, max_light, min_light, chance, active_object_count, max_height, spawn_func)
|
|
|
|
whinny:register_spawn("whinny:horse","default:dirt_with_grass",20, 6, 50000, 1, 100)
|
|
whinny:register_spawn("whinny:horsepeg","default:dirt_with_dry_grass",20, 6, 50000, 1, 100)
|
|
whinny:register_spawn("whinny:horseara","default:dirt_with_grass",20, 6, 50000, 1, 100)
|