This commit is contained in:
natey2000 2025-04-11 17:53:58 -06:00
commit f5aae11a27
10 changed files with 258 additions and 176 deletions

View file

@ -1,19 +1,42 @@
[![ContentDB](https://content.luanti.org/packages/Sumianvoice/sum_airship/shields/downloads/)]
# sum_airship # sum_airship
Mod for minetest
[ContentDB](https://content.minetest.net/packages/Sumianvoice/sum_airship/) Mod for [Luanti](https://luanti.org). You can download it from the in-game content manager, or [ContentDB](https://content.luanti.org/packages/Sumianvoice/sum_airship/).
This mod adds an airship to Minetest. It should work in most games, but only Minetest Game, MineClone (VoxeLibre) and RePixture are supported for crafting recipes. Games based on those may still have crafting if they use the same items. Other games are not because the mod doesn't know what each game calls each item or node. Although, it shouldn't crash no matter what game you use, this is only for crafting recipes.
**Controls:** Flies like a boat, WASD, jump and aux1 (sprint) for up and down. Shift to dismount. Does not require fuel but will go faster when given any type of coal.
This adds an airship to minetest_game or mcl2. Not tested on any other games. If it uses default:steel_ingot or mcl_core:iron_ingot for example, then it should work. It should not crash no matter what game you use though, this is only for the crafting recipes. The dependency on MTG or MCL2 is only for crafting, otherwise the ship it self can still be used just not crafted (because I don't know what your game calls each item / node etc) ### Crafting
Flies like a boat, WSAD controls with the addition of jump for up, sneak for down, and aux1 (sprint) to dismount. Does not require fuel but will go faster when given any type of coal. #### MineClon\* (VoxeLibre)
### Crafting (mcl)
Craftable with wool > canvas and boats > hull. All items: wool: 27, string: 4, wood: 15, iron_ingot: 4 All items: wool: 27, string: 4, wood: 15, iron_ingot: 4
9 Wool -> Canvas
3 Boats & 3 Iron Ingots -> Hull
3 Canvas, 1 Hull, 4 String & 1 Iron ingot -> Airship
![MCL crafting.gif](crafting_mcl.gif)
#### Minetest Game
All items: wool: 27, string: 4, wood: 15, iron_ingot: 4
9 Wool -> Canvas
3 Boats & 3 Iron Ingots -> Hull
3 Canvas, 1 Hull, 4 String & 1 Iron ingot -> Airship
![MTG crafting.gif](crafting_mtg.gif)
#### RePixture
All items: wool: 27, fiber: 8, wood: varies depending on boat type, steel_ingot: 4
9 group:fuzzy (wool or cotton bale) -> Canvas
3 Boats & 3 Steel Ingots -> Hull
3 Canvas, 1 Hull, 8 Fiber, 1 Steel Ingot -> Airship
![RePixture crafting.gif](crafting_rp.gif)
#### Crafting Guide GIF:
![airship%20crafting.gif](airship%20crafting.gif)
### Air Currents ### Air Currents
This optionally uses [sum_air_currents](https://content.minetest.net/packages/Sumianvoice/sum_air_currents/) to apply force based on the weather. Both this mod and the air currents mod are in development so expect changes made regularly. This optionally uses [sum_air_currents](https://content.luanti.org/packages/Sumianvoice/sum_air_currents/) to apply force based on the weather.

View file

@ -2,23 +2,25 @@ local mod_name = minetest.get_current_modname()
local mod_path = minetest.get_modpath(mod_name) local mod_path = minetest.get_modpath(mod_name)
local me = { local me = {
lift = 4, lift = 4,
speed = 4, speed = 4,
fuel_time = 10, fuel_time = 10,
speed_mult = 4, speed_mult = 4,
i = {}, i = {},
} }
local ship = { local ship = {
physical = true, initial_properties = {
pointable = true, physical = true,
collisionbox = {-0.6, -0.2, -0.6, 0.6, 0.3, 0.6}, pointable = true,
selectionbox = {-0.7, -0.35, -0.7, 0.7, 0.3, 0.7}, collisionbox = {-0.6, -0.2, -0.6, 0.6, 0.4, 0.6},
hp_max = 3, selectionbox = {-0.7, -0.35, -0.7, 0.7, 0.4, 0.7},
visual = "mesh", hp_max = 3,
backface_culling = false, visual = "mesh",
mesh = "sum_airship.b3d", backface_culling = true,
textures = {"sum_airship_texture.png"}, mesh = "sum_airship.b3d",
textures = {"sum_airship_texture.png"},
},
_animations = { _animations = {
idle = {x= 10, y= 90}, idle = {x= 10, y= 90},
fly = {x= 91, y= 170}, fly = {x= 91, y= 170},
@ -26,8 +28,8 @@ local ship = {
}, },
_driver = nil, _driver = nil,
_removed = false, _removed = false,
_flags = {}, _flags = {},
_itemstring = "sum_airship:boat", _itemstring = "sum_airship:boat",
_passenger = nil, _passenger = nil,
_vel = 0, _vel = 0,
_regen_timer = 0, _regen_timer = 0,
@ -88,7 +90,7 @@ function me.sound_countdown(self, dtime)
end end
function me.update_sound(self, dtime, forward) function me.update_sound(self, dtime, forward)
me.sound_countdown(self, dtime) me.sound_countdown(self, dtime)
local is_thrust = (forward ~= 0) and self._driver local is_thrust = (forward ~= 0) and self._driver
@ -128,15 +130,17 @@ function ship.on_activate(self, staticdata, dtime_s)
self._vel = data.v self._vel = data.v
self._itemstring = data.itemstring self._itemstring = data.itemstring
self._fuel = data.fuel self._fuel = data.fuel
if data._driver then self._flags = data._flags
self._driver = minetest.get_player_by_name((data._driver))
else
self._driver = nil
end
self._flags = data._flags
if self._driver then me.detach(self) end
end end
self.object:set_animation(ship._animations.idle, 24) self.object:set_armor_groups({
pierce=100,
slash=100,
blunt=100,
magic=100,
poison=100,
fleshy=100,
})
self.object:set_animation(ship._animations.idle, 24)
self._sounds = { -- workaround for copy vs reference issue self._sounds = { -- workaround for copy vs reference issue
engine = { engine = {
handle = nil, handle = nil,
@ -156,41 +160,39 @@ end
function ship.get_staticdata(self) function ship.get_staticdata(self)
return minetest.serialize({ return minetest.serialize({
itemstring = self._itemstring, itemstring = self._itemstring,
_driver = ((self._driver and self._driver:is_player()) _flags = self._flags,
and self._driver:get_player_name()) or nil,
_flags = self._flags,
v = self._vel, v = self._vel,
fuel = self._fuel, fuel = self._fuel,
}) })
end end
function me.attach(self, player) function me.attach(self, player)
if not (player and player:is_player()) then if not (player and player:is_player()) then
return false return false
end end
self._driver = player self._driver = player
self._driver:set_attach(self.object, "", self._driver:set_attach(self.object, "",
{x = 0, y = -3.0, z = 0}, {x = 0, y = 0, z = 0}) {x = 0, y = -0.0, z = -2}, {x = 0, y = 0, z = 0})
self._driver:set_look_horizontal(self.object:get_yaw()) self._driver:set_look_horizontal(self.object:get_yaw())
end end
function me.detach(self) function me.detach(self)
if not self._driver then return false end if not self._driver then return false end
self._driver:set_detach() self._driver:set_detach()
self._driver = nil self._driver = nil
return true return true
end end
function ship.on_death(self, killer) function ship.on_death(self, killer)
if killer and killer:is_player() if killer and killer:is_player()
and not minetest.is_creative_enabled(killer:get_player_name()) then and not minetest.is_creative_enabled(killer:get_player_name()) then
local inv = killer:get_inventory() local inv = killer:get_inventory()
inv:add_item("main", self._itemstring) inv:add_item("main", self._itemstring)
else else
minetest.add_item(self.object:get_pos(), self._itemstring) minetest.add_item(self.object:get_pos(), self._itemstring)
end end
me.detach(self) me.detach(self)
self._driver = nil self._driver = nil
end end
@ -198,7 +200,7 @@ function ship.on_rightclick(self, clicker)
local item = clicker:get_wielded_item() local item = clicker:get_wielded_item()
local item_name = item:get_name() local item_name = item:get_name()
if clicker and (item and item_name) if clicker and (item and item_name)
and (string.find(item_name, ":coal") and (string.find(item_name, ":coal")
or string.find(item_name, ":charcoal")) then or string.find(item_name, ":charcoal")) then
if not minetest.is_creative_enabled(clicker:get_player_name()) then if not minetest.is_creative_enabled(clicker:get_player_name()) then
item:take_item() item:take_item()
@ -260,16 +262,16 @@ function me.get_balloon_collide(self)
for _, check in pairs(balloon_nodes) do for _, check in pairs(balloon_nodes) do
local n = minetest.get_node(vector.add(check.p, o)) local n = minetest.get_node(vector.add(check.p, o))
if n and minetest.registered_nodes[n.name] if n and minetest.registered_nodes[n.name]
and minetest.registered_nodes[n.name].walkable then and (minetest.registered_nodes[n.name] or {}).walkable then
force = vector.add(force, check.dir) force = vector.add(force, check.dir)
end end
end end
return force return force
end end
me.chimney_dist = -1.0 me.chimney_dist = -0.8
me.chimney_yaw = 0.13 me.chimney_yaw = 0.13
me.chimney_height = 0.9 me.chimney_height = 1.5
function me.get_chimney_pos(self) function me.get_chimney_pos(self)
local p = self.object:get_pos() local p = self.object:get_pos()
local yaw = self.object:get_yaw() local yaw = self.object:get_yaw()
@ -281,50 +283,50 @@ function me.get_chimney_pos(self)
end end
function ship.on_step(self, dtime, moveresult) function ship.on_step(self, dtime, moveresult)
local exit = false local exit = false
local pi = nil local pi = nil
-- allow to exit -- allow to exit
if self._driver and self._driver:is_player() then if self._driver and self._driver:is_player() then
local name = self._driver:get_player_name() local name = self._driver:get_player_name()
pi = self._driver:get_player_control() pi = self._driver:get_player_control()
exit = pi.aux1 exit = pi.sneak
end end
if exit then if exit then
me.detach(self) me.detach(self)
return false return false
end end
local climb = 0 local climb = 0
local right = 0 local right = 0
local forward = 0 local forward = 0
local v = self.object:get_velocity() local v = self.object:get_velocity()
local p = self.object:get_pos() local p = self.object:get_pos()
local node_below = minetest.get_node(vector.offset(p, 0, -0.8, 0)).name local node_below = minetest.get_node(vector.offset(p, 0, -0.8, 0)).name
local is_on_floor = minetest.registered_nodes[node_below].walkable local is_on_floor = (minetest.registered_nodes[node_below] or {}).walkable
local in_water = minetest.get_item_group(minetest.get_node(p).name, "liquid") ~= 0 local in_water = minetest.get_item_group(minetest.get_node(p).name, "liquid") ~= 0
local on_water = (minetest.get_item_group(minetest.get_node(vector.offset(p, 0, -0.2, 0)).name, "liquid") ~= 0 and not in_water) local on_water = (minetest.get_item_group(minetest.get_node(vector.offset(p, 0, -0.2, 0)).name, "liquid") ~= 0 and not in_water)
local speedboost = 1 local speedboost = 1
if self._fuel > 0 then if self._fuel > 0 then
self._fuel = self._fuel - dtime self._fuel = self._fuel - dtime
speedboost = 3 speedboost = 3
end end
if pi then if pi then
if pi.up then forward = 1 if pi.up then forward = 1
elseif pi.down then forward = -1 end elseif pi.down then forward = -1 end
if pi.jump then climb = 1 if pi.jump then climb = 1
elseif pi.sneak then climb = -1 end elseif pi.aux1 then climb = -1 end
if pi.right then right = 1 if pi.right then right = 1
elseif pi.left then right = -1 end elseif pi.left then right = -1 end
local yaw = self.object:get_yaw() local yaw = self.object:get_yaw()
local dir = minetest.yaw_to_dir(yaw) local dir = minetest.yaw_to_dir(yaw)
self.object:set_yaw(yaw - right * dtime) self.object:set_yaw(yaw - right * dtime)
local added_vel = vector.multiply(dir, forward * dtime * me.speed * speedboost) local added_vel = vector.multiply(dir, forward * dtime * me.speed * speedboost)
added_vel.y = added_vel.y + (climb * dtime * me.lift) added_vel.y = added_vel.y + (climb * dtime * me.lift)
v = vector.add(v, added_vel) v = vector.add(v, added_vel)
end end
if self._driver then if self._driver then
local collide_force = me.get_balloon_collide(self) local collide_force = me.get_balloon_collide(self)
@ -335,32 +337,32 @@ function ship.on_step(self, dtime, moveresult)
v = vector.add(v, collide_force) v = vector.add(v, collide_force)
end end
if not self._driver then if not self._driver then
v.y = v.y - dtime v.y = v.y - dtime
end end
if sum_air_currents ~= nil then if minetest.get_modpath("sum_air_currents") then
if self._driver or not is_on_floor then if self._driver or not is_on_floor then
local wind_vel = sum_air_currents.get_wind(p) local wind_vel = sum_air_currents.get_wind(p)
wind_vel = vector.multiply(wind_vel, dtime) wind_vel = vector.multiply(wind_vel, dtime)
v = vector.add(wind_vel, v) v = vector.add(wind_vel, v)
end end
end end
if in_water then if in_water then
v.y = 1 v.y = 1
elseif on_water and not self._driver then elseif on_water and not self._driver then
v.y = 0 v.y = 0
end end
if (not self._driver) and is_on_floor then if (not self._driver) and is_on_floor then
v.x = v.x * 0.8 v.x = v.x * 0.8
v.y = v.y * 0.95 v.y = v.y * 0.95
v.z = v.z * 0.8 v.z = v.z * 0.8
else else
v.x = v.x * (0.98) v.x = v.x * (0.98)
v.y = v.y * (0.98) v.y = v.y * (0.98)
v.z = v.z * (0.98) v.z = v.z * (0.98)
end end
local wind_vel = vector.new(0,0,0) local wind_vel = vector.new(0,0,0)
if minetest.get_modpath("sum_air_currents") ~= nil then if minetest.get_modpath("sum_air_currents") ~= nil then
@ -371,7 +373,7 @@ function ship.on_step(self, dtime, moveresult)
end end
self.object:set_velocity(v) self.object:set_velocity(v)
me.update_sound(self, dtime, forward) me.update_sound(self, dtime, forward)
@ -407,31 +409,32 @@ minetest.register_entity("sum_airship:boat", ship)
minetest.register_craftitem("sum_airship:boat", { minetest.register_craftitem("sum_airship:boat", {
description = "Airship", description = "Airship",
inventory_image = "sum_airship.png", inventory_image = "sum_airship.png",
groups = { vehicle = 1, airship = 1, transport = 1}, groups = { vehicle = 1, airship = 1, transport = 1},
on_place = function(itemstack, placer, pointed_thing) on_place = function(itemstack, placer, pointed_thing)
if pointed_thing.type ~= "node" then if pointed_thing.type ~= "node" then
return itemstack return itemstack
end end
local node = minetest.get_node(pointed_thing.under) local node = minetest.get_node(pointed_thing.under)
if placer and not placer:get_player_control().sneak then if placer and not placer:get_player_control().sneak then
if minetest.registered_nodes[node.name] and minetest.registered_nodes[node.name].on_rightclick then local def = minetest.registered_nodes[node.name]
return minetest.registered_nodes[node.name].on_rightclick(pointed_thing.under, node, placer, itemstack) or itemstack if def and def.on_rightclick then
end return def.on_rightclick(pointed_thing.under, node, placer, itemstack) or itemstack
end end
local pos = vector.offset(pointed_thing.above, 0, 0.5, 0) end
local self = minetest.add_entity(pos, "sum_airship:boat"):get_luaentity() local pos = vector.offset(pointed_thing.above, 0, 0, 0)
if not minetest.is_creative_enabled(placer:get_player_name()) then local self = minetest.add_entity(pos, "sum_airship:boat"):get_luaentity()
itemstack:take_item() if not minetest.is_creative_enabled(placer:get_player_name()) then
end itemstack:take_item()
return itemstack end
end, return itemstack
end,
}) })
-- Support SilverSandstone's subtitles mod: -- Support SilverSandstone's subtitles mod:
if minetest.get_modpath("subtitles") then if minetest.get_modpath("subtitles") then
subtitles.register_description('sum_airship_lip_trill', 'Engine purring'); subtitles.register_description('sum_airship_lip_trill', 'Engine purring');
subtitles.register_description('sum_airship_lip_trill_end', 'Engine sputtering'); subtitles.register_description('sum_airship_lip_trill_end', 'Engine sputtering');
subtitles.register_description('sum_airship_fire', 'Engine stoked'); subtitles.register_description('sum_airship_fire', 'Engine stoked');
end end

View file

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

28
crafting_mcl.lua Normal file
View file

@ -0,0 +1,28 @@
local w = "group:wool"
local b = "group:boat"
local m = "mcl_core:iron_ingot"
local s = "mcl_mobitems:string"
minetest.register_craft({
output = "sum_airship:canvas_roll",
recipe = {
{w, w, w},
{w, w, w},
{w, w, w},
},
})
minetest.register_craft({
output = "sum_airship:hull",
recipe = {
{b, b, b},
{m, m, m},
},
})
minetest.register_craft({
output = "sum_airship:boat",
recipe = {
{"sum_airship:canvas_roll","sum_airship:canvas_roll","sum_airship:canvas_roll",},
{s, m, s,},
{s, "sum_airship:hull", s,},
},
})

BIN
crafting_mtg.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

29
crafting_mtg.lua Normal file
View file

@ -0,0 +1,29 @@
local w = "group:wool"
if not minetest.get_modpath("farming") then w = "default:paper" end
local b = "boats:boat"
local m = "default:steel_ingot"
local s = "farming:string"
minetest.register_craft({
output = "sum_airship:canvas_roll",
recipe = {
{w, w, w},
{w, w, w},
{w, w, w},
},
})
minetest.register_craft({
output = "sum_airship:hull",
recipe = {
{b, b, b},
{m, m, m},
},
})
minetest.register_craft({
output = "sum_airship:boat",
recipe = {
{"sum_airship:canvas_roll","sum_airship:canvas_roll","sum_airship:canvas_roll",},
{s, m, s,},
{s, "sum_airship:hull", s,},
},
})

BIN
crafting_rp.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

23
crafting_rp.lua Normal file
View file

@ -0,0 +1,23 @@
crafting.register_craft({
output = "sum_airship:canvas_roll",
items = {
"group:fuzzy 9"
}
})
crafting.register_craft({
output = "sum_airship:hull",
items = {
"group:boat 3",
"rp_default:ingot_steel 3"
}
})
crafting.register_craft({
output = "sum_airship:boat",
items = {
"sum_airship:canvas_roll 3",
"rp_default:ingot_steel 8",
"rp_default:ingot_steel",
"sum_airship:hull",
}
})

View file

@ -1,3 +1,5 @@
local mod_name = minetest.get_current_modname()
local mod_path = minetest.get_modpath(mod_name)
local S = minetest.get_translator(minetest.get_current_modname()) local S = minetest.get_translator(minetest.get_current_modname())
@ -16,43 +18,16 @@ minetest.register_craftitem("sum_airship:hull", {
groups = { craftitem = 1 }, groups = { craftitem = 1 },
}) })
if minetest.get_modpath("mcl_boats")
local w = "group:wool" and minetest.get_modpath("mcl_wool")
if not minetest.get_modpath("farming") then w = "default:paper" end and minetest.get_modpath("mcl_core")
local b = "boats:boat" and minetest.get_modpath("mcl_mobitems") then
local m = "default:steel_ingot" dofile(mod_path .. "/crafting_mcl.lua")
local s = "farming:string" elseif (minetest.get_modpath("rp_farming")
if minetest.get_modpath("mcl_boats") or minetest.get_modpath("rp_mobs_mobs"))
and minetest.get_modpath("mcl_wool") and minetest.get_modpath("rp_default")
and minetest.get_modpath("mcl_core") and minetest.get_modpath("rp_crafting") then
and minetest.get_modpath("mcl_mobitems") then dofile(mod_path .. "/crafting_rp.lua")
w = "group:wool" elseif minetest.get_modpath("default") then
b = "group:boat" dofile(mod_path .. "/crafting_mtg.lua")
m = "mcl_core:iron_ingot" end
s = "mcl_mobitems:string"
end
minetest.register_craft({
output = "sum_airship:canvas_roll",
recipe = {
{w, w, w},
{w, w, w},
{w, w, w},
},
})
minetest.register_craft({
output = "sum_airship:hull",
recipe = {
{b, b, b},
{m, m, m},
},
})
minetest.register_craft({
output = "sum_airship:boat",
recipe = {
{"sum_airship:canvas_roll","sum_airship:canvas_roll","sum_airship:canvas_roll",},
{s, m, s,},
{s, "sum_airship:hull", s,},
},
})

View file

@ -1,4 +1,5 @@
name = sum_airship name = sum_airship
title = Airship (sum)
author = Sumi author = Sumi
description = airship description = Adds a simple airship to Minetest Game, MineClone (VoxeLibre) and RePixture.
optional_depends = default, mcl_core, mcl_wool, mcl_mobitems, mcl_player optional_depends = default, mcl_core, mcl_wool, mcl_mobitems, mcl_player, rp_crafting, rp_default