Redstone [solo] aliments périssable

The_MurmeX

In the beginning was a cookie...
4 Juin 2014
173
16
75
Bonjour tout le monde,

Aujourd'hui c'est sur la demande de Yazzup que je vous présente un tutoriel sur la construction détaillée d'un système de péremption des aliments en blocs de commandes, en différenciant chaque pièce récoltée. Celui ci fonctionne pour tout les aliments mais doit être répété autant de fois qu'il y a d'aliments périssables dans votre map. Il fonctionne uniquement en solo.
Bien, voici comment va se dérouler le tuto :
1.Fonctionnement précis du système
a.présentation
b.commandes préalables
2.Récupération d'un aliment
a.commandes
b.explications
3.Détection de la péremption
a.commandes
b.explications
4.Le joueur mange un aliment
a.commandes
b.explications
5.Bugs et solutions

Comme vous le voyez, mes titres sont d'une grandes originalité et chacun est travaillé avec soin.... :D
Passons donc au tuto.

1.Fonctionnement précis du système

a.présentation

Globalement, le système ressemble à ça :
1434198815-vue-globale.png

Les parties rose, noire et blanche ne font pas a proprement parler partie du système : c'est à elles que nous nous intéresseront dans la partie b.
Vous remarquerez que le système n'utilise aucune fill clock parce que j'aime pas ça ce n'est pas nécessaire à part pour calculer la date de péremption au 1/20eme de seconde près.
En utilisant l’exemple du pain (comme dans tout le reste du tutoriel), si un joueur ramasse un pain avec un certain data tag, il se transformera au bout d'un temps déterminé en un autre pain portant la mention "Expired !" et qui donne poison une fois mangé. A vrai dire, le système que je vous présente bug lorsque 2 actions (ramassage, ingestion, péremption) ont lieu en même temps. Pour éviter ces bugs, il est possible de choisir une clock plus rapide (générant plus de lag) tout en gardant l'ordre d'execution des commandes -bonne chance :p - ou bien de rajouter un degug que je rajouterai -si j'en ai la foi- à la fin du tuto.

b.commandes préalables

Il est nécessaire de lancer plusieurs commandes avant la construction du système pour que tout fonctionne. Dans un premier temps :
Code:
/scoreboard objectives add ExpiryBread dummy
Code:
/scoreboard objectives add PickupBread dummy
Code:
/scoreboard objectives add EatBread stat.useItem.minecraft.bread
NOTE : La dernière commande finira par stat.useItem.minecraft.apple pour une pomme ou stat.useItem.minecraft.cooked_fish pour du poisson cuit par exemple.

Ensuite :
Code:
/scoreboard players set NbrActuel PickupBread 0
Code:
/scoreboard players set NbrAvant PickupBread 0
Code:
/scoreboard players set NbrActuel ExpiryBread 0
Code:
/scoreboard players set NbrAvant ExpiryBread 0
Code:
/scoreboard players set Stock ExpiryBread 0

Pour give le pain qui périra :
Code:
/give @p bread 1 0 {perishable:1}
Pour invoquer un mob qui le lootera :
Code:
/summon Creeper ~ ~1 ~ {Equipment:[{id:bread,Count:1,tag:{perishable:1}}],DropChances:[1.0f]}

2.Récupération d'un aliment

a.commandes

Ici nous ne nous intéressons qu'aux parties jaune et rouge. La numérotation des commandes correspond à l'ordre dans lequel elles s’exécutent.

1434200861-partie-1.png


Code:
1  clear @p bread 0 0 {perishable:1}
2  scoreboard players operation NbrAvant PickupBread -= NbrActuel PickupBread
3  blockdata ~2 ~-1 ~ {TransferCooldown:0}
4  scoreboard players operation @p PickupBread -= NbrAvant PickupBread
5  scoreboard players operation NbrAvant PickupBread = NbrActuel PickupBread

Après avoir construit cette partie il faut exécuter cette commande une fois :
Code:
/stats block <xA> <yA> <zA> set AffectedItems NbrActuel PickupBread
Note : Remplacez <xA> <yA> <zA> par les coordonnée du bloc noté A sur la photo.

Ensuite, fabriquons un morceau de la partie rouge:
1434202054-partie-4-comp-clock.png


Code:
1  execute @a[score_PickupBread_min=1] ~ ~ ~ summon Item <xC> <yC> <zC> {Item:{Count:1,id:wooden_sword},Age:0}
2  execute @a[score_PickupBread_min=1] ~ ~ ~ scoreboard players remove @p PickupBread 1
Note : Après "Age:" mettez 6000-le temps de validité de vos aliment en tick (1/20 de seconde). Avec 0 ça fait donc 5 minutes. Le minium pour cette valeur est -32766 ce qui porte le temps à environ 32 minutes.
Note 2 : Remplacez <xC> <yC> <zC> par les coordonnées du bloc d'air situé au dessus du bloc C.

b.explications

Cette partie à pour but de summon un Item en C à chaque fois que le joueur ramasse un item.
Ainsi en 1, grace au /stats, on stock dans la scoreboard PickupBread du joueur (factice) NbrActuel le nombre de pains "perishable" que porte le joueur.
En 2 on soustrait ce nombre au nombre obtenu lors de la précédente impulsion et on stock le résultat dans NbrAvant. Ce nombre et normalement de 0 mais quand le joueur ramasse du pain il diminue, à l'inverse, lorsqu'il drop du pain, il augmente.
En 4 (on parlera du 3 plus tard), on soustrait le nombre obtenu au score PickupBread du joueur qui prendra ensuite le résultat. Le score du joueur augmente à chaque fois qu'il ramasse un pain et rediminue quand il en jette un.
En 5, on met le score PickupBread de NbrActuel à la place de celui NbrAvant pour pouvoir recommencer le cycle.
Le 3 sert simplement à accélérer la hopper clock grâce à un blockdata.

Dans la partie comparator clock, à chaque cycle :
-Si le joueur à un score PickupBread > 0 on summon un item non stackable en C qui disparaitra dans un certain temps.
-Si le joueur à un score PickupBread >0 on lui réduit ce score de 1.

C'est compliqué ? Et bien c'est pas fini comme dirait orange ! :p Passons à la deuxième partie du système.

3.Détection de la péremption

a.commandes

Passons donc à la partie bleu :
1434206101-partie-2.png


Code:
1  testfor @e[<xC>,yC>,<zC>,2,type=Item]
2  scoreboard players operation NbrAvant ExpiryBread -= NbrActuel ExpiryBread
3  scoreboard players operation Stock ExpiryBread = NbrAvant ExpiryBrea
4  scoreboard players test Stock ExpiryBread 1 1000
5  scoreboard players operation NbrAvant ExpiryBread = NbrActuel ExpiryBread
6  scoreboard players operation @p ExpiryBread += Stock ExpiryBread
7  blockdata ~-2 ~ ~-1 {SuccessCount:0}
Note : Dans le testfor, remplacez <xC>,yC>,<zC> par vos coordonnées du bloc au dessus de C séparées par des virgules.

Ensuite, dans le chat faites :
Code:
/stats block <xB> <yB> <zB> set AffectedEntities NbrActuel ExpiryBread
NOTE : Remplacez <xB> <yB> <zB> par les coordonnées B.

Maintenant vous pouvez compléter la parties rouge :
1434201592-partie-4.png


Code:
3  clear @a[score_ExpiryBread_min=1] bread 0 1 {perishable:1}
4  give @a[score_ExpiryBread_min=1] bread 1 0 {display:{Lore:["Expired !"]},perishable:0}
5  execute @a[score_ExpiryBread_min=1] ~ ~ ~ scoreboard players add @p PickupBread 1
6  execute @a[score_ExpiryBread_min=1] ~ ~ ~ scoreboard players remove @p ExpiryBread 1

b.explications

Dans la hopper clock, notre but est de détecter quand un ou plusieurs des items disparaissent pour remplacer un ou plusieurs pains "sains" par des pains périmés dans l'inventaire du joueur.
En 1, on teste combien d'item sont présent en C. Le /stats stocke le résultat dans le score ExpiryBread de NbrActuel.
En 2, on soustrait le score ExpiryBread de NbrActuel à celui de NbrAvant. Le résultat va dans NbrAvant. Si un item après le résultat sera négatif, s'y un Item disparait il sera positif. Sinon il sera nul.
En 3, on met le résultat dans le score ExpiryBread de Stock.
En 4, on test si ce score est supérieur à 0 (un Item à disparu).
En 5, la scoreboard ExpiryBread de NbrAvant prend la valeur de NbrActuel pour le prochain cycle.
Si Le test fait en 4 à fonctionné alors:
-En 6, le score ExpiryBread du joueur prend la valeur de Stock
-En 7, un entitydata ordonne au 4 de cesser d'envoyer un signal.

Dans la comparator clock :
-En 3, on enlève un pain "sain" au joueur si il a un score ExpiryBread supérieur à 0.
-En 4, on lui donne le pain périmé si il a un score ExpiryBread supérieur à 0.
-En 5, on lui ajoute 1 à son score PickupBread pour éviter que cela soit considéré comme un drop. Toujours si il a un score ExpiryBread supérieur à 0.
-Enfin en 6, si il a un score ExpiryBread supérieur à 0, alors on lui diminue ce score de 1.

Votre cerveau et en bouillie ? Ça tombe bien on a fini l'échauffement ! :D
Non plus sérieusement, ce qui suit est le plus simple.

4.Le joueur mange un aliment

a.commandes

Cette fois-ci nous ne nous intéresseront qu'à la partie verte. Le bloc de commande n°4 est situé sous le n°1 :
1434364852-partie-3.png


Code:
1  blockdata ~ ~ ~-2 {TransferCooldown:0}
2  execute @p[score_EatBread=3,score_EatBread_min=3] ~ ~ ~ setblock <z> <y> <z> redstone_block
3  execute @p[score_EatBread=1,score_EatBread_min=1,score_PickupBread=-1] ~ ~ ~ scoreboard players add @p PickupBread 1
4  execute @p[score_EatBread=1,score_EatBread_min=1] ~ ~ ~ scoreboard players remove @p ExpiryBread 1
5  scoreboard players set @p EatBread 0
6  scoreboard players add @p EatBread 2 {SelectedItem:{id:"minecraft:bread",tag:{display:{Lore:[0:"Expired !"]}}}}

b.explications

Cette partie gère le moment où le joueur mange un pain. Si c'est un pain périmé, elle donne un effet au joueur, sinon elle informe le reste de la machine que le pain n'a pas été droppé et que le prochain item qui disparaitra ne causera pas de péremption (on considère que le joueur mange le pain le plus proche de l'expiration).
On va utiliser ici un ordre peu conventionnel :
En 4, le score EatBread du joueur passe à 0
En 5, si il tient un pain périmé, ce score est remonté à 2
Le tick d'après :
En 2, si le score EatBread est de 3, c'est que le joueur tenait un pain périmé et qu'il l'a mangé: on met un block au coordonnée x y z de la partie violette où on lui attribuera les effets voulus.
En 3, si son score EatBread est de 1, il a mangé un pain sain, donc son score PickupBread est normalement -voir la partie consacrée aux bugs- à -1 : on le réaugmente .
En 4, toujours si son score est de 1, on lui diminue son score ExpiryBread pour que la prochaine disparition d'item n'ai pas d'effet.
Le 1 accélère simplement la clock.

Voilà, on à terminé ! ;) Enfin presque parce que tel quel le système est plein de bugs :D : nous allons voir comment les fixer.

5.Bugs et solutions

Je mettrai ici tous les bugs que je trouverai ou que vous me signalerez -je compte sur vous ;) - ainsi que les solutions appropriées s'il y en a.

a.Le drop des aliments juste avant leur péremption

Si l'on drop un aliment et qu'il périme pendant qu'il est par terre, vous recevrez l'aliment périmé et un aliment sera impérissable.
Une solution est de désactiver le drop d'item grâce à une fill clock qui active la commande suivante :
Code:
/entitydata @e[type=Item] {PickupDelay:0}

b.Ramasser un pain en même temps qu'on en mange un

Cela cause théoriquement un bug, cependant je ne l'ai jamais constaté et je ne vois pas comment le fixer. Je continu de chercher. (Utiliser une fill clock plutôt qu'une hopper clock devrait rendre le problème négligeable mais je ne peux pas le faire avec les "performances" de mon ordi :D )

Ce sont les seuls bug répertorier pour le moment, j'espère que vous vous êtes bien amusé à comprendre et à reproduire le système :p. Si vous avez des problèmes, des bugs, des faute à me faire corriger ou si vous voulez me suggérer une solution à un bug ou une amélioration, faites-le dans les commentaires.

Bonne journée ;)
 
  • J'aime
Reactions: Bakkare