horse.lua 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697
  1. local function is_ground(pos)
  2. local nn = minetest.get_node(pos).name
  3. return minetest.get_item_group(nn, "crumbly") ~= 0 or
  4. minetest.get_item_group(nn, "cracky") ~= 0 or
  5. minetest.get_item_group(nn, "choppy") ~= 0 or
  6. minetest.get_item_group(nn, "snappy") ~= 0
  7. end
  8. local function get_sign(i)
  9. if i == 0 then
  10. return 0
  11. else
  12. return i/math.abs(i)
  13. end
  14. end
  15. local function get_velocity(v, yaw, y)
  16. local x = math.cos(yaw)*v
  17. local z = math.sin(yaw)*v
  18. return {x=x, y=y, z=z}
  19. end
  20. local function get_v(v)
  21. return math.sqrt(v.x^2+v.z^2)
  22. end
  23. function lottmobs:register_horse(name, craftitem, horse)
  24. if craftitem ~= nil then
  25. function craftitem.on_place(itemstack, placer, pointed_thing)
  26. if pointed_thing.above then
  27. minetest.add_entity(pointed_thing.above, name)
  28. if not minetest.setting_getbool("creative_mode") then
  29. itemstack:take_item()
  30. end
  31. end
  32. return itemstack
  33. end
  34. minetest.register_craftitem(name, craftitem)
  35. end
  36. horse.v = 0
  37. horse.driver = nil
  38. function horse:set_animation(type)
  39. if not self.animation then
  40. return
  41. end
  42. if not self.animation.current then
  43. self.animation.current = ""
  44. end
  45. if type == "stand" and self.animation.current ~= "stand" then
  46. if
  47. self.animation.stand_start
  48. and self.animation.stand_end
  49. and self.animation.speed_normal
  50. then
  51. self.object:set_animation(
  52. {x=self.animation.stand_start,y=self.animation.stand_end},
  53. self.animation.speed_normal * 0.6, 0
  54. )
  55. self.animation.current = "stand"
  56. end
  57. elseif type == "walk" and self.animation.current ~= "walk" then
  58. if
  59. self.animation.walk_start
  60. and self.animation.walk_end
  61. and self.animation.speed_normal
  62. then
  63. self.object:set_animation(
  64. {x=self.animation.walk_start,y=self.animation.walk_end},
  65. self.animation.speed_normal * 3, 0
  66. )
  67. self.animation.current = "walk"
  68. end
  69. elseif type == "punch" and self.animation.current ~= "punch" then
  70. if
  71. self.animation.punch_start
  72. and self.animation.punch_end
  73. and self.animation.speed_normal
  74. then
  75. self.object:set_animation(
  76. {x=self.animation.punch_start,y=self.animation.punch_end},
  77. self.animation.speed_normal * 3, 0
  78. )
  79. self.animation.current = "punch"
  80. end
  81. end
  82. end
  83. function horse:on_step(dtime)
  84. local p = self.object:getpos()
  85. p.y = p.y - 0.1
  86. local on_ground = is_ground(p)
  87. self.v = get_v(self.object:get_velocity())*get_sign(self.v)
  88. -- driver controls
  89. if self.driver then
  90. local ctrl = self.driver:get_player_control()
  91. -- rotation (the faster we go, the less we rotate)
  92. if ctrl.left then
  93. self.object:setyaw(self.object:getyaw()+2*(1.5-math.abs(self.v/self.max_speed))*math.pi/90 +dtime*math.pi/90)
  94. end
  95. if ctrl.right then
  96. self.object:setyaw(self.object:getyaw()-2*(1.5-math.abs(self.v/self.max_speed))*math.pi/90 -dtime*math.pi/90)
  97. end
  98. -- jumping (only if on ground)
  99. if ctrl.jump and on_ground then
  100. local v = self.object:getvelocity()
  101. v.y = (self.jump_speed or 3)
  102. self.object:setvelocity(v)
  103. end
  104. -- forwards/backwards
  105. if ctrl.up then
  106. self.v = self.v + self.forward_boost
  107. elseif ctrl.down then
  108. self.v = self.v - 0.3
  109. elseif on_ground then
  110. if math.abs(self.v) < 1 then
  111. self.v = 0
  112. else
  113. self.v = self.v * 0.8
  114. end
  115. end
  116. else
  117. if math.abs(self.v) < 1 then
  118. self.v = 0
  119. else
  120. self.v = self.v * 0.95
  121. end
  122. end
  123. local underattack = self.underattack or false
  124. if self.v == 0 then
  125. if underattack ~= true then
  126. self.object:setvelocity({x=0,y=0,z=0})
  127. self:set_animation("stand")
  128. return
  129. else
  130. self:set_animation("punch")
  131. end
  132. else
  133. self:set_animation("walk")
  134. end
  135. -- make sure we don't go past the limit
  136. if math.abs(self.v) > self.max_speed then
  137. self.v = self.max_speed*get_sign(self.v)
  138. end
  139. local p = self.object:getpos()
  140. p.y = p.y+1
  141. if not is_ground(p) then
  142. if minetest.registered_nodes[minetest.get_node(p).name].walkable then
  143. self.v = 0
  144. end
  145. self.object:setacceleration({x=0, y=-10, z=0})
  146. self.object:setvelocity(get_velocity(self.v, self.object:getyaw(), self.object:getvelocity().y))
  147. else
  148. self.object:setacceleration({x=0, y=0, z=0})
  149. -- falling
  150. if math.abs(self.object:getvelocity().y) < 1 then
  151. local pos = self.object:getpos()
  152. pos.y = math.floor(pos.y)+0.5
  153. self.object:setpos(pos)
  154. self.object:setvelocity(get_velocity(self.v, self.object:getyaw(), 0))
  155. else
  156. self.object:setvelocity(get_velocity(self.v, self.object:getyaw(), self.object:getvelocity().y))
  157. end
  158. end
  159. if self.object:getvelocity().y > 0.1 then
  160. local yaw = self.object:getyaw()
  161. if self.drawtype == "side" then
  162. yaw = yaw+(math.pi/2)
  163. end
  164. local x = math.sin(yaw) * -2
  165. local z = math.cos(yaw) * 2
  166. if minetest.get_item_group(minetest.get_node(self.object:getpos()).name, "water") ~= 0 then
  167. self.object:setacceleration({x = x, y = 2, z = z})
  168. else
  169. self.object:setacceleration({x = x, y = -5, z = z})
  170. end
  171. else
  172. if minetest.get_item_group(minetest.get_node(self.object:getpos()).name, "water") ~= 0 then
  173. self.object:setacceleration({x = 0, y = 2, z = 0})
  174. else
  175. self.object:setacceleration({x = 0, y = -5, z = 0})
  176. end
  177. end
  178. end
  179. function horse:on_rightclick(clicker)
  180. if not clicker or not clicker:is_player() then
  181. return
  182. end
  183. if self.driver and clicker == self.driver then
  184. self.driver = nil
  185. clicker:set_detach()
  186. default.player_attached[clicker:get_player_name()] = false
  187. if self.offset == true then
  188. clicker:set_eye_offset({x=0,y=0,z=0},{x=0,y=0,z=0})
  189. end
  190. elseif not self.driver then
  191. self.driver = clicker
  192. attach_h = self.attach_h or 5
  193. attach_r = self.attach_r or 90
  194. clicker:set_attach(self.object, "", {x=0,y= attach_h ,z=0}, {x=0,y= attach_r ,z=0})
  195. default.player_attached[clicker:get_player_name()] = true
  196. self.object:setyaw(clicker:get_look_yaw())
  197. self.ridername = clicker:get_player_name()
  198. if self.offset == true then
  199. offset_h = self.offset_h or 0
  200. offset_r = self.offset_r or 0
  201. clicker:set_eye_offset({x=0,y= offset_h ,z=0},{x=0,y= offset_r ,z=0})
  202. end
  203. end
  204. end
  205. function horse:on_activate(staticdata, dtime_s)
  206. self.object:set_armor_groups({fleshy=100})
  207. if staticdata then
  208. self.v = tonumber(staticdata)
  209. end
  210. local hp = self.hp or 10
  211. self.object:set_hp(hp)
  212. end
  213. function horse:get_staticdata()
  214. return tostring(self.v)
  215. end
  216. function horse:on_punch(puncher, time_from_last_punch, tool_capabilities, direction)
  217. local ridername = self.ridername
  218. if ridername ~= nil then
  219. rider = minetest.get_player_by_name(ridername)
  220. end
  221. if puncher and puncher:is_player() then
  222. if puncher:get_player_name() == ridername or ridername == nil then
  223. puncher:get_inventory():add_item("main", name)
  224. default.player_attached[puncher:get_player_name()] = false
  225. puncher:set_detach()
  226. self.object:remove()
  227. if self.offset == true then
  228. puncher:set_eye_offset({x=0,y=0,z=0},{x=0,y=0,z=0})
  229. end
  230. elseif self.aggressive == true then
  231. local objs = minetest.get_objects_inside_radius(self.object:getpos(), 4)
  232. local _,obj
  233. for _,obj in ipairs(objs) do
  234. if obj:is_player() and puncher:get_player_name() == obj:get_player_name() then
  235. self.underattack = true
  236. minetest.after(2, function()
  237. self.underattack = false
  238. end)
  239. puncher:punch(self.object, 1.0, {
  240. full_punch_interval = 1.0,
  241. damage_groups = {fleshy = self.dps}
  242. }, nil)
  243. end
  244. end
  245. end
  246. else
  247. if puncher and self.aggressive == true then
  248. local objs = minetest.get_objects_inside_radius(self.object:getpos(), 4)
  249. local _,obj
  250. for _,obj in ipairs(objs) do
  251. if puncher:get_luaentity() == obj:get_luaentity() then
  252. self.underattack = true
  253. minetest.after(2, function()
  254. self.underattack = false
  255. end)
  256. puncher:punch(self.object, 1.0, {
  257. full_punch_interval = 1.0,
  258. damage_groups = {fleshy = self.dps}
  259. }, nil)
  260. end
  261. end
  262. end
  263. end
  264. if self.object:get_hp() <= 0 then
  265. default.player_attached[ridername] = false
  266. rider:set_detach()
  267. self.object:remove()
  268. if self.offset == true then
  269. rider:set_eye_offset({x=0,y=0,z=0},{x=0,y=0,z=0})
  270. end
  271. end
  272. end
  273. minetest.register_entity(name, horse)
  274. end
  275. ---------------------
  276. lottmobs:register_horse("lottmobs:horseh1", {
  277. description = "Brown Horse",
  278. inventory_image = "lottmobs_horse_inventory.png",
  279. }, {
  280. physical = true,
  281. collisionbox = {-0.4, -0.01, -0.4, 0.4, 1, 0.4},
  282. visual = "mesh",
  283. stepheight = 1.1,
  284. visual_size = {x=1,y=1},
  285. mesh = "horseh1_model.x",
  286. textures = {"lottmobs_horse.png"},
  287. animation = {
  288. speed_normal = 10,
  289. stand_start = 0,
  290. stand_end = 50,
  291. walk_start = 75,
  292. walk_end = 98,
  293. },
  294. max_speed = 7,
  295. forward_boost = 2.33,
  296. jump_boost = 4
  297. })
  298. --horse white
  299. lottmobs:register_horse("lottmobs:horsepegh1", {
  300. description = "White Horse",
  301. inventory_image = "lottmobs_horsepeg_inventory.png",
  302. }, {
  303. physical = true,
  304. collisionbox = {-0.4, -0.01, -0.4, 0.4, 1, 0.4},
  305. visual = "mesh",
  306. stepheight = 1.1,
  307. visual_size = {x=1,y=1},
  308. mesh = "horseh1_model.x",
  309. textures = {"lottmobs_horsepeg.png"},
  310. animation = {
  311. speed_normal = 10,
  312. stand_start = 0,
  313. stand_end = 50,
  314. walk_start = 75,
  315. walk_end = 98,
  316. },
  317. max_speed = 7,
  318. forward_boost = 2.33,
  319. jump_boost = 4
  320. })
  321. --horse arabik
  322. lottmobs:register_horse("lottmobs:horsearah1", {
  323. description = "Black Horse",
  324. inventory_image = "lottmobs_horseara_inventory.png",
  325. }, {
  326. physical = true,
  327. collisionbox = {-0.4, -0.01, -0.4, 0.4, 1, 0.4},
  328. visual = "mesh",
  329. stepheight = 1.1,
  330. visual_size = {x=1,y=1},
  331. mesh = "horseh1_model.x",
  332. textures = {"lottmobs_horseara.png"},
  333. animation = {
  334. speed_normal = 10,
  335. stand_start = 0,
  336. stand_end = 50,
  337. walk_start = 75,
  338. walk_end = 98,
  339. },
  340. max_speed = 7,
  341. forward_boost = 2.33,
  342. jump_boost = 4
  343. })
  344. lottmobs:register_horse("lottmobs:shireponyblackh1", {
  345. description = "Shire Pony",
  346. inventory_image = "lottmobs_shireponyblack_inventory.png",
  347. }, {
  348. physical = true,
  349. collisionbox = {-0.4, -0.01, -0.4, 0.4, 1, 0.4},
  350. visual = "mesh",
  351. stepheight = 1.1,
  352. visual_size = {x=1.3,y=1.3},
  353. mesh = "shireponyh1_model.x",
  354. textures = {"lottmobs_shireponyblack.png"},
  355. animation = {
  356. speed_normal = 15,
  357. stand_start = 0,
  358. stand_end = 39,
  359. walk_start = 45,
  360. walk_end = 85,
  361. },
  362. max_speed = 5,
  363. forward_boost = 1.67,
  364. jump_boost = 3
  365. })
  366. lottmobs:register_horse("lottmobs:shireponyh1", {
  367. description = "Shire Pony",
  368. inventory_image = "lottmobs_shirepony_inventory.png",
  369. }, {
  370. physical = true,
  371. collisionbox = {-0.4, -0.01, -0.4, 0.4, 1, 0.4},
  372. visual = "mesh",
  373. stepheight = 1.1,
  374. visual_size = {x=1.3,y=1.3},
  375. mesh = "shireponyh1_model.x",
  376. textures = {"lottmobs_shirepony.png"},
  377. animation = {
  378. speed_normal = 15,
  379. stand_start = 0,
  380. stand_end = 39,
  381. walk_start = 45,
  382. walk_end = 85,
  383. },
  384. max_speed = 5,
  385. forward_boost = 1.67,
  386. jump_boost = 3
  387. })
  388. ----------------------
  389. mobs:register_mob("lottmobs:horse", {
  390. type = "animal",
  391. hp_min = 5,
  392. hp_max = 7,
  393. collisionbox = {-0.4, -0.01, -0.4, 0.4, 1, 0.4},
  394. textures = {
  395. {"lottmobs_horse.png"},
  396. },
  397. visual = "mesh",
  398. mesh = "horse_model.x",
  399. makes_footstep_sound = true,
  400. walk_velocity = 1,
  401. armor = 200,
  402. drops = {
  403. {name = "lottmobs:meat_raw",
  404. chance = 1,
  405. min = 2,
  406. max = 3,},
  407. },
  408. drawtype = "front",
  409. water_damage = 1,
  410. lava_damage = 5,
  411. light_damage = 0,
  412. sounds = {
  413. random = "",
  414. },
  415. animation = {
  416. speed_normal = 15,
  417. stand_start = 25,
  418. stand_end = 75,
  419. walk_start = 75,
  420. walk_end = 100,
  421. },
  422. follow = "farming:wheat",
  423. view_range = 5,
  424. on_rightclick = function(self, clicker)
  425. local item = clicker:get_wielded_item()
  426. if item:get_name() == "farming:wheat" then
  427. minetest.add_entity(self.object:getpos(), "lottmobs:horseh1")
  428. if not minetest.setting_getbool("creative_mode") then
  429. item:take_item()
  430. clicker:set_wielded_item(item)
  431. end
  432. self.object:remove()
  433. end
  434. end,
  435. jump = true,
  436. step=1,
  437. passive = true,
  438. })
  439. mobs:register_spawn("lottmobs:horse", {"lottmapgen:rohan_grass"}, 20, -1, 6000, 3, 31000)
  440. mobs:register_mob("lottmobs:horsepeg", {
  441. type = "animal",
  442. hp_min = 5,
  443. hp_max = 7,
  444. collisionbox = {-0.4, -0.01, -0.4, 0.4, 1, 0.4},
  445. textures = {
  446. {"lottmobs_horsepeg.png"},
  447. },
  448. visual = "mesh",
  449. mesh = "horse_model.x",
  450. makes_footstep_sound = true,
  451. walk_velocity = 1,
  452. armor = 200,
  453. drops = {
  454. {name = "lottmobs:meat_raw",
  455. chance = 1,
  456. min = 2,
  457. max = 3,},
  458. },
  459. drawtype = "front",
  460. water_damage = 1,
  461. lava_damage = 5,
  462. light_damage = 0,
  463. sounds = {
  464. random = "",
  465. },
  466. animation = {
  467. speed_normal = 15,
  468. stand_start = 25,
  469. stand_end = 75,
  470. walk_start = 75,
  471. walk_end = 100,
  472. },
  473. follow = "farming:wheat",
  474. view_range = 5,
  475. on_rightclick = function(self, clicker)
  476. local item = clicker:get_wielded_item()
  477. if item:get_name() == "farming:wheat" then
  478. minetest.add_entity(self.object:getpos(), "lottmobs:horsepegh1")
  479. if not minetest.setting_getbool("creative_mode") then
  480. item:take_item()
  481. clicker:set_wielded_item(item)
  482. end
  483. self.object:remove()
  484. end
  485. end,
  486. jump = true,
  487. step=1,
  488. passive = true,
  489. })
  490. mobs:register_spawn("lottmobs:horsepeg", {"lottmapgen:rohan_grass"}, 20, -1, 7000, 3, 31000)
  491. mobs:register_mob("lottmobs:horseara", {
  492. type = "animal",
  493. hp_min = 5,
  494. hp_max = 7,
  495. collisionbox = {-0.4, -0.01, -0.4, 0.4, 1, 0.4},
  496. textures = {
  497. {"lottmobs_horseara.png"},
  498. },
  499. visual = "mesh",
  500. mesh = "horse_model.x",
  501. makes_footstep_sound = true,
  502. walk_velocity = 1,
  503. armor = 200,
  504. drops = {
  505. {name = "lottmobs:meat_raw",
  506. chance = 1,
  507. min = 2,
  508. max = 3,},
  509. },
  510. drawtype = "front",
  511. water_damage = 1,
  512. lava_damage = 5,
  513. light_damage = 0,
  514. sounds = {
  515. random = "",
  516. },
  517. animation = {
  518. speed_normal = 15,
  519. stand_start = 25,
  520. stand_end = 75,
  521. walk_start = 75,
  522. walk_end = 100,
  523. },
  524. follow = "farming:wheat",
  525. view_range = 5,
  526. on_rightclick = function(self, clicker)
  527. local item = clicker:get_wielded_item()
  528. if item:get_name() == "farming:wheat" then
  529. minetest.add_entity(self.object:getpos(), "lottmobs:horsearah1")
  530. if not minetest.setting_getbool("creative_mode") then
  531. item:take_item()
  532. clicker:set_wielded_item(item)
  533. end
  534. self.object:remove()
  535. end
  536. end,
  537. jump = true,
  538. step=1,
  539. passive = true,
  540. })
  541. mobs:register_spawn("lottmobs:horseara", {"lottmapgen:rohan_grass"}, 20, -1, 7000, 3, 31000)
  542. mobs:register_mob("lottmobs:shirepony", {
  543. type = "animal",
  544. hp_min = 5,
  545. hp_max = 7,
  546. collisionbox = {-0.4, -0.01, -0.4, 0.4, 1, 0.4},
  547. textures = {
  548. {"lottmobs_shirepony.png"},
  549. },
  550. visual = "mesh",
  551. mesh = "shirepony_model.x",
  552. makes_footstep_sound = true,
  553. walk_velocity = 1,
  554. armor = 200,
  555. visual_size = {x=1.3,y=1.3},
  556. drops = {
  557. {name = "lottmobs:meat_raw",
  558. chance = 1,
  559. min = 2,
  560. max = 3,},
  561. },
  562. drawtype = "front",
  563. water_damage = 1,
  564. lava_damage = 5,
  565. light_damage = 0,
  566. sounds = {
  567. random = "",
  568. },
  569. animation = {
  570. speed_normal = 15,
  571. stand_start = 0,
  572. stand_end = 40,
  573. walk_start = 45,
  574. walk_end = 85,
  575. },
  576. follow = "farming:wheat",
  577. view_range = 5,
  578. on_rightclick = function(self, clicker)
  579. local item = clicker:get_wielded_item()
  580. if item:get_name() == "farming:wheat" then
  581. minetest.add_entity(self.object:getpos(), "lottmobs:shireponyh1")
  582. if not minetest.setting_getbool("creative_mode") then
  583. item:take_item()
  584. clicker:set_wielded_item(item)
  585. end
  586. self.object:remove()
  587. end
  588. end,
  589. jump = true,
  590. step=1,
  591. passive = true,
  592. })
  593. mobs:register_spawn("lottmobs:shirepony", {"lottmapgen:shire_grass"}, 20, -1, 6000, 3, 31000)
  594. mobs:register_mob("lottmobs:shireponyblack", {
  595. type = "animal",
  596. hp_min = 5,
  597. hp_max = 7,
  598. collisionbox = {-0.4, -0.01, -0.4, 0.4, 1, 0.4},
  599. textures = {
  600. {"lottmobs_shireponyblack.png"},
  601. },
  602. visual = "mesh",
  603. mesh = "shirepony_model.x",
  604. makes_footstep_sound = true,
  605. walk_velocity = 1,
  606. armor = 200,
  607. visual_size = {x=1.3,y=1.3},
  608. drops = {
  609. {name = "lottmobs:meat_raw",
  610. chance = 1,
  611. min = 2,
  612. max = 3,},
  613. },
  614. drawtype = "front",
  615. water_damage = 1,
  616. lava_damage = 5,
  617. light_damage = 0,
  618. sounds = {
  619. random = "",
  620. },
  621. animation = {
  622. speed_normal = 15,
  623. stand_start = 0,
  624. stand_end = 40,
  625. walk_start = 45,
  626. walk_end = 85,
  627. },
  628. follow = "farming:wheat",
  629. view_range = 5,
  630. on_rightclick = function(self, clicker)
  631. local item = clicker:get_wielded_item()
  632. if item:get_name() == "farming:wheat" then
  633. minetest.add_entity(self.object:getpos(), "lottmobs:shireponyblackh1")
  634. if not minetest.setting_getbool("creative_mode") then
  635. item:take_item()
  636. clicker:set_wielded_item(item)
  637. end
  638. self.object:remove()
  639. end
  640. end,
  641. jump = true,
  642. step=1,
  643. passive = true,
  644. })
  645. mobs:register_spawn("lottmobs:shireponyblack", {"lottmapgen:shire_grass"}, 20, -1, 9000, 3, 31000)