Carts: Merge boost_cart as "carts" mod
authorAuke Kok <sofar@foo-projects.org>
Sat, 8 Oct 2016 21:14:10 +0000 (14:14 -0700)
committerparamat <mat.gregory@virginmedia.com>
Mon, 21 Nov 2016 03:15:04 +0000 (03:15 +0000)
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.

35 files changed:
game_api.txt
mods/carts/README.txt [new file with mode: 0644]
mods/carts/depends.txt [new file with mode: 0644]
mods/carts/functions.lua [new file with mode: 0644]
mods/carts/init.lua [new file with mode: 0644]
mods/carts/license.txt [new file with mode: 0644]
mods/carts/models/carts_cart.b3d [new file with mode: 0644]
mods/carts/models/carts_cart.blend [new file with mode: 0644]
mods/carts/rails.lua [new file with mode: 0644]
mods/carts/sounds/carts_cart_moving.1.ogg [new file with mode: 0644]
mods/carts/sounds/carts_cart_moving.2.ogg [new file with mode: 0644]
mods/carts/sounds/carts_cart_moving.3.ogg [new file with mode: 0644]
mods/carts/textures/carts_cart.png [new file with mode: 0644]
mods/carts/textures/carts_cart_front.png [new file with mode: 0644]
mods/carts/textures/carts_cart_side.png [new file with mode: 0644]
mods/carts/textures/carts_cart_top.png [new file with mode: 0644]
mods/carts/textures/carts_rail_crossing.png [new file with mode: 0644]
mods/carts/textures/carts_rail_crossing_brk.png [new file with mode: 0644]
mods/carts/textures/carts_rail_crossing_pwr.png [new file with mode: 0644]
mods/carts/textures/carts_rail_curved.png [new file with mode: 0644]
mods/carts/textures/carts_rail_curved_brk.png [new file with mode: 0644]
mods/carts/textures/carts_rail_curved_pwr.png [new file with mode: 0644]
mods/carts/textures/carts_rail_straight.png [new file with mode: 0644]
mods/carts/textures/carts_rail_straight_brk.png [new file with mode: 0644]
mods/carts/textures/carts_rail_straight_pwr.png [new file with mode: 0644]
mods/carts/textures/carts_rail_t_junction.png [new file with mode: 0644]
mods/carts/textures/carts_rail_t_junction_brk.png [new file with mode: 0644]
mods/carts/textures/carts_rail_t_junction_pwr.png [new file with mode: 0644]
mods/default/aliases.lua
mods/default/crafting.lua
mods/default/nodes.lua
mods/default/textures/default_rail.png [deleted file]
mods/default/textures/default_rail_crossing.png [deleted file]
mods/default/textures/default_rail_curved.png [deleted file]
mods/default/textures/default_rail_t_junction.png [deleted file]

index 80272a60995350aaf9702765700c0c98ee8ec8dd..e85898fdd004900cd697c12cdc25fc88dbd02625 100644 (file)
@@ -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.
diff --git a/mods/carts/README.txt b/mods/carts/README.txt
new file mode 100644 (file)
index 0000000..0cfaea2
--- /dev/null
@@ -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
diff --git a/mods/carts/depends.txt b/mods/carts/depends.txt
new file mode 100644 (file)
index 0000000..4ad96d5
--- /dev/null
@@ -0,0 +1 @@
+default
diff --git a/mods/carts/functions.lua b/mods/carts/functions.lua
new file mode 100644 (file)
index 0000000..f255fef
--- /dev/null
@@ -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
diff --git a/mods/carts/init.lua b/mods/carts/init.lua
new file mode 100644 (file)
index 0000000..7cfee74
--- /dev/null
@@ -0,0 +1,403 @@
+
+carts = {}
+carts.modpath = minetest.get_modpath("carts")
+carts.railparams = {}
+
+-- Maximal speed of the cart in m/s (min = -1)
+carts.speed_max = 7
+-- Set to -1 to disable punching the cart from inside (min = -1)
+carts.punch_speed_max = 5
+
+
+dofile(carts.modpath.."/functions.lua")
+dofile(carts.modpath.."/rails.lua")
+
+-- Support for non-default games
+if not default.player_attached then
+       default.player_attached = {}
+end
+
+local cart_entity = {
+       physical = false, -- otherwise going uphill breaks
+       collisionbox = {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
+       visual = "mesh",
+       mesh = "carts_cart.b3d",
+       visual_size = {x=1, y=1},
+       textures = {"carts_cart.png"},
+
+       driver = nil,
+       punched = false, -- used to re-send velocity and position
+       velocity = {x=0, y=0, z=0}, -- only used on punch
+       old_dir = {x=1, y=0, z=0}, -- random value to start the cart on punch
+       old_pos = nil,
+       old_switch = 0,
+       railtype = nil,
+       attached_items = {}
+}
+
+function cart_entity:on_rightclick(clicker)
+       if not clicker or not clicker:is_player() then
+               return
+       end
+       local player_name = clicker:get_player_name()
+       if self.driver and player_name == self.driver then
+               self.driver = nil
+               carts:manage_attachment(clicker, nil)
+       elseif not self.driver then
+               self.driver = player_name
+               carts:manage_attachment(clicker, self.object)
+       end
+end
+
+function cart_entity:on_activate(staticdata, dtime_s)
+       self.object:set_armor_groups({immortal=1})
+       if string.sub(staticdata, 1, string.len("return")) ~= "return" then
+               return
+       end
+       local data = minetest.deserialize(staticdata)
+       if not data or type(data) ~= "table" then
+               return
+       end
+       self.railtype = data.railtype
+       if data.old_dir then
+               self.old_dir = data.old_dir
+       end
+       if data.old_vel then
+               self.old_vel = data.old_vel
+       end
+end
+
+function cart_entity:get_staticdata()
+       return minetest.serialize({
+               railtype = self.railtype,
+               old_dir = self.old_dir,
+               old_vel = self.old_vel
+       })
+end
+
+function cart_entity:on_punch(puncher, time_from_last_punch, tool_capabilities, direction)
+       local pos = self.object:getpos()
+       if not self.railtype then
+               local node = minetest.get_node(pos).name
+               self.railtype = minetest.get_item_group(node, "connect_to_raillike")
+       end
+
+       if not puncher or not puncher:is_player() then
+               local cart_dir = carts:get_rail_direction(pos, self.old_dir, nil, nil, self.railtype)
+               if vector.equals(cart_dir, {x=0, y=0, z=0}) then
+                       return
+               end
+               self.velocity = vector.multiply(cart_dir, 3)
+               self.punched = true
+               return
+       end
+
+       if puncher:get_player_control().sneak then
+               if self.sound_handle then
+                       minetest.sound_stop(self.sound_handle)
+               end
+               -- Pick up cart: Drop all attachments
+               if self.driver then
+                       if self.old_pos then
+                               self.object:setpos(self.old_pos)
+                       end
+                       local player = minetest.get_player_by_name(self.driver)
+                       carts:manage_attachment(player, nil)
+               end
+               for _,obj_ in ipairs(self.attached_items) do
+                       if obj_ then
+                               obj_:set_detach()
+                       end
+               end
+
+               local leftover = puncher:get_inventory():add_item("main", "carts:cart")
+               if not leftover:is_empty() then
+                       minetest.add_item(self.object:getpos(), leftover)
+               end
+               self.object:remove()
+               return
+       end
+
+       local vel = self.object:getvelocity()
+       if puncher:get_player_name() == self.driver then
+               if math.abs(vel.x + vel.z) > carts.punch_speed_max then
+                       return
+               end
+       end
+
+       local punch_dir = carts:velocity_to_dir(puncher:get_look_dir())
+       punch_dir.y = 0
+       local cart_dir = carts:get_rail_direction(pos, punch_dir, nil, nil, self.railtype)
+       if vector.equals(cart_dir, {x=0, y=0, z=0}) then
+               return
+       end
+
+       local punch_interval = 1
+       if tool_capabilities and tool_capabilities.full_punch_interval then
+               punch_interval = tool_capabilities.full_punch_interval
+       end
+       time_from_last_punch = math.min(time_from_last_punch or punch_interval, punch_interval)
+       local f = 2 * (time_from_last_punch / punch_interval)
+
+       self.velocity = vector.multiply(cart_dir, f)
+       self.old_dir = cart_dir
+       self.punched = true
+end
+
+local function rail_on_step_event(handler, obj, dtime)
+       if handler then
+               handler(obj, dtime)
+       end
+end
+
+-- sound refresh interval = 1.0sec
+local function rail_sound(self, dtime)
+       if not self.sound_ttl then
+               self.sound_ttl = 1.0
+               return
+       elseif self.sound_ttl > 0 then
+               self.sound_ttl = self.sound_ttl - dtime
+               return
+       end
+       self.sound_ttl = 1.0
+       if self.sound_handle then
+               local handle = self.sound_handle
+               self.sound_handle = nil
+               minetest.after(0.2, minetest.sound_stop, handle)
+       end
+       local vel = self.object:getvelocity()
+       local speed = vector.length(vel)
+       if speed > 0 then
+               self.sound_handle = minetest.sound_play(
+                       "carts_cart_moving", {
+                       object = self.object,
+                       gain = (speed / carts.speed_max) / 2,
+                       loop = true,
+               })
+       end
+end
+
+local function rail_on_step(self, dtime)
+       local pos = self.object:getpos()
+       local node = minetest.get_node(pos)
+       local railparams = carts.railparams[node.name] or {}
+
+       local vel = self.object:getvelocity()
+       local update = {}
+       if self.punched then
+               vel = vector.add(vel, self.velocity)
+               self.object:setvelocity(vel)
+               self.old_dir.y = 0
+       elseif vector.equals(vel, {x=0, y=0, z=0}) then
+               return
+       end
+
+       -- stop cart if velocity vector flips
+       if self.old_vel and (((self.old_vel.x * vel.x) < 0) or
+                       ((self.old_vel.z * vel.z) < 0)) and
+                       (self.old_vel.y == 0) then
+               self.old_dir = {x = 0, y = 0, z = 0}
+               self.old_vel = {x = 0, y = 0, z = 0}
+               self.velocity = {x = 0, y = 0, z = 0}
+               self.old_pos = pos
+               self.object:setvelocity(vector.new())
+               self.object:setacceleration(vector.new())
+               rail_on_step_event(railparams.on_step, self, dtime)
+               return
+       end
+       self.old_vel = vector.new(vel)
+
+       if self.old_pos and not self.punched then
+               local flo_pos = vector.round(pos)
+               local flo_old = vector.round(self.old_pos)
+               if vector.equals(flo_pos, flo_old) then
+                       -- Do not check one node multiple times
+                       rail_on_step_event(railparams.on_step, self, dtime)
+                       return
+               end
+       end
+
+       local ctrl, player
+
+       -- Get player controls
+       if self.driver then
+               player = minetest.get_player_by_name(self.driver)
+               if player then
+                       ctrl = player:get_player_control()
+               end
+       end
+
+       if self.old_pos then
+               -- Detection for "skipping" nodes
+               local expected_pos = vector.add(self.old_pos, self.old_dir)
+               local found_path = carts:pathfinder(
+                       pos, expected_pos, self.old_dir, ctrl, self.old_switch, self.railtype
+               )
+
+               if not found_path then
+                       -- No rail found: reset back to the expected position
+                       pos = vector.new(self.old_pos)
+                       update.pos = true
+               end
+       end
+
+       local cart_dir = carts:velocity_to_dir(vel)
+
+       -- dir:         New moving direction of the cart
+       -- switch_keys: Currently pressed L/R key, used to ignore the key on the next rail node
+       local dir, switch_keys = carts:get_rail_direction(
+               pos, cart_dir, ctrl, self.old_switch, self.railtype
+       )
+
+       local new_acc = {x=0, y=0, z=0}
+       if vector.equals(dir, {x=0, y=0, z=0}) then
+               vel = {x=0, y=0, z=0}
+               pos = vector.round(pos)
+               update.pos = true
+               update.vel = true
+       else
+               -- If the direction changed
+               if dir.x ~= 0 and self.old_dir.z ~= 0 then
+                       vel.x = dir.x * math.abs(vel.z)
+                       vel.z = 0
+                       pos.z = math.floor(pos.z + 0.5)
+                       update.pos = true
+               end
+               if dir.z ~= 0 and self.old_dir.x ~= 0 then
+                       vel.z = dir.z * math.abs(vel.x)
+                       vel.x = 0
+                       pos.x = math.floor(pos.x + 0.5)
+                       update.pos = true
+               end
+               -- Up, down?
+               if dir.y ~= self.old_dir.y then
+                       vel.y = dir.y * math.abs(vel.x + vel.z)
+                       pos = vector.round(pos)
+                       update.pos = true
+               end
+
+               -- Slow down or speed up..
+               local acc = dir.y * -4.0
+
+               -- no need to check for railparams == nil since we always make it exist.
+               local speed_mod = railparams.acceleration
+               if speed_mod and speed_mod ~= 0 then
+                       -- Try to make it similar to the original carts mod
+                       acc = acc + speed_mod
+               else
+                       -- Handbrake
+                       if ctrl and ctrl.down then
+                               acc = acc - 1.6
+                       else
+                               acc = acc - 0.4
+                       end
+               end
+
+               new_acc = vector.multiply(dir, acc)
+       end
+
+       -- Limits
+       local max_vel = carts.speed_max
+       for _,v in ipairs({"x","y","z"}) do
+               if math.abs(vel[v]) > max_vel then
+                       vel[v] = carts:get_sign(vel[v]) * max_vel
+                       new_acc[v] = 0
+                       update.vel = true
+               end
+       end
+
+       self.object:setacceleration(new_acc)
+       self.old_pos = vector.new(pos)
+       if not vector.equals(dir, {x=0, y=0, z=0}) then
+               self.old_dir = vector.new(dir)
+       end
+       self.old_switch = switch_keys
+
+       if self.punched then
+               -- Collect dropped items
+               for _,obj_ in ipairs(minetest.get_objects_inside_radius(pos, 1)) do
+                       if not obj_:is_player() and
+                                       obj_:get_luaentity() and
+                                       not obj_:get_luaentity().physical_state and
+                                       obj_:get_luaentity().name == "__builtin:item" then
+
+                               obj_:set_attach(self.object, "", {x=0, y=0, z=0}, {x=0, y=0, z=0})
+                               self.attached_items[#self.attached_items + 1] = obj_
+                       end
+               end
+               self.punched = false
+               update.vel = true
+       end
+
+       if not (update.vel or update.pos) then
+               rail_on_step_event(railparams.on_step, self, dtime)
+               return
+       end
+
+       local yaw = 0
+       if self.old_dir.x < 0 then
+               yaw = 0.5
+       elseif self.old_dir.x > 0 then
+               yaw = 1.5
+       elseif self.old_dir.z < 0 then
+               yaw = 1
+       end
+       self.object:setyaw(yaw * math.pi)
+
+       local anim = {x=0, y=0}
+       if dir.y == -1 then
+               anim = {x=1, y=1}
+       elseif dir.y == 1 then
+               anim = {x=2, y=2}
+       end
+       self.object:set_animation(anim, 1, 0)
+
+       self.object:setvelocity(vel)
+       if update.pos then
+               self.object:setpos(pos)
+       end
+
+       -- call event handler
+       rail_on_step_event(railparams.on_step, self, dtime)
+end
+
+function cart_entity:on_step(dtime)
+       rail_on_step(self, dtime)
+       rail_sound(self, dtime)
+end
+
+minetest.register_entity("carts:cart", cart_entity)
+
+minetest.register_craftitem("carts:cart", {
+       description = "Cart (Sneak+Click to pick up)",
+       inventory_image = minetest.inventorycube("carts_cart_top.png", "carts_cart_side.png", "carts_cart_side.png"),
+       wield_image = "carts_cart_side.png",
+       on_place = function(itemstack, placer, pointed_thing)
+               if not pointed_thing.type == "node" then
+                       return
+               end
+               if carts:is_rail(pointed_thing.under) then
+                       minetest.add_entity(pointed_thing.under, "carts:cart")
+               elseif carts:is_rail(pointed_thing.above) then
+                       minetest.add_entity(pointed_thing.above, "carts:cart")
+               else
+                       return
+               end
+
+               minetest.sound_play({name = "default_place_node_metal", gain = 0.5},
+                       {pos = pointed_thing.above})
+
+               if not minetest.setting_getbool("creative_mode") then
+                       itemstack:take_item()
+               end
+               return itemstack
+       end,
+})
+
+minetest.register_craft({
+       output = "carts:cart",
+       recipe = {
+               {"default:steel_ingot", "", "default:steel_ingot"},
+               {"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"},
+       },
+})
diff --git a/mods/carts/license.txt b/mods/carts/license.txt
new file mode 100644 (file)
index 0000000..6c5beb4
--- /dev/null
@@ -0,0 +1,54 @@
+
+License of source code
+----------------------
+
+The MIT License (MIT)
+Copyright (C) 2012-2016 PilzAdam
+Copyright (C) 2014-2016 SmallJoker
+Copyright (C) 2012-2016 Various Minetest developers and contributors
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation the
+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+For more details:
+https://opensource.org/licenses/MIT
+
+
+Licenses of media
+-----------------
+
+CC-0, see: https://creativecommons.org/share-your-work/public-domain/cc0/, except
+if other license is mentioned.
+
+
+Authors
+---------
+Originally from PixelBOX (Gambit):
+       carts_cart_side.png
+       carts_cart_top.png
+       carts_cart_front.png*
+       carts_cart.png*
+
+sofar + stujones11:
+       carts_cart.b3d and carts_cart.blend
+
+hexafraction, modified by sofar
+       carts_rail_*.png
+
+http://www.freesound.org/people/YleArkisto/sounds/253159/ - YleArkisto - CC-BY-3.0
+       carts_cart_moving.*.ogg
diff --git a/mods/carts/models/carts_cart.b3d b/mods/carts/models/carts_cart.b3d
new file mode 100644 (file)
index 0000000..4e7eba3
Binary files /dev/null and b/mods/carts/models/carts_cart.b3d differ
diff --git a/mods/carts/models/carts_cart.blend b/mods/carts/models/carts_cart.blend
new file mode 100644 (file)
index 0000000..7d2515e
Binary files /dev/null and b/mods/carts/models/carts_cart.blend differ
diff --git a/mods/carts/rails.lua b/mods/carts/rails.lua
new file mode 100644 (file)
index 0000000..f929e84
--- /dev/null
@@ -0,0 +1,58 @@
+carts:register_rail("carts:rail", {
+       description = "Rail",
+       tiles = {
+               "carts_rail_straight.png", "carts_rail_curved.png",
+               "carts_rail_t_junction.png", "carts_rail_crossing.png"
+       },
+       inventory_image = "carts_rail_straight.png",
+       wield_image = "carts_rail_straight.png",
+       groups = carts:get_rail_groups(),
+}, {})
+
+minetest.register_craft({
+       output = "carts:rail 16",
+       recipe = {
+               {"default:steel_ingot", "", "default:steel_ingot"},
+               {"default:steel_ingot", "group:stick", "default:steel_ingot"},
+               {"default:steel_ingot", "", "default:steel_ingot"},
+       }
+})
+
+minetest.register_alias("default:rail", "carts:rail")
+
+carts:register_rail("carts:powerrail", {
+       description = "Powered rail",
+       tiles = {
+               "carts_rail_straight_pwr.png", "carts_rail_curved_pwr.png",
+               "carts_rail_t_junction_pwr.png", "carts_rail_crossing_pwr.png"
+       },
+       groups = carts:get_rail_groups(),
+}, {acceleration = 4})
+
+minetest.register_craft({
+       output = "carts:powerrail 8",
+       recipe = {
+               {"default:steel_ingot", "default:mese_crystal_fragment", "default:steel_ingot"},
+               {"default:steel_ingot", "group:stick", "default:steel_ingot"},
+               {"default:steel_ingot", "default:mese_crystal_fragment", "default:steel_ingot"},
+       }
+})
+
+carts:register_rail("carts:brakerail", {
+       description = "Brake rail",
+       tiles = {
+               "carts_rail_straight_brk.png", "carts_rail_curved_brk.png",
+               "carts_rail_t_junction_brk.png", "carts_rail_crossing_brk.png"
+       },
+       groups = carts:get_rail_groups(),
+}, {acceleration = -3})
+
+
+minetest.register_craft({
+       output = "carts:brakerail 8",
+       recipe = {
+               {"default:steel_ingot", "default:coal_lump", "default:steel_ingot"},
+               {"default:steel_ingot", "group:stick", "default:steel_ingot"},
+               {"default:steel_ingot", "default:coal_lump", "default:steel_ingot"},
+       }
+})
diff --git a/mods/carts/sounds/carts_cart_moving.1.ogg b/mods/carts/sounds/carts_cart_moving.1.ogg
new file mode 100644 (file)
index 0000000..869e765
Binary files /dev/null and b/mods/carts/sounds/carts_cart_moving.1.ogg differ
diff --git a/mods/carts/sounds/carts_cart_moving.2.ogg b/mods/carts/sounds/carts_cart_moving.2.ogg
new file mode 100644 (file)
index 0000000..b4cc508
Binary files /dev/null and b/mods/carts/sounds/carts_cart_moving.2.ogg differ
diff --git a/mods/carts/sounds/carts_cart_moving.3.ogg b/mods/carts/sounds/carts_cart_moving.3.ogg
new file mode 100644 (file)
index 0000000..e19a782
Binary files /dev/null and b/mods/carts/sounds/carts_cart_moving.3.ogg differ
diff --git a/mods/carts/textures/carts_cart.png b/mods/carts/textures/carts_cart.png
new file mode 100644 (file)
index 0000000..965347c
Binary files /dev/null and b/mods/carts/textures/carts_cart.png differ
diff --git a/mods/carts/textures/carts_cart_front.png b/mods/carts/textures/carts_cart_front.png
new file mode 100644 (file)
index 0000000..b85696f
Binary files /dev/null and b/mods/carts/textures/carts_cart_front.png differ
diff --git a/mods/carts/textures/carts_cart_side.png b/mods/carts/textures/carts_cart_side.png
new file mode 100644 (file)
index 0000000..4362d6b
Binary files /dev/null and b/mods/carts/textures/carts_cart_side.png differ
diff --git a/mods/carts/textures/carts_cart_top.png b/mods/carts/textures/carts_cart_top.png
new file mode 100644 (file)
index 0000000..5f775ff
Binary files /dev/null and b/mods/carts/textures/carts_cart_top.png differ
diff --git a/mods/carts/textures/carts_rail_crossing.png b/mods/carts/textures/carts_rail_crossing.png
new file mode 100644 (file)
index 0000000..e10f3b1
Binary files /dev/null and b/mods/carts/textures/carts_rail_crossing.png differ
diff --git a/mods/carts/textures/carts_rail_crossing_brk.png b/mods/carts/textures/carts_rail_crossing_brk.png
new file mode 100644 (file)
index 0000000..0bf455e
Binary files /dev/null and b/mods/carts/textures/carts_rail_crossing_brk.png differ
diff --git a/mods/carts/textures/carts_rail_crossing_pwr.png b/mods/carts/textures/carts_rail_crossing_pwr.png
new file mode 100644 (file)
index 0000000..d763d50
Binary files /dev/null and b/mods/carts/textures/carts_rail_crossing_pwr.png differ
diff --git a/mods/carts/textures/carts_rail_curved.png b/mods/carts/textures/carts_rail_curved.png
new file mode 100644 (file)
index 0000000..b320f0d
Binary files /dev/null and b/mods/carts/textures/carts_rail_curved.png differ
diff --git a/mods/carts/textures/carts_rail_curved_brk.png b/mods/carts/textures/carts_rail_curved_brk.png
new file mode 100644 (file)
index 0000000..ca40723
Binary files /dev/null and b/mods/carts/textures/carts_rail_curved_brk.png differ
diff --git a/mods/carts/textures/carts_rail_curved_pwr.png b/mods/carts/textures/carts_rail_curved_pwr.png
new file mode 100644 (file)
index 0000000..781bbd0
Binary files /dev/null and b/mods/carts/textures/carts_rail_curved_pwr.png differ
diff --git a/mods/carts/textures/carts_rail_straight.png b/mods/carts/textures/carts_rail_straight.png
new file mode 100644 (file)
index 0000000..30dcafe
Binary files /dev/null and b/mods/carts/textures/carts_rail_straight.png differ
diff --git a/mods/carts/textures/carts_rail_straight_brk.png b/mods/carts/textures/carts_rail_straight_brk.png
new file mode 100644 (file)
index 0000000..0c69052
Binary files /dev/null and b/mods/carts/textures/carts_rail_straight_brk.png differ
diff --git a/mods/carts/textures/carts_rail_straight_pwr.png b/mods/carts/textures/carts_rail_straight_pwr.png
new file mode 100644 (file)
index 0000000..e067ff1
Binary files /dev/null and b/mods/carts/textures/carts_rail_straight_pwr.png differ
diff --git a/mods/carts/textures/carts_rail_t_junction.png b/mods/carts/textures/carts_rail_t_junction.png
new file mode 100644 (file)
index 0000000..8b1b946
Binary files /dev/null and b/mods/carts/textures/carts_rail_t_junction.png differ
diff --git a/mods/carts/textures/carts_rail_t_junction_brk.png b/mods/carts/textures/carts_rail_t_junction_brk.png
new file mode 100644 (file)
index 0000000..6b4f6fa
Binary files /dev/null and b/mods/carts/textures/carts_rail_t_junction_brk.png differ
diff --git a/mods/carts/textures/carts_rail_t_junction_pwr.png b/mods/carts/textures/carts_rail_t_junction_pwr.png
new file mode 100644 (file)
index 0000000..dd0eede
Binary files /dev/null and b/mods/carts/textures/carts_rail_t_junction_pwr.png differ
index 1259ac0e97ce85446d0072f38d0940a42816fc66..6db3fc8d47c48918ed16bf9b6cce3aa696a35556 100644 (file)
@@ -22,7 +22,7 @@ minetest.register_alias("papyrus", "default:papyrus")
 minetest.register_alias("bookshelf", "default:bookshelf")
 minetest.register_alias("glass", "default:glass")
 minetest.register_alias("wooden_fence", "default:fence_wood")
-minetest.register_alias("rail", "default:rail")
+minetest.register_alias("rail", "carts:rail")
 minetest.register_alias("ladder", "default:ladder_wood")
 minetest.register_alias("wood", "default:wood")
 minetest.register_alias("mese", "default:mese")
index fe9862a0c4703bd59c63c7d3fe4b92d2d2d4c060..23f233fb0c8db0f7cb92781233ef93f477094489 100644 (file)
@@ -352,15 +352,6 @@ minetest.register_craft({
        }
 })
 
-minetest.register_craft({
-       output = 'default:rail 24',
-       recipe = {
-               {'default:steel_ingot', '', 'default:steel_ingot'},
-               {'default:steel_ingot', 'group:stick', 'default:steel_ingot'},
-               {'default:steel_ingot', '', 'default:steel_ingot'},
-       }
-})
-
 minetest.register_craft({
        output = 'default:chest',
        recipe = {
index dba84da128ad4a2332a739b75633814a252cc63a..e514a48fc11f1a9b2783f6a2527554e706801b77 100644 (file)
@@ -181,8 +181,6 @@ default:fence_aspen_wood
 default:glass
 default:obsidian_glass
 
-default:rail
-
 default:brick
 
 default:meselamp
@@ -2058,27 +2056,6 @@ minetest.register_node("default:obsidian_glass", {
 })
 
 
-minetest.register_node("default:rail", {
-       description = "Rail",
-       drawtype = "raillike",
-       tiles = {"default_rail.png", "default_rail_curved.png",
-               "default_rail_t_junction.png", "default_rail_crossing.png"},
-       inventory_image = "default_rail.png",
-       wield_image = "default_rail.png",
-       paramtype = "light",
-       sunlight_propagates = true,
-       walkable = false,
-       is_ground_content = false,
-       selection_box = {
-               type = "fixed",
-                -- but how to specify the dimensions for curved and sideways rails?
-                fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2},
-       },
-       groups = {dig_immediate = 2, attached_node = 1,
-               connect_to_raillike = minetest.raillike_group("rail")},
-})
-
-
 minetest.register_node("default:brick", {
        description = "Brick Block",
        paramtype2 = "facedir",
diff --git a/mods/default/textures/default_rail.png b/mods/default/textures/default_rail.png
deleted file mode 100644 (file)
index 26fed02..0000000
Binary files a/mods/default/textures/default_rail.png and /dev/null differ
diff --git a/mods/default/textures/default_rail_crossing.png b/mods/default/textures/default_rail_crossing.png
deleted file mode 100644 (file)
index ba66e01..0000000
Binary files a/mods/default/textures/default_rail_crossing.png and /dev/null differ
diff --git a/mods/default/textures/default_rail_curved.png b/mods/default/textures/default_rail_curved.png
deleted file mode 100644 (file)
index 9084ac2..0000000
Binary files a/mods/default/textures/default_rail_curved.png and /dev/null differ
diff --git a/mods/default/textures/default_rail_t_junction.png b/mods/default/textures/default_rail_t_junction.png
deleted file mode 100644 (file)
index 486c416..0000000
Binary files a/mods/default/textures/default_rail_t_junction.png and /dev/null differ