Trains
La Station de train, le Signal de train et l'Observateur de train de Create : le train à quai, son planning, où il peut aller, l'assemblage, et les signaux de la ligne.
Un ordinateur posé près d'une Station de train de Create sait quel train est à quai, lequel arrive, et où il pourrait aller depuis là. Il renomme les trains, lit et écrit leurs plannings, les assemble ou les démonte. Les Signaux de train et les Observateurs de train lui racontent ce qui se passe le long de la ligne. Avec eux, un programme fait tourner un dépôt, un tableau des arrivées ou tout un service de trains.
local gare = peripheral.find("station")
if gare.train_present() then
print(gare.train_name() .. " est à quai à " .. gare.name())
endstation.name() | Le nom de la station, tel qu'il est écrit dans son interface. |
station.set_name(name) | Renomme la station, comme si vous tapiez le nom dans son interface. |
station.train_present() | Vrai quand un train s'est arrêté à cette station. |
station.train_imminent() | Vrai quand le train qui vient ici est à moins de 30 blocs par les rails, ou déjà à quai : le moment de faire sonner une cloche ou d'allumer une lampe au bord du quai. |
station.train_enroute() | Vrai dès qu'un train a cette station pour prochain arrêt, aussi loin soit-il. La réponse reste vraie tant que le train est à quai, et redevient fausse quand il repart. |
station.train_name() | Le nom du train arrêté à la station. Arrête le programme avec there is no train present quand le quai est vide : un programme qui veut le nom d'un train qui vient de partir doit le garder dans une variable. |
station.set_train_name(name) | Renomme le train arrêté à la station. Tous les joueurs voient le nouveau nom aussitôt. |
station.has_schedule() | Si le train arrêté à la station suit un planning. |
station.schedule() | Le planning du train arrêté à la station. Arrête le programme avec train doesn't have a schedule quand il n'en a pas. |
station.set_schedule(schedule) | Donne un planning au train arrêté à la station. Il remplace celui que le train avait, et le train le commence aussitôt, par sa première entrée (ou par l'entrée que désigne une clé progress, comptée à partir de 0, quand la table en a une). |
station.can_reach(name) | Si le train arrêté à la station peut rejoindre une station qui correspond à name. |
station.distance_to(name) | La distance que parcourrait le train arrêté à la station pour rejoindre une station qui correspond à name. |
station.assembling() | Si la station est en mode assemblage. Pendant ce temps, aucun train planifié ne vient à elle. |
station.set_assembly_mode(on) | Entre en mode assemblage, ou en sort. |
station.assemble() | Assemble le train posé dans la zone d'assemblage de la station, puis sort du mode assemblage : le nouveau train est prêt à partir. |
station.disassemble() | Démonte le train arrêté à quai, en blocs posés sur le rail. |
sig.state() | Le feu que montre le signal en ce moment. |
sig.forced_red() | Si le signal est tenu au rouge, quoi que fassent les trains. |
sig.set_forced_red(red) | Tient le signal au rouge, comme le ferait un signal de redstone : les trains attendent devant lui. |
sig.blocking_trains() | Les trains dans la section qui suit le signal : ceux qu'attend un train arrêté au feu rouge. |
sig.signal_type() | La sorte de signal : |
sig.cycle_signal_type() | Fait passer le signal à l'autre sorte, comme le fait la Clé de Create. |
obs.train_passing() | Si un train passe en ce moment. L'observateur reste allumé quelques ticks après le dernier wagon : en demandant toutes les 0,2 seconde, aucun train ne vous échappe. |
obs.passing_train() | Le nom du train qui passe, ou nil quand aucun ne passe. |
Installation
Trois blocs. La Station de train est un périphérique de type station, le Signal de train de type signal, l'Observateur de train de type track_observer. Posez-en un contre une face de l'ordinateur, ou contre un Câble de données de son réseau (à partir du Mini-ordinateur, il s'appelle alors comme station@120,64,-35), puis prenez-le : peripheral.wrap("left"), ou peripheral.find("station"). Voir Périphériques.
Sur un rail. Une station ou un signal ne fonctionne qu'une fois posé contre un rail, comme Create le pose (clic droit sur le rail avec le bloc d'abord). Sinon, la station arrête le programme avec station is not connected to a track, et le signal avec no signal: place it against a track.
Les trains sont partagés. Un train appartient à tout le serveur : un nom ou un planning changé par un programme est vu aussitôt par tous les joueurs et par toutes les autres stations.
Le train à quai. Beaucoup de méthodes agissent sur le train arrêté à la station. Quand il n'y en a pas, elles arrêtent le programme avec there is no train present : demandez d'abord train_present().
Pas d'évènements : demandez en boucle. Les périphériques ComputerCraft de Create envoient des évènements (train_arrival, train_passing...). Brass n'a pas d'évènements de périphériques : un programme redemande sans cesse, avec un court sleep entre deux questions. Une demi-seconde suffit largement pour des trains.
local gare = peripheral.find("station")
while not gare.train_present() do
sleep(0.5)
end
print(gare.train_name() .. " est arrivé")Pour faire autre chose pendant ce temps, voyez la boucle principale. Quand un bloc est cassé, ses méthodes arrêtent le programme avec station removed, signal removed ou track observer removed, et avec peripheral is not loaded quand son chunk n'est pas chargé.
La station
station.name()
Le nom de la station, tel qu'il est écrit dans son interface.
- string
- le nom de la station
local gare = peripheral.find("station")
print("Bienvenue à " .. gare.name())Voir aussi station.set_name()
station.set_name(name)
Renomme la station, comme si vous tapiez le nom dans son interface.
namestring- le nouveau nom, coupé à 64 caractères
Les plannings désignent leurs stations par leur nom : un train dont le planning demande l'ancien nom ne trouvera plus la station. Une station qui n'est pas sur un rail ne peut pas être renommée : le programme s'arrête avec could not set station name.
Voir aussi station.name()
station.train_present()
Vrai quand un train s'est arrêté à cette station.
- boolean
- vrai tant qu'un train est arrêté à quai
Un train qui passe sans s'arrêter ne compte pas : surveillez-le plutôt avec un Observateur de train.
Voir aussi station.train_imminent() station.train_enroute() station.train_name()
station.train_imminent()
Vrai quand le train qui vient ici est à moins de 30 blocs par les rails, ou déjà à quai : le moment de faire sonner une cloche ou d'allumer une lampe au bord du quai.
- boolean
- vrai quand un train va arriver, ou est déjà à quai
local gare = peripheral.find("station")
while true do
rs.set("top", gare.train_imminent()) -- une lampe au-dessus de l'ordinateur
sleep(0.5)
endVoir aussi station.train_present()
station.train_enroute()
Vrai dès qu'un train a cette station pour prochain arrêt, aussi loin soit-il. La réponse reste vraie tant que le train est à quai, et redevient fausse quand il repart.
- boolean
- vrai quand un train est en route vers cette station, ou à quai
Les trois questions répondent vrai l'une après l'autre : train_enroute, puis train_imminent, puis train_present.
Voir aussi station.train_present()
station.train_name()
Le nom du train arrêté à la station. Arrête le programme avec there is no train present quand le quai est vide : un programme qui veut le nom d'un train qui vient de partir doit le garder dans une variable.
- string
- le nom du train à quai
Voir aussi station.set_train_name()
station.set_train_name(name)
Renomme le train arrêté à la station. Tous les joueurs voient le nouveau nom aussitôt.
namestring- le nouveau nom, coupé à 64 caractères
local gare = peripheral.find("station")
if gare.train_present() then
gare.set_train_name("Express du fer")
endVoir aussi station.train_name()
Plannings
Un train suit son planning, celui écrit dans un Planning de train : une liste d'arrêts, chacun avec les conditions à attendre avant de repartir. Un programme le lit sous forme de table, et en donne un nouveau au train à quai. La table a la forme des données de planning de Create, avec leurs clés en snake_case (la même forme que le périphérique ComputerCraft de Create) :
local planning = {
cyclic = true,
entries = {
{
instruction = {id = "create:destination", data = {text = "Mine de fer"}},
conditions = {
{ {id = "create:delay", data = {value = 20, time_unit = 1}} },
},
},
{
instruction = {id = "create:destination", data = {text = "Fonderie"}},
conditions = {
{ {id = "create:idle", data = {value = 5, time_unit = 1}} },
},
},
},
}cyclic:truerecommence à la première entrée après la dernière ;falsearrête le train après elle.entries: les étapes, dans l'ordre. Chacune a uneinstruction,{id =, data =}.conditions, pour une destination : une liste de groupes de conditions. Le train repart dès qu'un groupe est rempli, et un groupe est rempli quand ses conditions le sont, l'une après l'autre. L'interface de Create montre chaque groupe comme une colonne. Même une condition seule est dans son propre groupe :{ {condition} }. Un arrêt sans aucune condition y garde le train pour de bon.
Les instructions et conditions courantes :
| id | ce qu'elle fait | data |
|---|---|---|
create:destination | aller à une station (* permis dans le nom) | text : le nom de la station |
create:rename | changer le titre du planning, le texte que montrent les affichages | text : le nouveau titre |
create:throttle | limiter la vitesse maximale du train | value : en pourcentage |
create:delay | condition : attendre un moment | value, et time_unit : 0 ticks, 1 secondes, 2 minutes |
create:idle | condition : la cargaison n'a pas bougé depuis un moment | value, time_unit |
create:powered | condition : la station reçoit de la redstone | aucune |
Pour toutes les autres, réglez-les dans un Planning de train en jeu, donnez-le à un train, et regardez ce que renvoie schedule().
station.has_schedule()
Si le train arrêté à la station suit un planning.
- boolean
- vrai quand le train à quai a un planning
local gare = peripheral.find("station")
if gare.train_present() and not gare.has_schedule() then
print(gare.train_name() .. " n'a pas de planning")
endUn train garde son planning une fois qu'il l'a fini (un planning qui n'est pas cyclique arrête le train, il ne disparaît pas).
Voir aussi station.schedule()
Le planning du train arrêté à la station. Arrête le programme avec train doesn't have a schedule quand il n'en a pas.
- table
- le planning du train à quai, de la forme décrite plus haut
Lister les arrêts :
local gare = peripheral.find("station")
local planning = gare.schedule()
for i, etape in ipairs(planning.entries) do
if etape.instruction.id == "create:destination" then
print(i .. ". " .. etape.instruction.data.text)
end
endVoir aussi station.set_schedule() station.has_schedule()
Donne un planning au train arrêté à la station. Il remplace celui que le train avait, et le train le commence aussitôt, par sa première entrée (ou par l'entrée que désigne une clé progress, comptée à partir de 0, quand la table en a une).
scheduletable- un planning de la même forme que celui que renvoie
schedule()
La table compte 4096 valeurs au plus, sur 16 niveaux. Sans aucune entrée, le programme s'arrête avec a schedule needs at least one entry. Quand le train n'avait pas de planning, le nouveau se comporte comme un planning donné par une station : un joueur qui le retire du train ne récupère pas de Planning de train.
local gare = peripheral.find("station")
local planning = gare.schedule()
planning.cyclic = false -- encore un tour, puis arrêt
gare.set_schedule(planning)Voir aussi station.schedule()
Où le train peut-il aller ?
Avant d'envoyer un train, un programme peut demander s'il peut seulement arriver : une station renommée, un rail cassé ou un signal manquant suffisent à couper une ligne. Ces deux méthodes regardent toutes les stations du réseau de rails du train dont le nom correspond à un filtre :
*remplace n'importe quel texte, même vide :"Mine*"correspond àMine,Mine 2etMine nord;?remplace exactement un caractère :"Quai ?"correspond àQuai 1jusqu'àQuai 9, pas àQuai 10;- tout le reste doit être identique, majuscules comprises. Un filtre fait 64 caractères au plus.
Les deux répondent pour le train arrêté à quai (sinon there is no train present), selon la façon dont la navigation de Create le conduirait : un train qui ne roule qu'en marche avant peut ne pas rejoindre une station qu'un autre train atteindrait. C'est la recherche dans le réseau qui les rend coûteuses.
Si le train arrêté à la station peut rejoindre une station qui correspond à name.
namestring- le nom d'une station,
*et?permis
- boolean
- vrai quand le train à quai peut rejoindre une station de ce nom
local gare = peripheral.find("station")
if gare.can_reach("Mine de fer") then
print("la ligne de la mine est ouverte")
else
print("aucun chemin vers la mine d'ici")
endVoir aussi station.distance_to()
La distance que parcourrait le train arrêté à la station pour rejoindre une station qui correspond à name.
namestring- le nom d'une station,
*et?permis
- number|nil
- la distance en blocs par les rails, arrondie à 0,01, ou nil quand aucune station de ce nom n'est accessible
Quand plusieurs stations correspondent, c'est la distance jusqu'à celle que choisirait la navigation, en général la plus proche.
local gare = peripheral.find("station")
local d = gare.distance_to("Carrière*")
if d then
print("carrière la plus proche : " .. math.floor(d) .. " blocs")
endVoir aussi station.can_reach()
Assembler les trains
En mode assemblage, une station transforme les bogies et les blocs collés posés sur son rail en un train, et démonte un train en blocs. Ces méthodes font ce que font les boutons de l'interface de la station.
Comme un joueur qui clique sur ces boutons, une station change une fois par tick au plus : un deuxième set_assembly_mode, assemble ou disassemble sur la même station dans le même tick arrête le programme avec the station already changed this tick: sleep(0) waits for the next. Mettez un sleep(0) entre deux d'entre eux.
station.assembling()
Si la station est en mode assemblage. Pendant ce temps, aucun train planifié ne vient à elle.
- boolean
- vrai tant que la station est en mode assemblage
Voir aussi station.set_assembly_mode()
Entre en mode assemblage, ou en sort.
onboolean- true pour entrer en mode assemblage, false pour en sortir
Y entrer avec un train à quai démonte ce train, comme disassemble(). Demander le mode dans lequel la station est déjà arrête le programme, avec failed to enter assembly mode ou failed to exit assembly mode : demandez d'abord assembling().
Voir aussi station.assembling() station.assemble()
Assemble le train posé dans la zone d'assemblage de la station, puis sort du mode assemblage : le nouveau train est prêt à partir.
local gare = peripheral.find("station")
if not gare.assembling() then
gare.set_assembly_mode(true)
sleep(0) -- un changement par tick
end
gare.assemble()
print(gare.train_name() .. " est prêt")Hors du mode assemblage, elle arrête le programme avec station must be in assembly mode. Quand Create refuse d'assembler (pas de Contrôles de train, un bogie qui manque...), elle s'arrête avec failed to assemble train : l'interface de la station dit pourquoi.
Voir aussi station.set_assembly_mode() station.disassemble()
Démonte le train arrêté à quai, en blocs posés sur le rail.
La station est ensuite en mode assemblage : appelez assemble() pour remonter le train, ou set_assembly_mode(false) pour rouvrir la station aux trains. Un Planning de train qu'un joueur avait donné au train tombe à la station. Erreurs : station must not be in assembly mode, there is no train present, et could not disassemble train quand Create n'y arrive pas.
Voir aussi station.assemble()
Signal de train
Un Signal de train découpe la voie en sections, et ne laisse un train entrer dans la section qui le suit que si elle est libre. Un programme lit son feu, voit quels trains occupent la section, et peut le garder au rouge.
sig.state()
Le feu que montre le signal en ce moment.
- string
"red","yellow","green"ou"invalid"
"yellow" n'apparaît que sur un signal de croisement : certaines sorties de sa section sont libres, d'autres non. "invalid" (le feu clignote en jeu) veut dire que le signal n'est pas sur un rail, ou qu'il ne sépare pas deux sections, comme sur une boucle sans autre signal.
local sig = peripheral.find("signal")
if sig.state() == "red" then
print("la section suivante est occupée")
endVoir aussi signal.blocking_trains()
sig.forced_red()
Si le signal est tenu au rouge, quoi que fassent les trains.
- boolean
- vrai quand le signal est forcé au rouge, par un programme ou par la redstone
Voir aussi signal.set_forced_red()
sig.set_forced_red(red)
Tient le signal au rouge, comme le ferait un signal de redstone : les trains attendent devant lui.
redboolean- true pour tenir le signal au rouge, false pour le libérer
Le changement se fait à la fin du tick du programme. La redstone garde le dernier mot : quand un bloc voisin du signal change, le signal suit de nouveau son entrée de redstone. Ne mettez pas de redstone autour d'un signal qu'un programme pilote.
local sig = peripheral.find("signal")
sig.set_forced_red(true) -- travaux sur la ligne
sleep(120)
sig.set_forced_red(false)Voir aussi signal.forced_red()
sig.blocking_trains()
Les trains dans la section qui suit le signal : ceux qu'attend un train arrêté au feu rouge.
- table
- les noms des trains dans la section que garde le signal, une liste vide quand elle est libre
local sig = peripheral.find("signal")
for _, nom in ipairs(sig.blocking_trains()) do
print(nom .. " bloque le passage")
endVoir aussi signal.state()
sig.signal_type()
La sorte de signal :
- string
"entry_signal"ou"cross_signal"
"entry_signal"(signal d'entrée) laisse entrer un train quand la section est inoccupée ;"cross_signal"(signal de croisement) ne laisse entrer un train que s'il peut traverser toute la section, pour qu'aucun train ne s'arrête au milieu d'un aiguillage ou d'un croisement.
Voir aussi signal.cycle_signal_type()
sig.cycle_signal_type()
Fait passer le signal à l'autre sorte, comme le fait la Clé de Create.
Voir aussi signal.signal_type()
Observateur de train
Un Observateur de train surveille un point de la voie et donne un signal de redstone pendant qu'un train passe. Quand un objet est réglé dans son filtre, seuls les trains qui transportent cette cargaison comptent.
obs.train_passing()
Si un train passe en ce moment. L'observateur reste allumé quelques ticks après le dernier wagon : en demandant toutes les 0,2 seconde, aucun train ne vous échappe.
- boolean
- vrai pendant qu'un train passe au point surveillé
Voir aussi track_observer.passing_train()
obs.passing_train()
Le nom du train qui passe, ou nil quand aucun ne passe.
- string|nil
- le nom du train qui passe, ou nil
Compter les trains d'une ligne :
local obs = peripheral.find("track_observer")
local compte = 0
local avant = false
while true do
local maintenant = obs.train_passing()
if maintenant and not avant then
compte = compte + 1
print(compte .. " : " .. (obs.passing_train() or "un train"))
end
avant = maintenant
sleep(0.2)
endVoir aussi track_observer.train_passing()
Exemples
Un tableau des arrivées
Un ordinateur sur le quai, sans moniteur : son propre écran annonce chaque train. L'heure vient de l'horloge du monde (os.day_time()).
local gare = peripheral.find("station")
local dernier_train = "Le train"
local function heure()
local t = (os.day_time() + 6000) % 24000
return string.format("%02d:%02d", t // 1000, t % 1000 * 60 // 1000)
end
local function situation()
if gare.train_present() then return "a_quai" end
if gare.train_imminent() then return "imminent" end
if gare.train_enroute() then return "en_route" end
return "vide"
end
term.clear()
term.set_cursor(1, 1)
print(gare.name())
local avant = "vide"
while true do
local maintenant = situation()
if maintenant ~= avant then
if avant == "a_quai" then
print(heure() .. " " .. dernier_train .. " est parti")
end
if maintenant == "a_quai" then
dernier_train = gare.train_name()
print(heure() .. " " .. dernier_train .. " est à quai")
elseif maintenant == "imminent" then
print(heure() .. " arrivée : éloignez-vous du bord")
elseif maintenant == "en_route" then
print(heure() .. " un train est en route")
end
avant = maintenant
end
sleep(0.5)
endLe nom du train est gardé dans dernier_train tant qu'il est à quai : une fois parti, train_name() arrêterait le programme.
Un dépôt qui n'envoie les trains que là où ils peuvent aller
Chaque train qui s'arrête au dépôt reçoit un nouveau planning : un aller vers la mine suivante, à tour de rôle, puis le retour au dépôt. Une mine dont la ligne est coupée est sautée, et quand aucune mine n'est accessible, le train attend au dépôt qu'une le redevienne.
local gare = peripheral.find("station")
local DEPOT = gare.name()
local MINES = {"Mine de fer", "Mine de charbon", "Carrière*"}
local tour = 1
-- un arrêt : aller à une station, y attendre quelques secondes
local function arret(station, secondes)
return {
instruction = {id = "create:destination", data = {text = station}},
conditions = {
{ {id = "create:delay", data = {value = secondes, time_unit = 1}} },
},
}
end
-- la prochaine mine que le train à quai peut rejoindre, ou nil
local function mine_suivante()
for i = 1, #MINES do
local mine = MINES[tour]
tour = tour % #MINES + 1
if gare.can_reach(mine) then
return mine
end
end
return nil
end
local servi = false
while true do
if not gare.train_present() then
servi = false
elseif not servi then
local mine = mine_suivante()
if mine then
local blocs = math.floor(gare.distance_to(mine))
gare.set_schedule({cyclic = false, entries = {arret(mine, 30), arret(DEPOT, 5)}})
print(gare.train_name() .. " part pour " .. mine .. ", " .. blocs .. " blocs")
servi = true
end
end
sleep(2)
endservi retient que le train à quai a reçu ses ordres, pour qu'il ne les reçoive qu'une fois. Quand il revient de la mine, il s'arrête de nouveau au dépôt et le programme l'envoie à la mine suivante. Un train sans mine accessible est redemandé toutes les deux secondes : un can_reach coûte 64 instructions, un tiers d'un tick de Calculateur à tubes, ne le demandez donc pas à chaque tick.