diff options
39 files changed, 1411 insertions, 0 deletions
| diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a57dbc9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +## Generic ignorable patterns and files +*~ +.*.swp +*bak* +tags +*.vim + diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..511244e --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,18 @@ +Minetest Modpack - Railnet [minetest-railnet] +============================================= + +**License Source Code:** LGPL v2.1 + +**License of media** (textures, sounds and models): CC-0 + +Authors of media files: +----------------------- + +kddekadenz: +  cart_bottom.png +  cart_side.png +  cart_top.png + +rarkenin: +  cart_rail_*.png + diff --git a/README.md b/README.md new file mode 100644 index 0000000..94229ab --- /dev/null +++ b/README.md @@ -0,0 +1,23 @@ +Modpack - Railnet [0.1.0] +========================= + +**Minetest version:** 0.4.13 + +This modpack is still very much a work-in-progress and is not recommended for +existing worlds or public servers at this stage. + +[mod] Railtrack [railtrack] +--------------------------- + +**Depends:** default + +Proof of concept rail networking system which enables rail-carts to travel +through unloaded map chunks. + +[mod] Railcart [railcart] +------------------------- + +**Depends:** railtrack + +Proof of concept ground up re-write based on the original carts mod by PilzAdam. + diff --git a/modpack.txt b/modpack.txt new file mode 100644 index 0000000..33d91f5 --- /dev/null +++ b/modpack.txt @@ -0,0 +1 @@ +The presence of this file indicates that the current folder is a modpack.
\ No newline at end of file diff --git a/railcart/LICENSE.txt b/railcart/LICENSE.txt new file mode 100644 index 0000000..5f3db02 --- /dev/null +++ b/railcart/LICENSE.txt @@ -0,0 +1,19 @@ +Minetest Mod - Railcart [railcart] +================================== + +License Source Code: LGPL v2.1 + +License of media (textures, sounds and models): CC-0 + +Authors of media files: +----------------------- + +kddekadenz: +  cart_bottom.png +  cart_side.png +  cart_top.png + +Zeg9: +  cart.x +  cart.png + diff --git a/railcart/README.txt b/railcart/README.txt new file mode 100644 index 0000000..dd4d70e --- /dev/null +++ b/railcart/README.txt @@ -0,0 +1,30 @@ +Minetest Mod - Railcart [railcart] +================================== + +Minetest version: 0.4.13 + +Depends: railtrack + +Proof of concept ground up re-write of the carts mod. Currently uses media files +borrowed from the original carts mod by PilzAdam. + +Please note, this mod makes heavy use of metadata so that carts are able to +travel through unloaded map chunks, therefor a 'carts' privilege is required +to place or pick up carts in multiplayer mode. + +Crafting +-------- + +S = Steel Ingot [default:steel_ingot] +W = Wood [group:wood] + +Railcart: [railcart:cart] + ++---+---+---+ +| S |   | S | ++---+---+---+ +| S |   | S | ++---+---+---+ +| W | S | W | ++---+---+---+ + diff --git a/railcart/depends.txt b/railcart/depends.txt new file mode 100644 index 0000000..e602f16 --- /dev/null +++ b/railcart/depends.txt @@ -0,0 +1 @@ +railtrack diff --git a/railcart/init.lua b/railcart/init.lua new file mode 100644 index 0000000..df9d4f1 --- /dev/null +++ b/railcart/init.lua @@ -0,0 +1,154 @@ +local modpath = minetest.get_modpath(minetest.get_current_modname()) + +dofile(modpath.."/railcart.lua") + +local worldpath = minetest.get_worldpath() +local input = io.open(worldpath.."/railcart.txt", "r") +if input then +	local data = input:read('*all') +	if data then +		local carts = minetest.deserialize(data) or {} +		for id, ref in pairs(carts) do +			railcart.allcarts[id] = railcart.cart:new(ref) +		end +	end +	input = nil +end + +local function is_valid_player(object) +	if object then +		return object:is_player() +	end +end + +minetest.register_globalstep(function(dtime) +	for _, cart in pairs(railcart.allcarts) do +		cart:on_step(dtime) +	end +	railcart.timer = railcart.timer + dtime +	if railcart.timer > RAILCART_OBJECT_SAVE_TIME then +		railcart:save() +		railcart.timer = 0 +	end +end) + +minetest.register_privilege("carts", "Player can pick-up and place carts.") + +minetest.register_entity("railcart:cart_entity", { +	physical = false, +	collisionbox = {-0.5,-0.5,-0.5, 0.5,0.5,0.5}, +	visual = "mesh", +	mesh = "railcart.x", +	visual_size = {x=1, y=1}, +	textures = {"cart.png"}, +	cart = nil, +	driver = nil, +	timer = 0, +	on_activate = function(self, staticdata, dtime_s) +		self.object:set_armor_groups({immortal=1}) +		if staticdata == "expired" then +			self.object:remove() +		end +	end, +	on_punch = function(self, puncher, _, _, direction) +		if not is_valid_player(puncher) then +			return +		end	 +		if puncher:get_player_control().sneak then +			if self.cart then +				if self.cart.id then +					railcart.allcarts[self.cart.id] = nil +				end +			end +			self.object:remove() +			local inv = puncher:get_inventory() +			if minetest.setting_getbool("creative_mode") then +				if not inv:contains_item("main", "railcart:cart") then +					inv:add_item("main", "railcart:cart") +				end +			else +				inv:add_item("main", "railcart:cart") +			end +			return +		end +		if self.cart and direction then +			local pos = vector.round(self.object:getpos()) +			local dir = vector.round(vector.normalize(direction)) +			self.timer = 0 +			self.cart.target = nil +			self.cart.prev = pos +			self.cart.vel = vector.multiply(dir, 4) +			self.cart.accel = railtrack:get_acceleration(pos) +			self.object:setvelocity(self.cart.vel) +		end +	end, +	on_rightclick = function(self, clicker) +		if not is_valid_player(clicker) then +			return +		end +		if self.driver and clicker == self.driver then +			self.driver = nil +			clicker:set_detach() +		elseif not self.driver then +			self.driver = clicker +			clicker:set_attach(self.object, "", {x=0,y=5,z=0}, {x=0,y=0,z=0}) +		end +	end, +	on_step = function(self, dtime) +		local cart = self.cart +		local object = self.object +		if not cart or not object then +			return +		end +		self.timer = self.timer - dtime +		if self.timer > 0 then +			return +		end +		self.timer = railcart:update(cart, RAILCART_ENTITY_UPDATE_TIME, object) +	end, +	get_staticdata = function(self) +		return "expired" +	end, +}) + +minetest.register_craftitem("railcart:cart", { +	description = "Railcart", +	inventory_image = minetest.inventorycube("cart_top.png", "cart_side.png", "cart_side.png"), +	wield_image = "cart_side.png", +	on_place = function(itemstack, placer, pointed_thing) +		local name = placer:get_player_name() +		if not name or pointed_thing.type ~= "node" then +			return +		end +		local pos = pointed_thing.under +		if not railtrack:is_railnode(pos) then +			return +		end +		if not minetest.is_singleplayer() then +			if not minetest.check_player_privs(name, {carts=true}) then +				minetest.chat_send_player(name, "Requires carts privilege") +				return +			end +		end +		local cart = railcart.cart:new() +		cart.id = #railcart.allcarts + 1 +		cart.pos = pos +		cart.prev = vector.new(pos) +		cart.accel = railtrack:get_acceleration(pos) +		table.insert(railcart.allcarts, cart) +		if not minetest.setting_getbool("creative_mode") then +			itemstack:take_item() +		end +		return itemstack +	end, +}) + +minetest.register_craft({ +	output = "railcart:cart", +	recipe = { +		{"default:steel_ingot", "", "default:steel_ingot"}, +		{"default:steel_ingot", "", "default:steel_ingot"}, +		{"group:wood", "default:steel_ingot", "group:wood"}, +	}, +}) + diff --git a/railcart/models/cart.png b/railcart/models/cart.pngBinary files differ new file mode 100644 index 0000000..1f9f568 --- /dev/null +++ b/railcart/models/cart.png diff --git a/railcart/models/railcart.x b/railcart/models/railcart.x new file mode 100644 index 0000000..3325aaf --- /dev/null +++ b/railcart/models/railcart.x @@ -0,0 +1,339 @@ +xof 0303txt 0032 + +Frame Root { +  FrameTransformMatrix { +     1.000000, 0.000000, 0.000000, 0.000000, +     0.000000, 0.000000, 1.000000, 0.000000, +     0.000000, 1.000000,-0.000000, 0.000000, +     0.000000, 0.000000, 0.000000, 1.000000;; +  } +  Frame Cube { +    FrameTransformMatrix { +       5.000000, 0.000000,-0.000000, 0.000000, +      -0.000000, 3.535534, 3.535534, 0.000000, +       0.000000,-3.535534, 3.535534, 0.000000, +       0.000000,-3.000000, 3.000000, 1.000000;; +    } +    Mesh { //Cube_001 Mesh +      72; +      -1.000000; 1.000000;-1.000000;, +      -1.000000;-1.000000;-1.000000;, +       1.000000;-1.000000;-1.000000;, +       1.000000; 1.000000;-1.000000;, +      -0.833334;-1.000000; 1.000000;, +      -1.000000;-1.000000; 1.000000;, +      -1.000000;-0.833333; 1.000000;, +      -0.833334;-0.833333; 1.000000;, +      -1.000000;-1.000000;-1.000000;, +      -1.000000;-1.000000; 1.000000;, +       0.999999;-1.000001; 1.000000;, +       1.000000;-1.000000;-1.000000;, +       0.999999;-1.000001; 1.000000;, +       0.833332;-1.000000; 1.000000;, +       0.833333;-0.833334; 1.000000;, +       1.000000;-0.833334; 1.000000;, +       0.833332;-1.000000; 1.000000;, +      -0.833334;-1.000000; 1.000000;, +      -0.833334;-0.833333; 1.000000;, +       0.833333;-0.833334; 1.000000;, +       1.000000; 0.833333; 1.000000;, +       0.833334; 0.833333; 1.000000;, +       0.833334; 1.000000; 1.000000;, +       1.000000; 0.999999; 1.000000;, +       1.000000;-0.833334; 1.000000;, +       0.833333;-0.833334; 1.000000;, +       0.833334; 0.833333; 1.000000;, +       1.000000; 0.833333; 1.000000;, +       0.833334; 0.833333; 1.000000;, +      -0.833333; 0.833333; 1.000000;, +      -0.833333; 1.000000; 1.000000;, +       0.833334; 1.000000; 1.000000;, +       0.833334; 0.833333;-0.800000;, +      -0.833333; 0.833333;-0.800000;, +      -0.833333; 0.833333; 1.000000;, +       0.833334; 0.833333; 1.000000;, +      -0.833333; 0.833333; 1.000000;, +      -1.000000; 0.833333; 1.000000;, +      -1.000000; 1.000000; 1.000000;, +      -0.833333; 1.000000; 1.000000;, +      -0.833334;-0.833333; 1.000000;, +      -1.000000;-0.833333; 1.000000;, +      -1.000000; 0.833333; 1.000000;, +      -0.833333; 0.833333; 1.000000;, +       0.833333;-0.833334;-0.800000;, +      -0.833334;-0.833333;-0.800000;, +      -0.833333; 0.833333;-0.800000;, +       0.833334; 0.833333;-0.800000;, +      -0.833333; 0.833333;-0.800000;, +      -0.833334;-0.833333;-0.800000;, +      -0.833334;-0.833333; 1.000000;, +      -0.833333; 0.833333; 1.000000;, +      -0.833334;-0.833333;-0.800000;, +       0.833333;-0.833334;-0.800000;, +       0.833333;-0.833334; 1.000000;, +      -0.833334;-0.833333; 1.000000;, +       0.833333;-0.833334;-0.800000;, +       0.833334; 0.833333;-0.800000;, +       0.833334; 0.833333; 1.000000;, +       0.833333;-0.833334; 1.000000;, +      -1.000000; 1.000000;-1.000000;, +      -1.000000; 1.000000; 1.000000;, +      -1.000000;-1.000000; 1.000000;, +      -1.000000;-1.000000;-1.000000;, +      -1.000000; 1.000000; 1.000000;, +      -1.000000; 1.000000;-1.000000;, +       1.000000; 1.000000;-1.000000;, +       1.000000; 0.999999; 1.000000;, +       1.000000;-1.000000;-1.000000;, +       0.999999;-1.000001; 1.000000;, +       1.000000; 0.999999; 1.000000;, +       1.000000; 1.000000;-1.000000;; +      18; +      4;0;1;2;3;, +      4;4;5;6;7;, +      4;8;9;10;11;, +      4;12;13;14;15;, +      4;16;17;18;19;, +      4;20;21;22;23;, +      4;24;25;26;27;, +      4;28;29;30;31;, +      4;32;33;34;35;, +      4;36;37;38;39;, +      4;40;41;42;43;, +      4;44;45;46;47;, +      4;48;49;50;51;, +      4;52;53;54;55;, +      4;56;57;58;59;, +      4;60;61;62;63;, +      4;64;65;66;67;, +      4;68;69;70;71;; +      MeshNormals { //Cube_001 Normals +        72; +         0.000000; 0.000000;-1.000000;, +         0.000000; 0.000000;-1.000000;, +         0.000000; 0.000000;-1.000000;, +         0.000000; 0.000000;-1.000000;, +         0.000000;-0.000000; 1.000000;, +         0.000000;-0.000000; 1.000000;, +         0.000000;-0.000000; 1.000000;, +         0.000000;-0.000000; 1.000000;, +        -0.000000;-1.000000;-0.000000;, +        -0.000000;-1.000000;-0.000000;, +        -0.000000;-1.000000;-0.000000;, +        -0.000000;-1.000000;-0.000000;, +         0.000000;-0.000000; 1.000000;, +         0.000000;-0.000000; 1.000000;, +         0.000000;-0.000000; 1.000000;, +         0.000000;-0.000000; 1.000000;, +         0.000000;-0.000000; 1.000000;, +         0.000000;-0.000000; 1.000000;, +         0.000000;-0.000000; 1.000000;, +         0.000000;-0.000000; 1.000000;, +         0.000000;-0.000000; 1.000000;, +         0.000000;-0.000000; 1.000000;, +         0.000000;-0.000000; 1.000000;, +         0.000000;-0.000000; 1.000000;, +         0.000000;-0.000000; 1.000000;, +         0.000000;-0.000000; 1.000000;, +         0.000000;-0.000000; 1.000000;, +         0.000000;-0.000000; 1.000000;, +         0.000000;-0.000000; 1.000000;, +         0.000000;-0.000000; 1.000000;, +         0.000000;-0.000000; 1.000000;, +         0.000000;-0.000000; 1.000000;, +        -0.000000;-1.000000; 0.000000;, +        -0.000000;-1.000000; 0.000000;, +        -0.000000;-1.000000; 0.000000;, +        -0.000000;-1.000000; 0.000000;, +         0.000000;-0.000000; 1.000000;, +         0.000000;-0.000000; 1.000000;, +         0.000000;-0.000000; 1.000000;, +         0.000000;-0.000000; 1.000000;, +         0.000000;-0.000000; 1.000000;, +         0.000000;-0.000000; 1.000000;, +         0.000000;-0.000000; 1.000000;, +         0.000000;-0.000000; 1.000000;, +         0.000000;-0.000000; 1.000000;, +         0.000000;-0.000000; 1.000000;, +         0.000000;-0.000000; 1.000000;, +         0.000000;-0.000000; 1.000000;, +         1.000000;-0.000000; 0.000000;, +         1.000000;-0.000000; 0.000000;, +         1.000000;-0.000000; 0.000000;, +         1.000000;-0.000000; 0.000000;, +         0.000000; 1.000000; 0.000000;, +         0.000000; 1.000000; 0.000000;, +         0.000000; 1.000000; 0.000000;, +         0.000000; 1.000000; 0.000000;, +        -1.000000; 0.000000; 0.000000;, +        -1.000000; 0.000000; 0.000000;, +        -1.000000; 0.000000; 0.000000;, +        -1.000000; 0.000000; 0.000000;, +        -1.000000; 0.000000;-0.000000;, +        -1.000000; 0.000000;-0.000000;, +        -1.000000; 0.000000;-0.000000;, +        -1.000000; 0.000000;-0.000000;, +         0.000000; 1.000000; 0.000000;, +         0.000000; 1.000000; 0.000000;, +         0.000000; 1.000000; 0.000000;, +         0.000000; 1.000000; 0.000000;, +         1.000000;-0.000000; 0.000000;, +         1.000000;-0.000000; 0.000000;, +         1.000000;-0.000000; 0.000000;, +         1.000000;-0.000000; 0.000000;; +        18; +        4;0;1;2;3;, +        4;4;5;6;7;, +        4;8;9;10;11;, +        4;12;13;14;15;, +        4;16;17;18;19;, +        4;20;21;22;23;, +        4;24;25;26;27;, +        4;28;29;30;31;, +        4;32;33;34;35;, +        4;36;37;38;39;, +        4;40;41;42;43;, +        4;44;45;46;47;, +        4;48;49;50;51;, +        4;52;53;54;55;, +        4;56;57;58;59;, +        4;60;61;62;63;, +        4;64;65;66;67;, +        4;68;69;70;71;; +      } //End of Cube_001 Normals +      MeshMaterialList { //Cube_001 Material List +        1; +        18; +        0, +        0, +        0, +        0, +        0, +        0, +        0, +        0, +        0, +        0, +        0, +        0, +        0, +        0, +        0, +        0, +        0, +        0;; +        Material Material { +           0.640000; 0.640000; 0.640000; 1.000000;; +           96.078431; +           0.500000; 0.500000; 0.500000;; +           0.000000; 0.000000; 0.000000;; +          TextureFilename {"cart.png";} +        } +      } //End of Cube_001 Material List +      MeshTextureCoords { //Cube_001 UV Coordinates +        72; +         0.000000; 0.500000;, +         0.500000; 0.500000;, +         0.500000; 1.000000;, +         0.000000; 1.000000;, +         0.031250; 0.500000;, +        -0.000000; 0.500000;, +        -0.000000; 0.468750;, +         0.031250; 0.468750;, +         0.500000; 0.500000;, +         0.500000; 0.000000;, +         1.000000; 0.000000;, +         1.000000; 0.500000;, +         0.468750; 0.468750;, +         0.500000; 0.468750;, +         0.500000; 0.500000;, +         0.468750; 0.500000;, +         0.031250; 0.468750;, +         0.468750; 0.468750;, +         0.468750; 0.500000;, +         0.031250; 0.500000;, +         0.468750; 0.000000;, +         0.500000; 0.000000;, +         0.500000; 0.031250;, +         0.468750; 0.031250;, +         0.468750; 0.031250;, +         0.500000; 0.031250;, +         0.500000; 0.468750;, +         0.468750; 0.468750;, +         0.468750; 0.031250;, +         0.031250; 0.031250;, +         0.031250; 0.000000;, +         0.468750; 0.000000;, +         1.000000; 0.500000;, +         0.500000; 0.500000;, +         0.500000; 0.000000;, +         1.000000; 0.000000;, +         0.031250; 0.031250;, +         0.000000; 0.031250;, +         0.000000; 0.000000;, +         0.031250; 0.000000;, +         0.031250; 0.468750;, +        -0.000000; 0.468750;, +         0.000000; 0.031250;, +         0.031250; 0.031250;, +         0.000000; 0.500000;, +         0.500000; 0.500000;, +         0.500000; 1.000000;, +         0.000000; 1.000000;, +         1.000000; 0.500000;, +         0.500000; 0.500000;, +         0.500000; 0.000000;, +         1.000000; 0.000000;, +         1.000000; 0.500000;, +         0.500000; 0.500000;, +         0.500000; 0.000000;, +         1.000000; 0.000000;, +         1.000000; 0.500000;, +         0.500000; 0.500000;, +         0.500000; 0.000000;, +         1.000000; 0.000000;, +         0.500000; 0.500000;, +         0.500000; 0.000000;, +         1.000000; 0.000000;, +         1.000000; 0.500000;, +         1.000000; 0.000000;, +         1.000000; 0.500000;, +         0.500000; 0.500000;, +         0.500000; 0.000000;, +         0.500000; 0.500000;, +         0.500000; 0.000000;, +         1.000000; 0.000000;, +         1.000000; 0.500000;; +      } //End of Cube_001 UV Coordinates +    } //End of Cube_001 Mesh +  } //End of Cube +} //End of Root Frame +AnimationSet { +  Animation { +    {Cube} +    AnimationKey { //Position +      2; +      4; +      0;3;     0.000000, 0.000000, 0.000000;;, +      1;3;     0.000000, 3.000000, 3.000000;;, +      2;3;     0.000000,-3.000000, 3.000000;;, +      3;3;     0.000000,-3.000000, 3.000000;;; +    } +    AnimationKey { //Rotation +      0; +      4; +      0;4;    -1.000000, 0.000000, 0.000000, 0.000000;;, +      1;4;    -0.923880,-0.382683,-0.000000, 0.000000;;, +      2;4;    -0.923880, 0.382683, 0.000000, 0.000000;;, +      3;4;    -0.923880, 0.382683, 0.000000, 0.000000;;; +    } +    AnimationKey { //Scale +      1; +      4; +      0;3;     5.000000, 5.000000, 5.000000;;, +      1;3;     5.000000, 5.000000, 5.000000;;, +      2;3;     5.000000, 5.000000, 5.000000;;, +      3;3;     5.000000, 5.000000, 5.000000;;; +    } +  } +} //End of AnimationSet diff --git a/railcart/railcart.lua b/railcart/railcart.lua new file mode 100644 index 0000000..917da44 --- /dev/null +++ b/railcart/railcart.lua @@ -0,0 +1,252 @@ +RAILCART_ENTITY_UPDATE_TIME = 1 +RAILCART_OBJECT_UPDATE_TIME = 5 +RAILCART_OBJECT_SAVE_TIME = 10 +RAILCART_RELOAD_DISTANCE = 32 +RAILCART_SNAP_DISTANCE = 0.5 +RAILCART_SPEED_MIN = 0.1 +RAILCART_SPEED_MAX = 10 + +railcart = { +	timer = 0, +	allcarts = {}, +} + +railcart.cart = { +	id = nil, +	entity = {}, +	pos = nil, +	target = nil, +	prev = nil, +	accel = nil, +	dir = {x=0, y=0, z=0}, +	vel = {x=0, y=0, z=0}, +	acc = {x=0, y=0, z=0}, +	timer = 0, +} + +function railcart.cart:new(obj) +	obj = obj or {} +	setmetatable(obj, self) +	self.__index = self +	return obj +end + +function railcart.cart:is_loaded() +	for _, player in pairs(minetest.get_connected_players()) do +		local pos = player:getpos() +		if pos then +			local dist = railtrack:get_distance(pos, self.pos) +			if dist <= RAILCART_RELOAD_DISTANCE then +				return true +			end +		end +	end +	return false +end + +function railcart.cart:on_step(dtime) +	self.timer = self.timer - dtime +	if self.timer > 0 then +		return +	end +	self.timer = RAILCART_OBJECT_UPDATE_TIME +	local entity = railcart:get_cart_ref(self.id) +	if entity.object then +		return +	end +	if self:is_loaded() then +		local object = minetest.add_entity(self.pos, "railcart:cart_entity") +		if object then +			entity = object:get_luaentity() or {} +			entity.cart = self +			object:setvelocity(self.vel) +			object:setacceleration(self.acc) +		end +	else +		self.timer = railcart:update(self, self.timer) +	end +end + +function railcart:save() +	local carts = {} +	for id, cart in pairs(railcart.allcarts) do +		local ref = {} +		for k, v in pairs(cart) do +			ref[k] = v +		end +		ref.entity = nil +		table.insert(carts, ref) +	end +	local output = io.open(minetest.get_worldpath().."/railcart.txt",'w') +	if output then +		output:write(minetest.serialize(carts)) +		io.close(output) +	end +end + +function railcart:get_cart_ref(id) +	local cart_ref = {} +	for _, ref in pairs(minetest.luaentities) do +		if ref.cart then +			if ref.cart.id == id then +				cart_ref = ref +				break +			end +		end +	end +	return cart_ref +end + +function railcart:get_delta_time(vel, acc, dist) +	if vel > 0 then +		if acc == 0 then +			return dist / vel +		end +		local r = math.sqrt(vel * vel + 2 * acc * dist) +		if r > 0 then +			return (-vel + r) / acc +		end +	end +	return 9999 --INF +end + +function railcart:velocity_to_dir(v) +	if math.abs(v.x) > math.abs(v.z) then +		return {x=railtrack:get_sign(v.x), y=railtrack:get_sign(v.y), z=0} +	else +		return {x=0, y=railtrack:get_sign(v.y), z=railtrack:get_sign(v.z)} +	end +end + +function railcart:velocity_to_speed(vel) +	local speed = math.max(math.abs(vel.x), math.abs(vel.z)) +	if speed < RAILCART_SPEED_MIN then +		speed = 0 +	elseif speed > RAILCART_SPEED_MAX then +		speed = RAILCART_SPEED_MAX +	end +	return speed +end + +function railcart:get_target(pos, vel) +	local meta = minetest.get_meta(vector.round(pos)) +	local dir = self:velocity_to_dir(vel) +	local targets = {} +	local rots = RAILTRACK_ROTATIONS +	local contype = meta:get_string("contype") or "" +	local s_junc = meta:get_string("junctions") or "" +	local s_cons = meta:get_string("connections") or "" +	local s_rots = meta:get_string("rotations") or "" +	if contype == "section" then +		local junctions = minetest.deserialize(s_junc) or {} +		for _, p in pairs(junctions) do +			table.insert(targets, p) +		end +	else +		local cons = minetest.deserialize(s_cons) or {} +		for _, p in pairs(cons) do +			table.insert(targets, p) +		end +		if s_rots ~= "" then +			local fwd = false +			for _, p in pairs(cons) do +				if vector.equals(vector.add(pos, dir), p) then +					fwd = true +				end +			end +			if fwd == true or #cons == 1 then +				rots = s_rots +			end +		end +	end +	local rotations = railtrack:get_rotations(rots, dir) +	for _, r in ipairs(rotations) do +		for _, t in pairs(targets) do +			local d = railtrack:get_direction(t, pos) +			if r.x == d.x and r.z == d.z then +				return t +			end +		end +	end +end + +function railcart:update(cart, time, object) +	if object then +		cart.pos = object:getpos() +		cart.vel = object:getvelocity() +	end +	if not cart.target then +		cart.pos = vector.new(cart.prev) +		cart.target = railcart:get_target(cart.pos, cart.vel) +		if object then +			object:moveto(cart.pos) +		end +	end +	local speed = railcart:velocity_to_speed(cart.vel) +	if not cart.target then +		speed = 0 +	end +	if speed > RAILCART_SPEED_MIN then +		cart.dir = railtrack:get_direction(cart.target, cart.pos) +		local d1 = railtrack:get_distance(cart.prev, cart.target) +		local d2 = railtrack:get_distance(cart.prev, cart.pos) +		local dist = d1 - d2 +		if dist > RAILCART_SNAP_DISTANCE then +			local accel = RAILTRACK_ACCEL_FLAT +			if cart.dir.y == -1 then +				accel = RAILTRACK_ACCEL_DOWN +			elseif cart.dir.y == 1 then +				accel = RAILTRACK_ACCEL_UP +			end +			accel = cart.accel or accel +			local dt = railcart:get_delta_time(speed, accel, dist) +			if dt < time then +				time = dt +			end +			local dp = speed * time + 0.5 * accel * time * time +			local vf = speed + accel * time +			if object then +				if vf <= 0 then +					speed = 0 +					accel = 0 +				end +				cart.vel = vector.multiply(cart.dir, speed) +				cart.acc = vector.multiply(cart.dir, accel) +			elseif dp > 0 then +				cart.vel = vector.multiply(cart.dir, vf) +				cart.pos = vector.add(cart.pos, vector.multiply(cart.dir, dp)) +			end +		else +			cart.pos = vector.new(cart.target) +			cart.prev = vector.new(cart.target) +			cart.accel = railtrack:get_acceleration(cart.target) +			cart.target = nil +			return 0 +		end +	else +		cart.vel = {x=0, y=0, z=0} +		cart.acc = {x=0, y=0, z=0} +	end +	if object then +		if cart.dir.y == -1 then +			object:set_animation({x=1, y=1}, 1, 0) +		elseif cart.dir.y == 1 then +			object:set_animation({x=2, y=2}, 1, 0) +		else +			object:set_animation({x=0, y=0}, 1, 0) +		end +		if cart.dir.x < 0 then +			object:setyaw(math.pi / 2) +		elseif cart.dir.x > 0 then +			object:setyaw(3 * math.pi / 2) +		elseif cart.dir.z < 0 then +			object:setyaw(math.pi) +		elseif cart.dir.z > 0 then +			object:setyaw(0) +		end +		object:setvelocity(cart.vel) +		object:setacceleration(cart.acc) +	end +	return time +end + diff --git a/railcart/textures/cart.png b/railcart/textures/cart.pngBinary files differ new file mode 100644 index 0000000..1f9f568 --- /dev/null +++ b/railcart/textures/cart.png diff --git a/railcart/textures/cart_bottom.png b/railcart/textures/cart_bottom.pngBinary files differ new file mode 100644 index 0000000..f84b1ae --- /dev/null +++ b/railcart/textures/cart_bottom.png diff --git a/railcart/textures/cart_side.png b/railcart/textures/cart_side.pngBinary files differ new file mode 100644 index 0000000..79f6c32 --- /dev/null +++ b/railcart/textures/cart_side.png diff --git a/railcart/textures/cart_top.png b/railcart/textures/cart_top.pngBinary files differ new file mode 100644 index 0000000..8140fc7 --- /dev/null +++ b/railcart/textures/cart_top.png diff --git a/railtrack/LICENSE.txt b/railtrack/LICENSE.txt new file mode 100644 index 0000000..c43348a --- /dev/null +++ b/railtrack/LICENSE.txt @@ -0,0 +1,13 @@ +Minetest Mod - Railtrack [railtrack] +==================================== + +License Source Code: LGPL v2.1 + +License of media (textures, sounds and models): CC-0 + +Authors of media files: +----------------------- + +rarkenin: +  cart_rail_*.png + diff --git a/railtrack/README.txt b/railtrack/README.txt new file mode 100644 index 0000000..b371e29 --- /dev/null +++ b/railtrack/README.txt @@ -0,0 +1,72 @@ +Minetest Mod - Railtrack [railtrack] +==================================== + +Minetest version: 0.4.13 + +Depends: default + +Proof of concept rail networking system which enables rail-carts to travel +through unloaded map chunks. + +Please note, this mod makes heavy use of metadata so that much of the processing +gets done as tracks are laid, for this reason a 'rails' privilege is required in +order to place rails when using multiplayer mode. + +Crafting +-------- + +R = Rail [default:rail] +F = Mese Crystal Fragment [default:mese_crystal_fragment] +C = Coal Lump [default:coal_lump] +D = Diamond [default:diamond] +M = Mese Block [default:mese] + +Powered Rail: [railtrack:powerrail] + +By default these rails apply a positive acceleration during the time a cart +remains on a given section of track. When used with the mesecons mod the rails +will require power from a mesecon source to become active. + ++---+---+---+ +| R | F | R | ++---+---+---+ + +Braking Rail: [railtrack:brakerail] + +By default these rails apply a negative acceleration during the time a cart +remains on a given section of track. When used with the mesecons mod the rails +will require power from a mesecon source to become active. + ++---+---+---+ +| R | C | R | ++---+---+---+ + +Superconducting Rail: [railtrack:superrail] + +Zero friction rails that are easier to manage and are also a little less +cpu-intensive by avoiding the use of square root calculations. + ++---+---+---+ +| R | D | R | ++---+---+---+ + +Switching Rail: [railtrack:switchrail] + +Currently depends on mesecons to do much other than provide a convenient, zero +friction union to join long sections of superconducting rails. + ++---+---+---+ +| R | M | R | ++---+---+---+ + +Misc Items +---------- + +Rail Fixer: [railtrack:fixer] + +Only available in creative menu or with give(me) privileges. + +Rail Inspector [railtrack:inspector] + +Only available in creative menu or with give(me) privileges. + diff --git a/railtrack/depends.txt b/railtrack/depends.txt new file mode 100644 index 0000000..4ad96d5 --- /dev/null +++ b/railtrack/depends.txt @@ -0,0 +1 @@ +default diff --git a/railtrack/init.lua b/railtrack/init.lua new file mode 100644 index 0000000..373fcaa --- /dev/null +++ b/railtrack/init.lua @@ -0,0 +1,197 @@ +local modpath = minetest.get_modpath(minetest.get_current_modname()) + +dofile(modpath.."/railtrack.lua") + +railtrack:register_rail(":default:rail", { +	description = "Rail", +	tiles = {"default_rail.png", "default_rail_curved.png", +		"default_rail_t_junction.png", "default_rail_crossing.png"}, +	railtype = "rail", +}) + +railtrack:register_rail("railtrack:superrail", { +	description = "Superconducting Rail", +	tiles = {"carts_rail_sup.png", "carts_rail_curved_sup.png", +		"carts_rail_t_junction_sup.png", "carts_rail_crossing_sup.png"}, +	railtype = "superrail", +	acceleration = 0, +}) + +railtrack:register_rail("railtrack:powerrail", { +	description = "Powered Rail", +	tiles = {"carts_rail_pwr.png", "carts_rail_curved_pwr.png", +		"carts_rail_t_junction_pwr.png", "carts_rail_crossing_pwr.png"}, +	railtype = "powerrail", +	acceleration = 4, +	mesecons = { +		effector = { +			action_on = function(pos, node) +				railtrack:set_acceleration(pos, 4) +			end, +			action_off = function(pos, node) +				railtrack:set_acceleration(pos, RAILTRACK_FRICTION_FLAT) +			end, +		}, +	}, +}) + +railtrack:register_rail("railtrack:brakerail", { +	description = "Braking Rail", +	tiles = {"carts_rail_brk.png", "carts_rail_curved_brk.png", +		"carts_rail_t_junction_brk.png", "carts_rail_crossing_brk.png"}, +	railtype = "brakerail", +	acceleration = -4, +	mesecons = { +		effector = { +			action_on = function(pos, node) +				railtrack:set_acceleration(pos, -4) +			end, +			action_off = function(pos, node) +				railtrack:set_acceleration(pos, RAILTRACK_FRICTION_FLAT) +			end, +		}, +	}, +}) + +railtrack:register_rail("railtrack:switchrail", { +	description = "Switching Rail", +	tiles = {"carts_rail_swt.png", "carts_rail_curved_swt.png", +		"carts_rail_t_junction_swt.png", "carts_rail_crossing_swt.png"}, +	railtype = "switchrail", +	acceleration = 0, +	mesecons = { +		effector = { +			action_on = function(pos, node) +				local meta = minetest.get_meta(pos) +				meta:set_string("rotations", "RFLB") +			end, +			action_off = function(pos, node) +				local meta = minetest.get_meta(pos) +				meta:set_string("rotations", nil) +			end, +		}, +	}, +}) + +minetest.register_privilege("rails", "Player can dig and place rails.") + +minetest.register_tool("railtrack:fixer", { +	description = "Rail Fixer", +	inventory_image = "railtrack_fixer.png", +	wield_image = "railtrack_fixer.png", +	on_use = function(itemstack, user, pointed_thing) +		local pos = minetest.get_pointed_thing_position(pointed_thing, false) +		local name = user:get_player_name() +		if not pos or not name or pointed_thing.type ~= "node" then +			return +		end +		if not railtrack:is_railnode(pos) then +			minetest.chat_send_player(name, "Not a rail node!") +			return +		end +		if not minetest.is_singleplayer() then +			if not minetest.check_player_privs(name, {rails=true}) then +				minetest.chat_send_player(name, "Requires rails privilege") +				return +			end +		end +		local node = minetest.get_node(pos) +		minetest.remove_node(pos) +		set_node(pos, node) +		local def = minetest.registered_items[node.name] or {} +		if type(def.after_place_node) == "function" then +			def.after_place_node(pos, user, node) +		end +	end, +}) + +minetest.register_tool("railtrack:inspector", { +	description = "Rail Inspector", +	inventory_image = "railtrack_inspector.png", +	wield_image = "railtrack_inspector.png", +	on_use = function(itemstack, user, pointed_thing) +		local name = user:get_player_name() +		local pos = minetest.get_pointed_thing_position(pointed_thing, false) +		if not name or not pos then +			return +		end +		local node = minetest.get_node(pos) or {} +		if not railtrack:is_railnode(pos) or not node.name then +			minetest.chat_send_player(name, "Not a rail node!") +			return +		end +		local ref = minetest.registered_items[node.name] or {} +		local meta = minetest.get_meta(pos) +		local form = "" +		local size = 2.5 +		form = form.."label[0.5,0.5;POS: "..minetest.pos_to_string(pos).."]" +		local railtype = ref.railtype or "NIL" +		form = form.."label[0.5,1.0;RAILTYPE: "..railtype.."]" +		local contype = meta:get_string("contype") or "NIL" +		form = form.."label[0.5,1.5;CONTYPE: "..contype.."]" +		local accel = meta:get_string("acceleration") or "NIL" +		form = form.."label[0.5,2.0;ACCEL: "..accel.."]" +		local s_junc = meta:get_string("junctions") +		if s_junc then +			local junctions = minetest.deserialize(s_junc) +			if junctions then +				form = form.."label[0.5,2.5;JUNCTIONS:]" +				for i, p in ipairs(junctions) do +					size = size + 0.5 +					form = form.."label[0.5,"..size..";#"..i.." " +							..minetest.pos_to_string(p).."]" +				end +			end +		end +		local s_cons = meta:get_string("connections") +		if s_cons then +			local cons = minetest.deserialize(s_cons) +			if cons then +				size = size + 0.5 +				form = form.."label[0.5,"..size..";CONNECTIONS:]" +				for i, p in pairs(cons) do +					size = size + 0.5 +					form = form.."label[0.5,"..size..";#"..i.." " +							..minetest.pos_to_string(p).."]" +				end +			end +		end +		local s_rots = meta:get_string("rotations") +		if s_rots then +			size = size + 0.5 +			form = form.."label[0.5,"..size..";ROTATIONS: "..s_rots.."]" +		end +		form = form.."button_exit[3.0,"..(size + 1)..";2,0.5;;Ok]" +		form = "size[8,"..(size + 2).."]"..form +		minetest.show_formspec(name, "info", form) +	end, +}) + +minetest.register_craft({ +	output = "railtrack:powerrail 2", +	recipe = { +		{"default:rail", "default:mese_crystal_fragment", "default:rail"}, +	} +}) + +minetest.register_craft({ +	output = "railtrack:brakerail 2", +	recipe = { +		{"default:rail", "default:coal_lump", "default:rail"}, +	} +}) + +minetest.register_craft({ +	output = "railtrack:switchrail 2", +	recipe = { +		{"default:rail", "default:mese", "default:rail"}, +	} +}) + +minetest.register_craft({ +	output = "railtrack:superrail 2", +	recipe = { +		{"default:rail", "default:diamond", "default:rail"}, +	} +}) + diff --git a/railtrack/railtrack.lua b/railtrack/railtrack.lua new file mode 100644 index 0000000..3a1f714 --- /dev/null +++ b/railtrack/railtrack.lua @@ -0,0 +1,284 @@ +RAILTRACK_WARN_SECTION_LEN = 20 +RAILTRACK_ROTATIONS = "FLR" +RAILTRACK_ACCEL_FLAT = -0.5 +RAILTRACK_ACCEL_UP = -2 +RAILTRACK_ACCEL_DOWN = 2 + +railtrack = {} + +railtrack.default_rail = { +	description = "Rail", +	drawtype = "raillike", +	tiles = {"default_rail.png", "default_rail_curved.png", +		"default_rail_t_junction.png", "default_rail_crossing.png"}, +	paramtype = "light", +	sunlight_propagates = true, +	walkable = false, +	is_ground_content = false, +	selection_box = { +		type = "fixed", +		fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2}, +	}, +	groups = {bendy = 2, dig_immediate = 2, attached_node = 1, +		connect_to_raillike = minetest.raillike_group("rail")}, +	railtype = "rail", +	on_place = function(itemstack, placer, pointed_thing) +		local name = placer:get_player_name() +		if not name or pointed_thing.type ~= "node" then +			return +		end +		if not minetest.is_singleplayer() then +			if not minetest.check_player_privs(name, {rails=true}) then +				minetest.chat_send_player(name, "Requires rails privilege") +				return +			end +		end +	end, +	after_place_node = function(pos, placer, itemstack) +		local meta = minetest.get_meta(pos) +		local def = itemstack:get_definition() or {} +		if def.acceleration then +			meta:set_string("acceleration", def.acceleration) +		end +		local junc = {} +		local contype = meta:get_string("contype") or "" +		local s_cons = meta:get_string("connections") or "" +		if contype == "section" then +			railtrack:warn_section_len(placer, pos, meta) +		elseif s_cons ~= "" then +			local cons = minetest.deserialize(s_cons) +			for _, con in pairs(cons) do +				if railtrack:warn_section_len(placer, con) then +					break +				end +			end +		end +	end, +	on_construct = function(pos) +		railtrack:update_rails(pos) +	end, +	after_destruct = function(pos) +		local cons = railtrack:get_connections(pos) +		for _, p in pairs(cons) do +			railtrack:update_rails(p) +		end +	end, +} + +function railtrack:register_rail(name, def) +	for k, v in pairs(railtrack.default_rail) do +		if not def[k] then +			def[k] = v +		end +	end +	def.inventory_image = def.inventory_image or def.tiles[1] +	def.wield_image = def.wield_image or def.tiles[1] +	minetest.register_node(name, def) +end + +function railtrack:warn_section_len(player, pos, meta) +	meta = meta or minetest.get_meta(pos) +	local contype = meta:get_string("contype") or "" +	if contype == "section" then +		local s_junc = meta:get_string("junctions") or "" +		if s_junc ~= "" then +			local junc = minetest.deserialize(s_junc) +			if #junc == 2 then +				local dist = railtrack:get_distance(junc[1], junc[2]) +				if dist > RAILTRACK_WARN_SECTION_LEN then +					local name = player:get_player_name() +					if name then +						minetest.chat_send_player(name, "Warning, section" +								.." length "..dist.." exceeds the recommended" +								.." maximum of "..RAILTRACK_WARN_SECTION_LEN) +						return true +					end +				end +			end +		end +	end +end + +function railtrack:is_railnode(pos) +	local node = minetest.get_node(pos) +	if node then +		return minetest.get_item_group(node.name, "connect_to_raillike") > 0 +	end +end + +function railtrack:get_sign(z) +	if z == 0 then +		return 0 +	else +		return z / math.abs(z) +	end +end + +function railtrack:get_rotations(s_rots, dir) +	local rots = {} +	for i = 1, string.len(s_rots) do +		local r = string.sub(s_rots, i, i) +		local rot = nil +		if r == "F" then +			rot = {x=dir.x, z=dir.z} +		elseif r == "L" then +			rot = {x=-dir.z, z=dir.x} +		elseif r == "R" then +			rot = {x=dir.z, z=-dir.x} +		elseif r == "B" then +			rot = {x=-dir.x, z=-dir.z} +		end +		if rot then +			table.insert(rots, rot) +		end +	end +	return rots +end + +function railtrack:get_acceleration(pos) +	local meta = minetest.get_meta(pos) +	local accel = meta:get_string("acceleration") or "" +	if accel ~= "" then +		return tonumber(accel) +	end +end + +function railtrack:get_direction(p1, p2) +	local v = vector.subtract(p1, p2) +	return { +		x = railtrack:get_sign(v.x), +		y = railtrack:get_sign(v.y), +		z = railtrack:get_sign(v.z), +	} +end + +function railtrack:get_distance(p1, p2) +	local dx = p1.x - p2.x +	local dz = p1.z - p2.z +	return math.abs(dx) + math.abs(dz) +end + + +function railtrack:get_railtype(pos) +	local node = minetest.get_node(pos) or {} +	if node.name then +		local ref = minetest.registered_items[node.name] or {} +		return ref.railtype +	end +end + +function railtrack:get_connection_type(pos, cons) +	local railtype = railtrack:get_railtype(pos) +	if #cons == 0 then +		return "single" +	elseif #cons == 1 then +		return "junction" +	elseif #cons == 2 then +		if cons[1].x == cons[2].x or cons[1].z == cons[2].z then +			if (cons[1].y == cons[2].y and cons[1].y == pos.y) or +					(math.abs(cons[1].y - cons[2].y) == 2) then +				if railtype == railtrack:get_railtype(cons[1]) and +						railtype == railtrack:get_railtype(cons[2]) then +					return "section" +				end +			end +		end +	end +	return "junction" +end + +function railtrack:get_connections(pos) +	local connections = {} +	for y = -1, 1 do +		for x = -1, 1 do +			for z = -1, 1 do +				if math.abs(x) ~= math.abs(z) then +					local p = vector.add(pos, {x=x, y=y, z=z}) +					if railtrack:is_railnode(p) then +						table.insert(connections, p) +					end +				end +			end +		end +	end +	return connections +end + +function railtrack:get_junctions(pos, last_pos, junctions) +	junctions = junctions or {} +	local cons = railtrack:get_connections(pos) +	local contype = railtrack:get_connection_type(pos, cons) +	if contype == "junction" then +		table.insert(junctions, pos) +	elseif contype == "section" then +		if last_pos then +			for i, p in pairs(cons) do +				if vector.equals(p, last_pos) then +					cons[i] = nil +				end +			end +		end +		for _, p in pairs(cons) do +			railtrack:get_junctions(p, pos, junctions) +		end +	end +	return junctions +end + +function railtrack:set_acceleration(pos, accel) +	local meta = minetest.get_meta(pos) +	local contype = meta:get_string("contype") +	if contype == "section" then +		local s_junc = meta:get_string("junctions") or "" +		local junc = minetest.deserialize(s_junc) or {} +		if #junc == 2 then +			local p = vector.new(junc[2]) +			local dir = railtrack:get_direction(junc[1], junc[2]) +			local dist = railtrack:get_distance(junc[1], junc[2]) +			for i = 0, dist do +				local m = minetest.get_meta(p) +				if m then +					m:set_string("acceleration", tostring(accel)) +				end +				p = vector.add(dir, p) +			end +		end +	else +		meta:set_string("acceleration", tostring(accel)) +	end +end + +function railtrack:update_rails(pos, last_pos, level) +	local connections = {} +	local junctions = {} +	local meta = minetest.get_meta(pos) +	local cons = railtrack:get_connections(pos) +	local contype = railtrack:get_connection_type(pos, cons) +	level = level or 0 +	for i, p in pairs(cons) do +		connections[i] = p +	end +	if contype == "junction" then +		level = level + 1 +	end +	if contype == "section" or level < 2 then +		if last_pos then +			for i, p in pairs(cons) do +				if vector.equals(p, last_pos) then +					cons[i] = nil +				end +			end +		end +		for _, p in pairs(cons) do +			railtrack:update_rails(p, pos, level) +		end +	end +	if contype == "section" then +		junctions = railtrack:get_junctions(pos) +		connections = {} +	end +	meta:set_string("connections", minetest.serialize(connections)) +	meta:set_string("junctions", minetest.serialize(junctions)) +	meta:set_string("contype", contype) +end + diff --git a/railtrack/textures/carts_rail_brk.png b/railtrack/textures/carts_rail_brk.pngBinary files differ new file mode 100644 index 0000000..f3e0ff9 --- /dev/null +++ b/railtrack/textures/carts_rail_brk.png diff --git a/railtrack/textures/carts_rail_crossing_brk.png b/railtrack/textures/carts_rail_crossing_brk.pngBinary files differ new file mode 100644 index 0000000..3ace508 --- /dev/null +++ b/railtrack/textures/carts_rail_crossing_brk.png diff --git a/railtrack/textures/carts_rail_crossing_pwr.png b/railtrack/textures/carts_rail_crossing_pwr.pngBinary files differ new file mode 100644 index 0000000..d63f133 --- /dev/null +++ b/railtrack/textures/carts_rail_crossing_pwr.png diff --git a/railtrack/textures/carts_rail_crossing_sup.png b/railtrack/textures/carts_rail_crossing_sup.pngBinary files differ new file mode 100644 index 0000000..b51467d --- /dev/null +++ b/railtrack/textures/carts_rail_crossing_sup.png diff --git a/railtrack/textures/carts_rail_crossing_swt.png b/railtrack/textures/carts_rail_crossing_swt.pngBinary files differ new file mode 100644 index 0000000..a780cf2 --- /dev/null +++ b/railtrack/textures/carts_rail_crossing_swt.png diff --git a/railtrack/textures/carts_rail_curved_brk.png b/railtrack/textures/carts_rail_curved_brk.pngBinary files differ new file mode 100644 index 0000000..5a84918 --- /dev/null +++ b/railtrack/textures/carts_rail_curved_brk.png diff --git a/railtrack/textures/carts_rail_curved_pwr.png b/railtrack/textures/carts_rail_curved_pwr.pngBinary files differ new file mode 100644 index 0000000..e2ac67a --- /dev/null +++ b/railtrack/textures/carts_rail_curved_pwr.png diff --git a/railtrack/textures/carts_rail_curved_sup.png b/railtrack/textures/carts_rail_curved_sup.pngBinary files differ new file mode 100644 index 0000000..326d544 --- /dev/null +++ b/railtrack/textures/carts_rail_curved_sup.png diff --git a/railtrack/textures/carts_rail_curved_swt.png b/railtrack/textures/carts_rail_curved_swt.pngBinary files differ new file mode 100644 index 0000000..0ed9287 --- /dev/null +++ b/railtrack/textures/carts_rail_curved_swt.png diff --git a/railtrack/textures/carts_rail_pwr.png b/railtrack/textures/carts_rail_pwr.pngBinary files differ new file mode 100644 index 0000000..95f33f6 --- /dev/null +++ b/railtrack/textures/carts_rail_pwr.png diff --git a/railtrack/textures/carts_rail_sup.png b/railtrack/textures/carts_rail_sup.pngBinary files differ new file mode 100644 index 0000000..4c812a9 --- /dev/null +++ b/railtrack/textures/carts_rail_sup.png diff --git a/railtrack/textures/carts_rail_swt.png b/railtrack/textures/carts_rail_swt.pngBinary files differ new file mode 100644 index 0000000..b7da323 --- /dev/null +++ b/railtrack/textures/carts_rail_swt.png diff --git a/railtrack/textures/carts_rail_t_junction_brk.png b/railtrack/textures/carts_rail_t_junction_brk.pngBinary files differ new file mode 100644 index 0000000..0c2c1cb --- /dev/null +++ b/railtrack/textures/carts_rail_t_junction_brk.png diff --git a/railtrack/textures/carts_rail_t_junction_pwr.png b/railtrack/textures/carts_rail_t_junction_pwr.pngBinary files differ new file mode 100644 index 0000000..7f97fc7 --- /dev/null +++ b/railtrack/textures/carts_rail_t_junction_pwr.png diff --git a/railtrack/textures/carts_rail_t_junction_sup.png b/railtrack/textures/carts_rail_t_junction_sup.pngBinary files differ new file mode 100644 index 0000000..fbdc89c --- /dev/null +++ b/railtrack/textures/carts_rail_t_junction_sup.png diff --git a/railtrack/textures/carts_rail_t_junction_swt.png b/railtrack/textures/carts_rail_t_junction_swt.pngBinary files differ new file mode 100644 index 0000000..b03844d --- /dev/null +++ b/railtrack/textures/carts_rail_t_junction_swt.png diff --git a/railtrack/textures/default_rail.png b/railtrack/textures/default_rail.pngBinary files differ new file mode 100644 index 0000000..26fed02 --- /dev/null +++ b/railtrack/textures/default_rail.png diff --git a/railtrack/textures/railtrack_fixer.png b/railtrack/textures/railtrack_fixer.pngBinary files differ new file mode 100644 index 0000000..17af383 --- /dev/null +++ b/railtrack/textures/railtrack_fixer.png diff --git a/railtrack/textures/railtrack_inspector.png b/railtrack/textures/railtrack_inspector.pngBinary files differ new file mode 100644 index 0000000..671fd38 --- /dev/null +++ b/railtrack/textures/railtrack_inspector.png | 
