Rewrite seating system
authororwell96 <mono96.mml@gmail.com>
Wed, 25 Jan 2017 20:23:54 +0000 (21:23 +0100)
committerorwell96 <mono96.mml@gmail.com>
Wed, 25 Jan 2017 20:23:54 +0000 (21:23 +0100)
Players no longer need to worry where to sit down.

advtrains/advtrains/api_doc.txt
advtrains/advtrains/helpers.lua
advtrains/advtrains/wagons.lua
advtrains/advtrains_train_industrial/depends.txt
advtrains/advtrains_train_industrial/init.lua
advtrains/advtrains_train_japan/depends.txt
advtrains/advtrains_train_japan/init.lua
advtrains/advtrains_train_steam/depends.txt
advtrains/advtrains_train_steam/init.lua
advtrains/advtrains_train_subway/depends.txt
advtrains/advtrains_train_subway/init.lua

index 6b1aa2e..ca894b1 100644 (file)
@@ -20,6 +20,7 @@ advtrains.register_wagon(name, prototype, description, inventory_image)
        max_speed = 10,
        ^- optional, default 10: defines the maximum speed this wagon can drive. The maximum speed of a train is determined by the wagon with the lowest max_speed value.
        seats = {
+       ^- contains zero or more seat definitions. A seat is a place where a player can be attached when getting on a wagon.
                {
                        name="Left front window",
                        ^- display name of this seat
@@ -29,10 +30,24 @@ advtrains.register_wagon(name, prototype, description, inventory_image)
                        ^- player:set_eye_offset is called with this parameter.
                        driving_ctrl_access=false,
                        ^- If the seat is a driver stand, and players sitting here should get access to the train's driving control.
-
+                       group="default"
+                       ^- optional. Defines the seat group. See 'seat_groups' below
                },
        },
-       ^- contains zero or more seat definitions. A seat is a place where a player can be attached when getting on a wagon.
+       seat_groups = {
+       ^- optional. If defined, activates advanced seating behavior. See "seating behavior".
+               default = {
+                       name = "Seats"
+                       ^- name of this seat group, to be shown in get-on menu.
+                       access_to = {"foo", "bar"}
+                       ^- List of seat groups you can access from this seat using the menu when sitting inside the train.
+                       require_doors_open = true
+                       ^- Only allow getting on and off if doors are open.
+               }
+       }
+       assign_to_seat_group = {"default"}
+       ^- optional, like seat_groups. When player right_clicks the wagon, player will be assigned to the first free seat group in the list.
+       
        wagon_span=2,
        ^- How far this wagon extends from its base position. Is the half of the wagon length.
        ^- Used to determine in which distance the other wagons have to be positioned. Will require tweaking.
@@ -72,6 +87,18 @@ advtrains.register_wagon(name, prototype, description, inventory_image)
        - the overall extent in X and Y direction is <=3 units
 - wagon_span is then the distance between the model origin and the Z axis extent.
 
+# Seating behavior
+If the advanced seating behavior is active, clicking on a wagon will immediately get you on that wagon depending on the entries in assign_to_seat_group.
+If all seat groups are full, if the doors are closed or if you are not authorized to enter this seat group(e.g. driver stands), will show a warning.
+On a train, right-clicking the wagon will make you get off the train unless:
+- the doors are closed and it requires open doors.
+- you have access to a seat group specified in access_to (you may enter it and it's not full)
+- you are the owner and can access the wagon preferences
+In case there's no possibility, does nothing.
+In case there are multiple possibilities, will show a form.
+
+If you can't enter a train because the doors are closed, any of the train's wagon owners or people authorized by them can open the doors(on the side they are standing) with shift-click.
+
 ### Tracks
 Most modders will be satisfied with the built-in tracks. If cog railways, maglev trains and mine trains are added, it is necessary to understand the definition of tracks. Although the tracks API is there, explaining it would require more effort than me creating the wanted definitions myself. Contact me if you need to register your own rails using my registration functions.
 
index cc7deb8..5761d18 100644 (file)
@@ -94,7 +94,7 @@ function advtrains.conway(midreal, prev, drives_on)--in order prev,mid,return
        --atprint("dir applied next pos: "..(next and minetest.pos_to_string(next) or "nil").."(chkdir is "..(chkdir or "nil")..", y-offset "..y_offset..")")\r
        --is there a next\r
        if not next then\r
-               atprint("in conway: no next rail(nil), returning!")\r
+               --atprint("in conway: no next rail(nil), returning!")\r
                return nil\r
        end\r
        \r
@@ -102,31 +102,31 @@ function advtrains.conway(midreal, prev, drives_on)--in order prev,mid,return
        \r
        --is it a rail?\r
        if(not nextnode_ok) then\r
-               atprint("in conway: next "..minetest.pos_to_string(next).." not a rail, trying one node below!")\r
+               --atprint("in conway: next "..minetest.pos_to_string(next).." not a rail, trying one node below!")\r
                next.y=next.y-1\r
                y_offset=y_offset-1\r
                \r
                nextnode_ok, nextdir1, nextdir2, nextrely1, nextrely2, nextrailheight=advtrains.get_rail_info_at(advtrains.round_vector_floor_y(next), drives_on)\r
                if(not nextnode_ok) then\r
-                       atprint("in conway: one below "..minetest.pos_to_string(next).." is not a rail either, returning!")\r
+                       --atprint("in conway: one below "..minetest.pos_to_string(next).." is not a rail either, returning!")\r
                        return nil\r
                end\r
        end\r
        \r
        --is this next rail connecting to the mid?\r
        if not ( (((nextdir1+8)%16)==chkdir and nextrely1==chkrely-y_offset) or (((nextdir2+8)%16)==chkdir and nextrely2==chkrely-y_offset) ) then\r
-               atprint("in conway: next "..minetest.pos_to_string(next).." not connecting, trying one node below!")\r
+               --atprint("in conway: next "..minetest.pos_to_string(next).." not connecting, trying one node below!")\r
                next.y=next.y-1\r
                y_offset=y_offset-1\r
                \r
                nextnode_ok, nextdir1, nextdir2, nextrely1, nextrely2, nextrailheight=advtrains.get_rail_info_at(advtrains.round_vector_floor_y(next), drives_on)\r
                if(not nextnode_ok) then\r
-                       atprint("in conway: (at connecting if check again) one below "..minetest.pos_to_string(next).." is not a rail either, returning!")\r
+                       --atprint("in conway: (at connecting if check again) one below "..minetest.pos_to_string(next).." is not a rail either, returning!")\r
                        return nil\r
                end\r
                if not ( (((nextdir1+8)%16)==chkdir and nextrely1==chkrely) or (((nextdir2+8)%16)==chkdir and nextrely2==chkrely) ) then\r
-                       atprint("in conway: one below "..minetest.pos_to_string(next).." rail not connecting, returning!")\r
-                       atprint(" in order mid1,2,next1,2,chkdir "..middir1.." "..middir2.." "..nextdir1.." "..nextdir2.." "..chkdir)\r
+                       --atprint("in conway: one below "..minetest.pos_to_string(next).." rail not connecting, returning!")\r
+                       --atprint(" in order mid1,2,next1,2,chkdir "..middir1.." "..middir2.." "..nextdir1.." "..nextdir2.." "..chkdir)\r
                        return nil\r
                end\r
        end\r
index 2e80fa6..ef7f238 100644 (file)
@@ -22,27 +22,6 @@ local wagon={
 }\r
 \r
 \r
-\r
-function wagon:on_rightclick(clicker)\r
-       if not self:ensure_init() then return end\r
-       if not clicker or not clicker:is_player() then\r
-               return\r
-       end\r
-       if clicker:get_player_control().aux1 then\r
-               --advtrains.dumppath(self:train().path)\r
-               --minetest.chat_send_all("at index "..(self:train().index or "nil"))\r
-               --advtrains.invert_train(self.train_id)\r
-               atprint(dump(self))\r
-               return\r
-       end     \r
-       local no=self:get_seatno(clicker:get_player_name())\r
-       if no then\r
-               self:get_off(no)\r
-       else\r
-               self:show_get_on_form(clicker:get_player_name())\r
-       end\r
-end\r
-\r
 function wagon:train()\r
        return advtrains.trains[self.train_id]\r
 end\r
@@ -451,14 +430,97 @@ function advtrains.get_real_path_index(train, pit)
        return index\r
 end\r
 \r
+function wagon:on_rightclick(clicker)\r
+       if not self:ensure_init() then return end\r
+       if not clicker or not clicker:is_player() then\r
+               return\r
+       end\r
+       if clicker:get_player_control().aux1 then\r
+               --advtrains.dumppath(self:train().path)\r
+               --minetest.chat_send_all("at index "..(self:train().index or "nil"))\r
+               --advtrains.invert_train(self.train_id)\r
+               atprint(dump(self))\r
+               return\r
+       end     \r
+       local pname=clicker:get_player_name()\r
+       local no=self:get_seatno(pname)\r
+       if no then\r
+               if self.seat_groups then\r
+                       local poss={}\r
+                       local sgr=self.seats[no].group\r
+                       for _,access in ipairs(self.seat_groups[sgr].access_to) do\r
+                               if self:check_seat_group_access(pname, access) then\r
+                                       poss[#poss+1]={name=self.seat_groups[access].name, key="sgr_"..access}\r
+                               end\r
+                       end\r
+                       if self.has_inventory and self.get_inventory_formspec then\r
+                               poss[#poss+1]={name="Show inventory", key="inv"}\r
+                       end\r
+                       if self.owner==pname then\r
+                               poss[#poss+1]={name="Wagon properties", key="prop"}\r
+                       end\r
+                       if not self.seat_groups[sgr].require_doors_open or self:train().door_open~=0 then\r
+                               poss[#poss+1]={name="Get off", key="off"}\r
+                       end\r
+                       if #poss==0 then\r
+                               --can't do anything.\r
+                       elseif #poss==1 then\r
+                               self:seating_from_key_helper(pname, {[poss[1].key]=true}, no)\r
+                       else\r
+                               local form = "size[5,"..1+(#poss).."]"\r
+                               for pos,ent in ipairs(poss) do\r
+                                       form = form .. "button_exit[0.5,"..(pos-0.5)..";4,1;"..ent.key..";"..ent.name.."]"\r
+                               end\r
+                               minetest.show_formspec(pname, "advtrains_seating_"..self.unique_id, form)\r
+                       end\r
+               else\r
+                       self:get_off(no)\r
+               end\r
+       else\r
+               if self.seat_groups then\r
+                       if #self.seats==0 then\r
+                               if self.has_inventory and self.get_inventory_formspec then\r
+                                       minetest.show_formspec(pname, "advtrains_inv_"..self.unique_id, self:get_inventory_formspec(pname))\r
+                               end\r
+                               return\r
+                       end\r
+                       \r
+                       local doors_open = self:train().door_open~=0\r
+                       for _,sgr in ipairs(self.assign_to_seat_group) do\r
+                               if self:check_seat_group_access(pname, sgr) then\r
+                                       for seatid, seatdef in ipairs(self.seats) do\r
+                                               atprint(sgr, seatid, seatdef, self.seat_groups[sgr], doors_open)\r
+                                               if seatdef.group==sgr and not self.seatp[seatid] and (not self.seat_groups[sgr].require_doors_open or doors_open) then\r
+                                                       self:get_on(clicker, seatid)\r
+                                                       return\r
+                                               end\r
+                                       end\r
+                               end\r
+                       end\r
+                       minetest.chat_send_player(pname, "Can't get on: wagon full or doors closed!")\r
+               else\r
+                       self:show_get_on_form(pname)\r
+               end\r
+       end\r
+end\r
+\r
 function wagon:get_on(clicker, seatno)\r
        if not self.seatp then\r
                self.seatp={}\r
        end\r
        if not self.seats[seatno] then return end\r
+       local oldno=self:get_seatno(clicker:get_player_name())\r
+       if oldno then\r
+               atprint("get_on: clearing oldno",seatno)\r
+               advtrains.player_to_train_mapping[clicker:get_player_name()]=nil\r
+               advtrains.clear_driver_hud(clicker:get_player_name())\r
+               self.seatp[oldno]=nil\r
+       end\r
        if self.seatp[seatno] and self.seatp[seatno]~=clicker:get_player_name() then\r
+               atprint("get_on: throwing off",self.seatp[seatno],"from seat",seatno)\r
                self:get_off(seatno)\r
        end\r
+       atprint("get_on: attaching",clicker:get_player_name())\r
        self.seatp[seatno] = clicker:get_player_name()\r
        advtrains.player_to_train_mapping[clicker:get_player_name()]=self.train_id\r
        clicker:set_attach(self.object, "", self.seats[seatno].attach_offset, {x=0,y=0,z=0})\r
@@ -485,6 +547,7 @@ function wagon:get_off(seatno)
        advtrains.player_to_train_mapping[pname]=nil\r
        advtrains.clear_driver_hud(pname)\r
        if clicker then\r
+               atprint("get_off: detaching",clicker:get_player_name())\r
                clicker:set_detach()\r
                clicker:set_eye_offset({x=0,y=0,z=0}, {x=0,y=0,z=0})\r
                local objpos=advtrains.round_vector_floor_y(self.object:getpos())\r
@@ -545,7 +608,47 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
                        end\r
                end\r
        end\r
+       uid=string.match(formname, "^advtrains_seating_(.+)$")\r
+       if uid then\r
+               for _,wagon in pairs(minetest.luaentities) do\r
+                       if wagon.is_wagon and wagon.initialized and wagon.unique_id==uid then\r
+                               local pname=player:get_player_name()\r
+                               local no=wagon:get_seatno(pname)\r
+                               if no then\r
+                                       if wagon.seat_groups then\r
+                                               wagon:seating_from_key_helper(pname, fields, no)\r
+                                       end\r
+                               end\r
+                       end\r
+               end\r
+       end\r
 end)\r
+function wagon:seating_from_key_helper(pname, fields, no)\r
+       local sgr=self.seats[no].group\r
+       for _,access in ipairs(self.seat_groups[sgr].access_to) do\r
+               if fields["sgr_"..access] and self:check_seat_group_access(pname, access) then\r
+                       for seatid, seatdef in ipairs(self.seats) do\r
+                               if seatdef.group==access and not self.seatp[seatid] then\r
+                                       self:get_on(minetest.get_player_by_name(pname), seatid)\r
+                                       return\r
+                               end\r
+                       end\r
+               end\r
+       end\r
+       if fields.inv and self.has_inventory and self.get_inventory_formspec then\r
+               minetest.show_formspec(player:get_player_name(), "advtrains_inv_"..self.unique_id, wagon:get_inventory_formspec(player:get_player_name()))\r
+       end\r
+       if fields.prop and self.owner==pname then\r
+               self:show_wagon_properties(pname)\r
+       end\r
+       if fields.off and (not self.seat_groups[sgr].require_doors_open or self:train().door_open~=0) then\r
+               self:get_off(no)\r
+       end\r
+end\r
+function wagon:check_seat_group_access(pname, sgr)\r
+       --TODO implement\r
+       return sgr~="driverstand" or pname=="orwell"\r
+end\r
 function wagon:reattach_all()\r
        if not self.seatp then self.seatp={} end\r
        for seatno, pname in pairs(self.seatp) do\r
index 6f00bf6..1fb6665 100644 (file)
@@ -1 +1,2 @@
-advtrains
\ No newline at end of file
+advtrains
+intllib?
\ No newline at end of file
index 8b13cfe..2eed2b1 100644 (file)
@@ -17,14 +17,23 @@ advtrains.register_wagon("engine_industrial", {
                        attach_offset={x=-5, y=10, z=-10},
                        view_offset={x=0, y=10, z=0},
                        driving_ctrl_access=true,
+                       group = "dstand",
                },
                {
                        name=S("Driver Stand (right)"),
                        attach_offset={x=5, y=10, z=-10},
                        view_offset={x=0, y=10, z=0},
                        driving_ctrl_access=true,
+                       group = "dstand",
                },
        },
+       seat_groups = {
+               dstand={
+                       name = "Driver Stand",
+                       access_to = {},
+               },
+       },
+       assign_to_seat_group = {"dstand"},
        visual_size = {x=1, y=1},
        wagon_span=2.6,
        is_locomotive=true,
index 6f00bf6..1fb6665 100644 (file)
@@ -1 +1,2 @@
-advtrains
\ No newline at end of file
+advtrains
+intllib?
\ No newline at end of file
index ad26fd1..ffe169f 100644 (file)
@@ -13,11 +13,49 @@ advtrains.register_wagon("engine_japan", {
        seats = {
                {
                        name=S("Driver stand"),
-                       attach_offset={x=0, y=10, z=0},
+                       attach_offset={x=0, y=8, z=13},
                        view_offset={x=0, y=0, z=0},
                        driving_ctrl_access=true,
+                       group="dstand",
+               },
+               {
+                       name="1",
+                       attach_offset={x=-4, y=8, z=0},
+                       view_offset={x=0, y=0, z=0},
+                       group="pass",
+               },
+               {
+                       name="2",
+                       attach_offset={x=4, y=8, z=0},
+                       view_offset={x=0, y=0, z=0},
+                       group="pass",
+               },
+               {
+                       name="3",
+                       attach_offset={x=-4, y=8, z=-8},
+                       view_offset={x=0, y=0, z=0},
+                       group="pass",
+               },
+               {
+                       name="4",
+                       attach_offset={x=4, y=8, z=-8},
+                       view_offset={x=0, y=0, z=0},
+                       group="pass",
                },
        },
+       seat_groups = {
+               dstand={
+                       name = "Driver Stand",
+                       access_to = {"pass"},
+                       require_doors_open=true,
+               },
+               pass={
+                       name = "Passenger area",
+                       access_to = {"dstand"},
+                       require_doors_open=true,
+               },
+       },
+       assign_to_seat_group = {"dstand", "pass"},
        doors={
                open={
                        [-1]={frames={x=0, y=20}, time=1},
@@ -42,11 +80,50 @@ advtrains.register_wagon("wagon_japan", {
        max_speed=20,
        seats = {
                {
-                       name=S("Default Seat"),
-                       attach_offset={x=0, y=10, z=0},
+                       name="1",
+                       attach_offset={x=-4, y=8, z=8},
+                       view_offset={x=0, y=0, z=0},
+                       group="pass",
+               },
+               {
+                       name="2",
+                       attach_offset={x=4, y=8, z=8},
+                       view_offset={x=0, y=0, z=0},
+                       group="pass",
+               },
+               {
+                       name="1a",
+                       attach_offset={x=-4, y=8, z=0},
+                       view_offset={x=0, y=0, z=0},
+                       group="pass",
+               },
+               {
+                       name="2a",
+                       attach_offset={x=4, y=8, z=0},
                        view_offset={x=0, y=0, z=0},
+                       group="pass",
+               },
+               {
+                       name="3",
+                       attach_offset={x=-4, y=8, z=-8},
+                       view_offset={x=0, y=0, z=0},
+                       group="pass",
+               },
+               {
+                       name="4",
+                       attach_offset={x=4, y=8, z=-8},
+                       view_offset={x=0, y=0, z=0},
+                       group="pass",
+               },
+       },
+       seat_groups = {
+               pass={
+                       name = "Passenger area",
+                       access_to = {},
+                       require_doors_open=true,
                },
        },
+       assign_to_seat_group = {"pass"},
        doors={
                open={
                        [-1]={frames={x=0, y=20}, time=1},
index 6f00bf6..1fb6665 100644 (file)
@@ -1 +1,2 @@
-advtrains
\ No newline at end of file
+advtrains
+intllib?
\ No newline at end of file
index ca366db..e489fd4 100644 (file)
@@ -17,14 +17,23 @@ advtrains.register_wagon("newlocomotive", {
                        attach_offset={x=-5, y=10, z=-10},
                        view_offset={x=0, y=6, z=0},
                        driving_ctrl_access=true,
+                       group = "dstand",
                },
                {
                        name=S("Driver Stand (right)"),
                        attach_offset={x=5, y=10, z=-10},
                        view_offset={x=0, y=6, z=0},
                        driving_ctrl_access=true,
+                       group = "dstand",
                },
        },
+       seat_groups = {
+               dstand={
+                       name = "Driver Stand",
+                       access_to = {},
+               },
+       },
+       assign_to_seat_group = {"dstand"},
        visual_size = {x=1, y=1},
        wagon_span=1.85,
        collisionbox = {-1.0,-0.5,-1.0, 1.0,2.5,1.0},
@@ -76,14 +85,23 @@ advtrains.register_wagon("detailed_steam_engine", {
                        attach_offset={x=-5, y=10, z=-10},
                        view_offset={x=0, y=6, z=0},
                        driving_ctrl_access=true,
+                       group = "dstand",
                },
                {
                        name=S("Driver Stand (right)"),
                        attach_offset={x=5, y=10, z=-10},
                        view_offset={x=0, y=6, z=0},
                        driving_ctrl_access=true,
+                       group = "dstand",
+               },
+       },
+       seat_groups = {
+               dstand={
+                       name = "Driver Stand",
+                       access_to = {},
                },
        },
+       assign_to_seat_group = {"dstand"},
        visual_size = {x=1, y=1},
        wagon_span=2.05,
        collisionbox = {-1.0,-0.5,-1.0, 1.0,2.5,1.0},
@@ -133,23 +151,34 @@ advtrains.register_wagon("wagon_default", {
                        name="1",
                        attach_offset={x=-4, y=8, z=8},
                        view_offset={x=0, y=0, z=0},
+                       group="pass",
                },
                {
                        name="2",
                        attach_offset={x=4, y=8, z=8},
                        view_offset={x=0, y=0, z=0},
+                       group="pass",
                },
                {
                        name="3",
                        attach_offset={x=-4, y=8, z=-8},
                        view_offset={x=0, y=0, z=0},
+                       group="pass",
                },
                {
                        name="4",
                        attach_offset={x=4, y=8, z=-8},
                        view_offset={x=0, y=0, z=0},
+                       group="pass",
+               },
+       },
+       seat_groups = {
+               pass={
+                       name = "Passenger area",
+                       access_to = {},
                },
        },
+       assign_to_seat_group = {"pass"},
        visual_size = {x=1, y=1},
        wagon_span=3.1,
        collisionbox = {-1.0,-0.5,-1.0, 1.0,2.5,1.0},
index 6f00bf6..1fb6665 100644 (file)
@@ -1 +1,2 @@
-advtrains
\ No newline at end of file
+advtrains
+intllib?
\ No newline at end of file
index 766081e..5625418 100644 (file)
@@ -12,12 +12,50 @@ advtrains.register_wagon("subway_wagon", {
        max_speed=15,
        seats = {
                {
-                       name="Default Seat (driver stand)",
+                       name="Driver stand",
                        attach_offset={x=0, y=10, z=0},
                        view_offset={x=0, y=0, z=0},
                        driving_ctrl_access=true,
+                       group="dstand",
+               },
+               {
+                       name="1",
+                       attach_offset={x=-4, y=8, z=8},
+                       view_offset={x=0, y=0, z=0},
+                       group="pass",
+               },
+               {
+                       name="2",
+                       attach_offset={x=4, y=8, z=8},
+                       view_offset={x=0, y=0, z=0},
+                       group="pass",
+               },
+               {
+                       name="3",
+                       attach_offset={x=-4, y=8, z=-8},
+                       view_offset={x=0, y=0, z=0},
+                       group="pass",
+               },
+               {
+                       name="4",
+                       attach_offset={x=4, y=8, z=-8},
+                       view_offset={x=0, y=0, z=0},
+                       group="pass",
+               },
+       },
+       seat_groups = {
+               dstand={
+                       name = "Driver Stand",
+                       access_to = {"pass"},
+                       require_doors_open=true,
+               },
+               pass={
+                       name = "Passenger area",
+                       access_to = {"dstand"},
+                       require_doors_open=true,
                },
        },
+       assign_to_seat_group = {"dstand", "pass"},
        doors={
                open={
                        [-1]={frames={x=0, y=20}, time=1},