Skip to content

Commit

Permalink
Carts: Merge boost_cart as "carts" mod
Browse files Browse the repository at this point in the history
This is all the working code from SmallJoker's boost_cart, poored into
a more suitable form for minetest_game.

- Mesecons and moreores stuff was removed entirely.
- Textures were all renamed and moved out of default/
- Updated license, readme.txt, attribution
- Changed code license to MIT, left artwork at CC0
- removed default:rail and made aliases for it
- :carts:rail is now carts:rail.
- localized entity def
- removed copper rail entirely
- startstop rail was removed, as well as detector rail
- remodeled to b3d using stujones11 excellent blend model, but sizes
  of cart adjusted to make pixel sizes consistent (0.625) everywhere.
- slightly more complex texture map for the cart (front/side visibly
  different)
- rail parameters are passed as a separate def table, and stored in
  a private list. This avoids having to call `get_meta` on every
  node. In return, we need the node name, though.
- adds metal sounds (based on default metal sound function) and
  cart moving sound.
- reduced cart speeds to max 7, 5 by pushing.
- Added on_step() rail event handler, gets called when a cart is on
  a rail.
- Added various rebased updates from upstream (thanks Krock)
- Included a fix that removes the 'reverse jiggle' when stopping.
- Included reworked textures by sofar.

The mod namespace is still public, but I'm NOT declaring it an API. I'd
rather see it localized instead, for now. Any public interface in this
code is *experimental* at best, and should be considered non-stable and
unsupported for now.
  • Loading branch information
sofar authored and paramat committed Nov 21, 2016
1 parent 75caa91 commit 1e691c4
Show file tree
Hide file tree
Showing 35 changed files with 780 additions and 33 deletions.
22 changes: 22 additions & 0 deletions game_api.txt
Expand Up @@ -650,3 +650,25 @@ Trees

* `default.grow_new_snowy_pine_tree(pos)`
* Grows a new design snowy pine tree at pos

Carts
-----

carts.register_rail(
"mycarts:myrail", -- Rail name
nodedef, -- standard nodedef
railparams -- rail parameter struct (optional)
)

railparams = {
on_step(obj, dtime), -- Event handler called when
-- cart is on rail
acceleration, -- integer acceleration factor (negative
-- values to brake)
}

The event handler is called after all default calculations
are made, so the custom on_step handler can override things
like speed, acceleration, player attachment. The handler will
likely be called many times per second, so the function needs
to make sure that the event is handled properly.
20 changes: 20 additions & 0 deletions mods/carts/README.txt
@@ -0,0 +1,20 @@
Carts (formerly boost_cart)
==========================

Cleaned up for merge based almost entirely on SmallJoker's boost_cart
mod (github.com/smalljoker/boost_cart).

That in turn was based on (and fully compatible with) the mod "carts"
by PilzAdam

The model was redone, but based on github.com/stujones11/railcart, CC-0

Cart Textures are based on original work from PixelBOX (WTFPL).


Features
----------
- A fast cart for your railway or roller coaster (up to 7 m/s!)
- Boost and brake rails
- Rail junction switching with the 'right-left' walking keys
- Handbrake with the 'back' key
1 change: 1 addition & 0 deletions mods/carts/depends.txt
@@ -0,0 +1 @@
default
221 changes: 221 additions & 0 deletions mods/carts/functions.lua
@@ -0,0 +1,221 @@
function carts:get_sign(z)
if z == 0 then
return 0
else
return z / math.abs(z)
end
end

function carts:manage_attachment(player, obj)
if not player then
return
end
local status = obj ~= nil
local player_name = player:get_player_name()
if default.player_attached[player_name] == status then
return
end
default.player_attached[player_name] = status

if status then
player:set_attach(obj, "", {x=0, y=6, z=0}, {x=0, y=0, z=0})
player:set_eye_offset({x=0, y=-4, z=0},{x=0, y=-4, z=0})
else
player:set_detach()
player:set_eye_offset({x=0, y=0, z=0},{x=0, y=0, z=0})
end
end

function carts:velocity_to_dir(v)
if math.abs(v.x) > math.abs(v.z) then
return {x=carts:get_sign(v.x), y=carts:get_sign(v.y), z=0}
else
return {x=0, y=carts:get_sign(v.y), z=carts:get_sign(v.z)}
end
end

function carts:is_rail(pos, railtype)
local node = minetest.get_node(pos).name
if node == "ignore" then
local vm = minetest.get_voxel_manip()
local emin, emax = vm:read_from_map(pos, pos)
local area = VoxelArea:new{
MinEdge = emin,
MaxEdge = emax,
}
local data = vm:get_data()
local vi = area:indexp(pos)
node = minetest.get_name_from_content_id(data[vi])
end
if minetest.get_item_group(node, "rail") == 0 then
return false
end
if not railtype then
return true
end
return minetest.get_item_group(node, "connect_to_raillike") == railtype
end

function carts:check_front_up_down(pos, dir_, check_up, railtype)
local dir = vector.new(dir_)
local cur

-- Front
dir.y = 0
cur = vector.add(pos, dir)
if carts:is_rail(cur, railtype) then
return dir
end
-- Up
if check_up then
dir.y = 1
cur = vector.add(pos, dir)
if carts:is_rail(cur, railtype) then
return dir
end
end
-- Down
dir.y = -1
cur = vector.add(pos, dir)
if carts:is_rail(cur, railtype) then
return dir
end
return nil
end

function carts:get_rail_direction(pos_, dir, ctrl, old_switch, railtype)
local pos = vector.round(pos_)
local cur
local left_check, right_check = true, true

-- Check left and right
local left = {x=0, y=0, z=0}
local right = {x=0, y=0, z=0}
if dir.z ~= 0 and dir.x == 0 then
left.x = -dir.z
right.x = dir.z
elseif dir.x ~= 0 and dir.z == 0 then
left.z = dir.x
right.z = -dir.x
end

if ctrl then
if old_switch == 1 then
left_check = false
elseif old_switch == 2 then
right_check = false
end
if ctrl.left and left_check then
cur = carts:check_front_up_down(pos, left, false, railtype)
if cur then
return cur, 1
end
left_check = false
end
if ctrl.right and right_check then
cur = carts:check_front_up_down(pos, right, false, railtype)
if cur then
return cur, 2
end
right_check = true
end
end

-- Normal
cur = carts:check_front_up_down(pos, dir, true, railtype)
if cur then
return cur
end

-- Left, if not already checked
if left_check then
cur = carts:check_front_up_down(pos, left, false, railtype)
if cur then
return cur
end
end

-- Right, if not already checked
if right_check then
cur = carts:check_front_up_down(pos, right, false, railtype)
if cur then
return cur
end
end

-- Backwards
if not old_switch then
cur = carts:check_front_up_down(pos, {
x = -dir.x,
y = dir.y,
z = -dir.z
}, true, railtype)
if cur then
return cur
end
end

return {x=0, y=0, z=0}
end

function carts:pathfinder(pos_, expected_pos, old_dir, ctrl, pf_switch, railtype)
local pos = vector.round(pos_)
local pf_pos = vector.round(expected_pos)
local pf_dir = vector.new(old_dir)

for i = 1, 3 do
if vector.equals(pf_pos, pos) then
-- Success! Cart moved on correctly
return true
end

pf_dir, pf_switch = carts:get_rail_direction(pf_pos, pf_dir, ctrl, pf_switch, railtype)
if vector.equals(pf_dir, {x=0, y=0, z=0}) then
-- No way forwards
return false
end

pf_pos = vector.add(pf_pos, pf_dir)
end
-- Cart not found
return false
end

function carts:register_rail(name, def, railparams)
local def_default = {
drawtype = "raillike",
paramtype = "light",
sunlight_propagates = true,
is_ground_content = true,
walkable = false,
selection_box = {
type = "fixed",
fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2},
},
sounds = default.node_sound_metal_defaults()
}
for k, v in pairs(def_default) do
def[k] = v
end
if not def.inventory_image then
def.wield_image = def.tiles[1]
def.inventory_image = def.tiles[1]
end

if railparams then
carts.railparams[name] = table.copy(railparams)
end

minetest.register_node(name, def)
end

function carts:get_rail_groups(additional_groups)
-- Get the default rail groups and add more when a table is given
local groups = {dig_immediate = 2, attached_node = 1, rail = 1, connect_to_raillike = 1}
if type(additional_groups) == "table" then
for k, v in pairs(additional_groups) do
groups[k] = v
end
end
return groups
end

0 comments on commit 1e691c4

Please sign in to comment.