Documentation

# 🛍️ Shops

# 🛒 Configuration des Shops

Cette section concerne les paramètres de configuration dans config.yml.

# ⚙️ Paramètres de Configuration

# 🕐 Fréquence de mise à jour

Cette option configure l'intervalle à laquelle les prix des articles dans les shops sont automatiquement mis à jour. La valeur par défaut est "15m" (15 minutes).

Le format accepte différentes unités de temps:

  • s pour secondes
  • m pour minutes
  • h pour heures

# 💡 Exemple d'utilisation

shops:
  # Intervalle de mise à jour des prix (format: 15m, 1h, etc.)
  # Contrôle la fréquence à laquelle les prix de tous les shops sont mis à jour
  price_update_interval: "15m"

À chaque intervalle, le système exécute la méthode pour tous les shops configurés, recalculant les prix selon les paramètres de prix dynamiques définis pour chaque article.

# 🔊 Sons de l'Interface

Les sons peuvent être configurés à deux niveaux :

  1. Globalement dans config.yml → s'applique à tous les shops
  2. Par shop/NPC dans le fichier de shop → surcharge les sons globaux

Hiérarchie de priorité : Configuration NPC > Configuration globale

Configuration globale (config.yml)

shops:
  sounds:
    open: BLOCK_CHEST_OPEN          # Son d'ouverture
    close: BLOCK_CHEST_CLOSE        # Son de fermeture
    purchase_success: ENTITY_PLAYER_LEVELUP  # Vente réussie
    purchase_fail: ENTITY_VILLAGER_NO        # Vente échouée
    page_change: UI_BUTTON_CLICK    # Changement de page
    volume: 1.0                     # Volume (0.0 - 1.0)
    pitch: 1.0                      # Tonalité (0.5 - 2.0)

Configuration par shop (fichier de shop)

Vous pouvez surcharger les sons pour un shop spécifique :

shop:
  Miner_Market:
    display_name: "&7Miner Market"
    # ... autres options ...
    gui:
      sounds:
        open: BLOCK_BARREL_OPEN
        close: BLOCK_BARREL_CLOSE
        purchase_success: ENTITY_VILLAGER_YES
        purchase_fail: ENTITY_VILLAGER_NO
        page_change: UI_BUTTON_CLICK
        volume: 0.8
        pitch: 1.2

💡 Astuce : Les sons par shop sont optionnels. Si non spécifiés, les sons globaux seront utilisés.

# 💬 Messages d'Interaction

messages:
  # Message lors d'une vente réussie (supporte {points} pour le montant)
  purchase_success: "&aVous avez gagné {points} points pour votre équipe!"
  # Message lors d'une vente échouée
  purchase_fail: "&cVous n'avez pas l'item requis!"

# 💡 Exemple complet

shops:
  price_update_interval: "15m"  # Intervalle de mise à jour des prix (s: secondes, m: minutes, h: heures)
  # Configuration des sons
  sounds:
    open: BLOCK_CHEST_OPEN        # Son d'ouverture du shop
    close: BLOCK_CHEST_CLOSE      # Son de fermeture du shop
    page_change: UI_BUTTON_CLICK  # Son lors du changement de page
    purchase_success: ENTITY_PLAYER_LEVELUP  # Son lors d'une vente réussie
    purchase_fail: ENTITY_VILLAGER_NO       # Son lors d'une vente échouée
    volume: 1.0                   # Volume des sons (entre 0.0 et 1.0)
    pitch: 1.0                    # Tonalité des sons (entre 0.5 et 2.0)
  # Messages personnalisables
  messages:
    purchase_success: "&aVous avez gagné {points} points pour votre équipe!"
    purchase_fail: "&cVous n'avez pas l'item requis!"
  # Mode de stockage des prix
  storage:
    type: "JSON"                  # Type de stockage: "JSON" ou "MYSQL"
    # Configuration MySQL (uniquement si type est "MYSQL")
    mysql:
      host: "localhost"
      port: 3306
      database: "horizons"
      username: "user"
      password: "password"
      table_prefix: "hz_"

# 💾 Système de Sauvegarde des Prix des shops

Le plugin Horizons propose deux méthodes de stockage pour les prix des shops permettant une persistance des prix après rechargement du plugin.

📄 Stockage JSON

  • Les prix sont sauvegardés dans des fichiers JSON dans le dossier plugins/Horizons/data/shop_prices/
  • Chaque shop a son propre fichier (ex: example_shop::Forgeron.json)
  • Avantages: simple, pas de dépendance externe
  • Configuration par défaut, ne nécessite aucune configuration supplémentaire

🗃️ Stockage MySQL (optionnel)

  • Les prix sont sauvegardés dans une base de données MySQL
  • Idéal pour les serveurs multi-instances ou avec beaucoup de shops
  • Nécessite une configuration dans la section shops.storage.mysql
  • Les tables sont créées automatiquement lors du premier démarrage
  • Permet une synchronisation des prix en temps réel entre plusieurs serveurs

⏱️ Les prix sont automatiquement sauvegardés:

  • À intervalles réguliers (configurable via price_update_interval)
  • Lors de la désactivation du plugin
  • Lors du rechargement des configurations

Pour changer le mode de stockage, modifiez simplement shops.storage.type dans la configuration principale.

# 🎮 Interactions avec les Shops

Les shop gèrent les interactions suivantes :

  • 🖱️ Clic gauche sur un item : Vend une unité de cet item au prix actuel.
  • 🖱️ Clic droit sur un item : Vend tous les items du même type dans l'inventaire du joueur.
  • 🔄 Clic sur une flèche : Permet de naviguer entre les pages du shop.
    • ⬅️ Flèche gauche (emplacement 45) : Page précédente.
    • ➡️ Flèche droite (emplacement 53) : Page suivante.

# 💰 Format d'Affichage des Prix

Les prix sont affichés dans l'interface avec une tendance indiquant leur évolution :

  • 📈 Augmentation :
  • 📉 Diminution :
  • ➡️ Stable :

# 🏪 Association avec les NPCs

Les shops sont automatiquement associés à des NPCs FancyNPCs par leur ID. Lorsqu'un joueur fait un clic droit sur un NPC :

  1. 🎵 Le son configuré est joué.
  2. 🛍️ Le shop correspondant s'ouvre automatiquement.
  3. 📦 L'interface s'affiche avec les items disponibles.

# 🎯 Modes de Trigger

Le plugin propose deux modes pour ouvrir un shop : via NPC ou via commande.

# Mode NPC (par défaut)

C'est le comportement classique : un NPC FancyNpcs est créé aux coordonnées spécifiées et le shop s'ouvre au clic.

shop:
  Shop_Keeper:
    # trigger.type: "npc"  # optionnel, c'est la valeur par défaut
    display_name: "&6&lShop Keeper"
    entity_type: VILLAGER
    Position:
      world: world
      x: 0
      y: 64
      z: 0
    gui_title: "&6General Store"
    items:
      # ...

# Mode Command

Ce mode permet d'ouvrir un shop sans créer de NPC. Idéal pour l'intégration avec d'autres plugins de NPC ou autres plugins (menus customs, blocs interactifs, etc.)

shop:
  Remote_Shop:
    trigger:
      type: "command"  # Pas de NPC créé
    display_name: "&d&lRemote Shop"
    gui_title: "§d§lRemote Shop"
    gui:
      rows: 3
    # Note: Position non requise en mode "command"
    # entity_type non requis non plus
    items:
      DIAMOND:
        pricing:
          type: STATIC
          base_price: 100

# Ouverture via Commande

La commande pour ouvrir un shop est réservée à la console ou aux administrateurs (permission horizons.admin).

/horizons shop open <joueur> <shopId>

Exemple :

/horizons shop open Notch example_shop::Remote_Shop

⚠️ Sécurité : Les joueurs normaux ne peuvent PAS utiliser cette commande, même avec des permissions shop. Cela permet aux autres plugins d'exécuter la commande via console sans risque.

Intégration avec d'autres plugins :

💡 Pour l'API Java complète, voir la documentation API.

# 📝 Structure des Shops

Les shops sont configurés dans des fichiers YAML situés dans le dossier plugins/Horizons/shops/. Chaque fichier représente une ou plusieurs boutiques avec un ou plusieurs NPCs.

# 🏪 Configuration des NPCs

shop:
  ID_DU_VENDEUR: #Peut être un nombre ou du texte
    display_name: '&6&lNom du vendeur'
    entity_type: VILLAGER
    profession: ARMORER
    villager_type: PLAINS
    Position:
      world: world
      x: 0
      y: 64
      z: 0
    gui_title: '&6Nom du GUI'
    items:
      DIAMOND_SWORD:
        pricing:
          type: STATIC
          base_price: 500
      NETHERITE_CHESTPLATE:
        pricing:
          type: STATIC
          base_price: 2000
      DIAMOND_PICKAXE:
        pricing:
          type: DYNAMIC
          base_price: 300
          min_price: 150
          max_price: 600
          adjustment:
            type: SUPPLY_DEMAND
            demand_multiplier: 0.15
            supply_threshold: 50
            cooldown_rate: 0.03
      GOLDEN_APPLE:
        quantity: 8
        pricing:
          type: DYNAMIC
          base_price: 120
          min_price: 80
          max_price: 250
          adjustment:
            type: FIXED_PERCENTAGE
            change_rate: 0.05
            supply_threshold: 30
      ENCHANTED_GOLDEN_APPLE:
        pricing:
          type: DYNAMIC
          base_price: 1500
          min_price: 1000
          max_price: 3000
          adjustment:
            type: SUPPLY_DEMAND
            demand_multiplier: 0.2
            supply_threshold: 10
            cooldown_rate: 0.02
      IRON_INGOT:
        pricing:
          type: TIERED
          base_price: 50
          tiers:
            tier2:
              threshold: 100
              price: 45
            tier3:
              threshold: 500
              price: 40
            tier4:
              threshold: 1000
              price: 35

# ⚙ Configuration des NPCs

Options Disponibles

Paramètre Description Obligatoire
display_name Nom affiché du NPC (supporte les codes couleur) Oui
entity_type Type d'entité (VILLAGER, PLAYER, etc.) Oui
Position Section contenant les coordonnées Oui
gui_title Titre de l'interface du shop Oui

Types d'Entités Spécifiques

Villageois

shop:
  Forgeron:
    display_name: "&c&lForgeron"
    entity_type: "VILLAGER"
    profession: "WEAPONSMITH"  # Type de métier
    villager_type: "PLAINS"    # Type de biome

Professions disponibles : ARMORER, BUTCHER, CARTOGRAPHER, CLERIC, FARMER, FISHERMAN, FLETCHER, LEATHERWORKER, LIBRARIAN, MASON, NITWIT, NONE, SHEPHERD, TOOLSMITH, WEAPONSMITH.

Types de villageois : DESERT, JUNGLE, PLAINS, SAVANNA, SNOW, SWAMP, TAIGA.

Joueur avec Skin

shop:
  Trader:
    display_name: "&6&lTrader Elite"
    entity_type: "PLAYER"
    skin_name: "Notch"  # Nom du skin à utiliser

# 🎨 Configuration de l'Interface (GUI)

Les shops peuvent avoir une interface entièrement personnalisable. Si non spécifié, une configuration par défaut est utilisée.

# 📊 Hiérarchie de Priorité

La configuration GUI suit une hiérarchie de 3 niveaux. Le système cherche chaque paramètre dans cet ordre :

Priorité Source Chemin
1 (Plus haute) Configuration NPC shop.NPC_ID.gui.*
2 Defaults du fichier shop.gui_default.*
3 Defaults globaux config.ymlshops.gui_defaults.*
4 (Fallback) Valeurs codées en dur Voir tableau ci-dessous

💡 Astuce : Vous pouvez définir des defaults dans config.yml pour tous les shops, puis les surcharger au niveau fichier ou NPC.

# 📦 Valeurs par Défaut (Fallback)

Si aucune configuration n'est trouvée, ces valeurs sont utilisées :

Paramètre Valeur par défaut
rows 6
layout.items.slots Slots 10-16, 19-25, 28-34, 37-43 (7 colonnes × 4 lignes au centre)
layout.pagination.previous.slot 45
layout.pagination.next.slot 53
layout.border.item.material BLACK_STAINED_GLASS_PANE
layout.border.item.name (espace)

# 🔧 Structure Complète

shop:
  # ════════════════════════════════════════════════════
  # DEFAULTS DU FICHIER (Optionnel)
  # S'applique à tous les NPCs de ce fichier
  # ════════════════════════════════════════════════════
  gui_default:
    rows: 4
    layout:
      border:
        item:
          material: BLUE_STAINED_GLASS_PANE
      items:
        slots: [10, 11, 12, 13, 14, 15, 16]
      pagination:
        previous:
          slot: 27
        next:
          slot: 35

  # ════════════════════════════════════════════════════
  # CONFIGURATION SPÉCIFIQUE AU NPC
  # Surcharge les defaults du fichier et globaux
  # ════════════════════════════════════════════════════
  Shop_Keeper:
    display_name: "&6&lShop Keeper"
    entity_type: VILLAGER
    # ... autres options ...
    
    gui:
      # Nombre de lignes de l'inventaire (1-6)
      rows: 6
      
      layout:
        # ─────────────────────────────────────────────
        # BORDURE
        # ─────────────────────────────────────────────
        border:
          # Option 1: Remplissage intelligent (2 slots = début et fin)
          # Remplit automatiquement tous les slots sauf items et pagination
          slots: [0, 53]
          
          # Option 2: Liste explicite de slots
          # slots: [0, 1, 2, 3, 4, 5, 6, 7, 8, 45, 46, 47, 48, 49, 50, 51, 52, 53]
          
          item:
            material: BLACK_STAINED_GLASS_PANE
            name: " "
            # lore: [] # Optionnel
            
        # ─────────────────────────────────────────────
        # SLOTS D'ITEMS À VENDRE
        # ─────────────────────────────────────────────
        items:
          slots:
            - 10
            - 11
            - 12
            - 13
            - 14
            - 15
            - 16
            # ... etc
          # Ou en ligne: slots: [10, 11, 12, 13, 14, 15, 16]
          
        # ─────────────────────────────────────────────
        # PAGINATION
        # ─────────────────────────────────────────────
        pagination:
          previous:
            # Un seul slot
            slot: 45
            # OU plusieurs slots (tous cliquables)
            # slots: [45, 46]
            item:
              material: ARROW
              name: "&6<< Page précédente"
              
          next:
            slot: 53
            # slots: [52, 53]
            item:
              material: ARROW
              name: "&6Page suivante >>"

# 📐 Cas de Figures et Exemples

# Cas 1: Shop Minimal (utilise tous les defaults)

shop:
  Simple_Vendor:
    display_name: "&aVendeur"
    entity_type: VILLAGER
    Position:
      world: world
      x: 100
      y: 64
      z: 200
    gui_title: "&aShop"
    items:
      DIAMOND:
        pricing:
          type: STATIC
          base_price: 100

Résultat : GUI de 6 lignes, bordure noire, items au centre, pagination en bas.


# Cas 2: Petit Shop (3 lignes)

shop:
  Mini_Shop:
    display_name: "&eMini Shop"
    entity_type: VILLAGER
    Position:
      world: world
      x: 100
      y: 64
      z: 200
    gui_title: "&ePetit Shop"
    gui:
      rows: 3
      layout:
        items:
          slots: [10, 11, 12, 13, 14, 15, 16]  # Ligne du milieu uniquement
        pagination:
          previous:
            slot: 18  # En bas à gauche
          next:
            slot: 26  # En bas à droite
    items:
      DIAMOND:
        pricing:
          type: STATIC
          base_price: 100

# Cas 3: Shop avec Layout Custom (style grille espacée)

shop:
  Miner_Market:
    display_name: "&8&lMiner Market"
    entity_type: PLAYER
    skin_name: "Notch"
    Position:
      world: world
      x: 100
      y: 64
      z: 200
    gui_title: "&8Miner Market"
    gui:
      rows: 5
      layout:
        border:
          slots: [0, 44]  # Remplissage auto
          item:
            material: GRAY_STAINED_GLASS_PANE
        items:
          # Grille espacée 3x3 au centre
          slots: [11, 13, 15, 20, 22, 24, 29, 31, 33]
        pagination:
          previous:
            slot: 36
          next:
            slot: 44
    items:
      COAL:
        quantity: 64
        pricing:
          type: STATIC
          base_price: 5

# Cas 4: Defaults au niveau fichier

shop:
  # Tous les NPCs de ce fichier héritent de cette config
  gui_default:
    rows: 4
    layout:
      border:
        item:
          material: PURPLE_STAINED_GLASS_PANE
      items:
        slots: [10, 11, 12, 13, 14, 15, 16]

  # Ce NPC utilise les defaults du fichier
  Vendor_1:
    display_name: "&5Vendeur 1"
    # ... pas de section gui: → utilise gui_default

  # Ce NPC surcharge certains paramètres
  Vendor_2:
    display_name: "&5Vendeur 2"
    gui:
      rows: 6  # Surcharge seulement rows
      # layout hérite de gui_default

# Cas 5: Configuration globale dans config.yml

# Dans config.yml
shops:
  gui_defaults:
    rows: 6
    layout:
      items:
        slots: [10, 11, 12, 13, 14, 15, 16, 19, 20, 21, 22, 23, 24, 25]
      border:
        item:
          material: BLACK_STAINED_GLASS_PANE
      pagination:
        previous:
          slot: 45
        next:
          slot: 53

Note : Cette configuration s'applique à TOUS les shops du serveur, sauf s'ils ont leur propre configuration.

# ⚠️ Points Importants

  1. Les slots d'items sont exclusifs : Un slot ne peut pas être à la fois un slot d'item ET un slot de pagination.
  2. Le remplissage de bordure est intelligent : Avec slots: [0, 53], le système remplit tous les slots SAUF ceux définis pour les items et la pagination.
  3. La pagination est optionnelle : Si vous avez peu d'items (tous tiennent sur une page), les flèches n'apparaîtront pas.

# 🖼️ Format d'Affichage des Items

Vous pouvez personnaliser comment les items sont affichés dans le shop (nom et description).

shop:
  Shop_Keeper:
    # ...
    display:
      name_format: "&6%name%" # Format du nom de l'item
      
      lore_formats:
        # Format par défaut
        default:
          - "&7Prix actuel: &2%price% %currency% %trend%"
          - "&7Quantité requise: &c%amount%"
          - "&7Clique gauche: &7&l>> &6Vendre %amount_click_left% item(s)"
          - "&7Clique droit: &7&l>> &6Vendre le maximum possible"
        
        # Format spécifique pour les items TIERED (optionnel)
        tiered:
          - "&7Prix actuel: &2%price% %currency% %trend%"
          - "&7Palier actuel: &6Tier %tier%"
          - "&7Quantité: &c%amount%"

Placeholders Disponibles :

  • %name% : Nom de l'item
  • %price% : Prix actuel
  • %currency% : Nom de la monnaie (ex: Emeralds)
  • %trend% : Flèche de tendance (↑, ↓, →)
  • %tier% : Numéro du palier actuel (pour les items TIERED)
  • %amount% : Quantité vendue par transaction
  • %amount_click_left% : Quantité vendue au clic gauche

# ⚙ Configuration des Items

Chaque item du shop est configuré dans la section items avec l'identifiant Minecraft de l'item comme clé.

# Système de Prix

Le plugin supporte plusieurs modes de tarification définis par le paramètre type dans la section pricing.

# 1. Prix Statique (STATIC)

Le prix ne change jamais. Il reste fixé au base_price défini.

items:
  DIAMOND:
    pricing:
      type: "STATIC"
      base_price: 100          # Prix fixe

# 2. Prix Dynamique (SUPPLY_DEMAND / FIXED_PERCENTAGE)

Utilise le type DYNAMIC et une stratégie d'ajustement.

items:
  BREAD:
    pricing:
      type: "DYNAMIC"
      base_price: 50           # Prix de base
      min_price: 25            # Prix minimum
      max_price: 100           # Prix maximum
      adjustment:
        type: "SUPPLY_DEMAND"
        demand_multiplier: 0.15  # Multiplicateur de demande
        supply_threshold: 50     # Seuil de fourniture
        cooldown_rate: 0.05      # Taux de récupération

# 3. Prix par Paliers (TIERED)

Ce mode permet de définir des prix fixes qui évoluent selon le volume total cumulé des ventes de l'objet.

  • Le prix est déterminé par des paliers (tiers) de ventes cumulées.
  • Le base_price est utilisé tant que le premier palier n'est pas atteint (équivalent à un seuil de 0).
  • Les prix changent immédiatement au franchissement d'un palier (ce mode ignore l'intervalle de rafraîchissement global).

Paramètres spécifiques :

  • tiers: Section contenant la liste des paliers.
    • threshold: Nombre de ventes total requis pour atteindre ce palier.
    • price: Prix appliqué à partir de ce seuil.
items:
  GOLD_INGOT:
    pricing:
      type: "TIERED"
      base_price: 200.0 # Prix initial (pour 0 à 99 ventes)
      tiers:
        tier1:
          threshold: 100 # À partir de 100 ventes cumulées
          price: 150.0
        tier2:
          threshold: 500 # À partir de 500 ventes cumulées
          price: 100.0

# Fonctionnement des Prix Dynamiques

# Mode SUPPLY_DEMAND (Offre et Demande)

  • Les prix diminuent à mesure que les joueurs vendent des items (demande élevée)
  • Le calcul des prix est basé sur la formule : priceChange = -demandMultiplier * (salesCount/supplyThreshold)^1.5
  • Plus le nombre de ventes (salesCount) s'approche ou dépasse le seuil (supplyThreshold), plus la baisse est importante
  • Le taux de baisse dépend du demand_multiplier et du nombre d'achats par rapport au supply_threshold
  • Quand aucun achat n'est effectué, les prix remontent lentement selon le cooldown_rate

# Mode FIXED_PERCENTAGE (Pourcentage Fixe)

  • Les prix augmentent régulièrement selon le change_rate si peu de ventes sont effectués
  • Quand les ventes dépassent le supply_threshold, les prix diminuent proportionnellement selon la formule : priceChange = -changeRate * (salesCount/supplyThreshold)^1.2
  • La diminution s'intensifie de manière exponentielle lorsque le nombre de ventes dépasse largement le seuil

# 🔢 Système de quantités

# ⚙ Configuration des quantités

Chaque item dans un shop peut avoir une quantité configurée qui détermine combien d'items sont vendus par transaction.

items:
  NETHERITE_INGOT:
    quantity: 5
    pricing:
      type: "STATIC"
      base_price: 1000          

# 🤖 Fonctionnement des quantités

🖱️ Clic gauche (Vente de quantité configurée)

  • Vend exactement la quantité configurée d'items
  • Le prix affiché est pour la quantité complète
  • Exemple : avec quantity: 5 et un prix de vente à 1000, un clic gauche vend 5 items pour 1000 points

🖱️ Clic droit (Vente maximale)

  • Vend le maximum possible en multiples de la quantité configurée
  • Le prix est multiplié par le nombre de sets vendus
  • Exemple : avec 12 items, quantity: 4, et un prix de vente à 1000 → vend 3 sets (12 items) pour 3000 points

# 🎯 Scope des Prix (GLOBAL / PER_TEAM)

Le plugin permet de configurer si les prix sont partagés globalement ou calculés séparément par équipe.

# Modes disponibles

Mode Description
GLOBAL Tous les joueurs voient le même prix. Les ventes de tous les joueurs affectent le même pool de prix. (Par défaut)
PER_TEAM Chaque équipe a son propre marché indépendant. Les ventes d'une équipe n'affectent pas les prix des autres équipes.

# Hiérarchie de priorité

Le scope est déterminé selon cette priorité (du plus prioritaire au moins prioritaire) :

  1. Niveau Item → Défini dans la section pricing de l'item
  2. Niveau Shop → Défini dans la configuration du NPC/shop
  3. Niveau Global → Défini dans config.yml sous shops.price_scope

# Configuration

# Niveau Global (config.yml)

shops:
  price_scope: "GLOBAL"  # ou "PER_TEAM"

# Niveau Shop

shop:
  Forgeron:
    display_name: "&6&lForgeron"
    price_scope: "PER_TEAM"  # Tous les items de ce shop utilisent PER_TEAM
    items:
      DIAMOND:
        pricing:
          type: DYNAMIC
          base_price: 100

# Niveau Item

shop:
  Marchand:
    display_name: "&2&lMarchand"
    price_scope: "GLOBAL"  # Par défaut pour ce shop
    items:
      DIAMOND:
        pricing:
          type: DYNAMIC
          base_price: 100
          price_scope: "PER_TEAM"  # Override: cet item est PER_TEAM
      IRON_INGOT:
        pricing:
          type: STATIC
          base_price: 50
          # Hérite du shop = GLOBAL

# Exemple d'utilisation

Scénario : Compétition entre équipes

Avec price_scope: "PER_TEAM", chaque équipe gère son propre marché :

  • L'équipe Rouge vend beaucoup de diamants → Le prix baisse uniquement pour l'équipe Rouge
  • L'équipe Bleue n'a pas vendu de diamants → Le prix reste élevé pour l'équipe Bleue

Cela permet de créer des stratégies économiques où chaque équipe doit gérer son propre marché !

# 🔄 Système de Rotation

Le système de rotation permet de modifier automatiquement les items disponibles dans un shop selon un emploi du temps précis.

# 🎯 Fonctionnalités Clés

  • Planification Horaire : Définissez des plages horaires précises (ex: 14h00 à 18h00).
  • Récurrence Quotidienne : Créez des événements qui se répètent tous les jours.
  • Dates Spécifiques : Programmez des événements uniques pour des dates précises (ex: Nouvel An).
  • Filtres de Jours : Limitez les événements récurrents à certains jours (ex: Week-end uniquement).

# ⚙️ Configuration

shop:
  Daily_Deals:
    display_name: "&6&lOffres du Jour"
    # ... config standard ...
    
    rotation:
      enabled: true
      notify_players: true
      notification_message: "&e[Shop] &7Les offres ont changé!"
      
      sets:
        # EXEMPLE 1: Récurrence Quotidienne
        morning_coffee:
          start_time: "06:00"  # Format HH:mm
          end_time: "10:00"
          items:
            MILK_BUCKET:
              pricing:
                type: STATIC
                base_price: 5
                
        # EXEMPLE 2: Jours Spécifiques (Week-end)
        weekend_special:
          start_time: "00:00"
          end_time: "23:59"
          days: [SATURDAY, SUNDAY]
          items:
            DIAMOND_SWORD:
              pricing:
                type: STATIC
                base_price: 500
                
        # EXEMPLE 3: Date Absolue (Prioritaire)
        special_event:
          start_time: "2026-05-01 10:00" # Format yyyy-MM-dd HH:mm
          end_time: "2026-05-01 22:00"
          items:
            ENCHANTED_GOLDEN_APPLE:
              quantity: 2
              pricing:
                type: STATIC
                base_price: 50

# 📋 Options de Configuration

Vous pouvez personnaliser le comportement global de la rotation pour chaque shop :

Option Description Valeur par défaut
enabled Active ou désactive le système de rotation pour ce shop. false
notify_players Si true, envoie un message à tous les joueurs lors d'un changement d'items. false
notification_message Le message à envoyer. Supporte les couleurs &. "&e[Shop] &7New items available!"

# 📋 Règles de Fonctionnement

  1. Logique "Est-ce l'heure ?" : Le plugin vérifie chaque minute si l'un des sets correspond à l'heure actuelle.
  2. Priorité : Si plusieurs sets peuvent être actifs en même temps (ex: un set "Tous les jours" et un set "Lundi"), le premier défini dans le fichier prend la priorité.
  3. Inactivité : Si aucun set ne correspond à l'heure actuelle, le shop n'affichera aucun item de rotation.

# 📅 Formats de Temps

Type Format Exemple Description
Récurrent HH:mm 14:30 S'active tous les jours à cette heure.
Absolu yyyy-MM-dd HH:mm 2026-12-25 08:00 S'active une seule fois à cette date précise.

# 📅 Filtre de Jours (days)

Vous pouvez ajouter une liste days pour restreindre un horaire récurrent à des jours spécifiques.

Valeurs acceptées (Anglais) : MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY.

happy_hour_tuesdays:
  start_time: "18:00"
  end_time: "19:00"
  days: [TUESDAY]

# 💾 Persistance

Le système est conçu pour être robuste :

  • Il vérifie l'heure système réelle (pas de décalage si le serveur lag).
  • Il se recalibre automatiquement après un redémarrage.
  • Si vous changez la config et faites /horizons reload, la mise à jour est immédiate.