Shops
Visão geral
O Shops permite que os jogadores comprem e vendam itens por um menu de inventário que você monta no painel web do TypeWriter. Uma loja é uma única entry Shop Definition: ela guarda a lista de itens à venda, seus preços, a moeda, os limites, as mensagens e o layout do menu. O jogador a abre com /tw shop <id> ou por meio de uma ação Open Shop disparada por uma quest, um NPC ou um botão de outro menu.
Cada item tem o preço definido de uma de três formas: um preço fixo, um preço dinâmico que acompanha o estoque ou escambo, em que o item é pago com outros itens em vez de dinheiro. Compras e vendas passam pelo Vault, por uma economia do PlaceholderAPI ou por um saldo de pontos embutido.
O menu em si é desenhado com a extensão GUI. Você coloca marcadores em um layout onde os produtos aparecem (SHOP_ITEM) e botões marcados para paginação, fechamento e quantidades, e o Shops os preenche para cada jogador.
Recursos
- Preços fixos, dinâmicos e em itens — um preço fixo por unidade, um preço que sobe conforme o estoque cai ou uma lista de itens a entregar.
- Escambo —
priceModeITEMSvende um artigo em troca de um ou vários itens, com um preço padrão para toda a loja e o token de lore{item_price}. - Três moedas —
VAULT,PLACEHOLDER(saldo lido de um placeholder do PlaceholderAPI e alterado com comandos de console) e um saldoPOINTSembutido. - Ações de clique e quantidades — compre ou venda 1, uma pilha, o máximo, tudo, uma quantidade personalizada a partir de um diálogo ou uma quantidade fixa como 10 em um submenu.
- Estoque, limites e resets — estoque por item, limites por jogador e globais, tetos de compra e venda para toda a loja e resets por cron, intervalo, diário, semanal ou mensal.
- Impostos e promoções — um imposto global, substituições de imposto por item e descontos percentuais com prazo.
- Menu no painel — pool de layouts, submenu, item de preenchimento, lore de preço e formatos padrão de nome e lore.
- Aba de um menu compartilhado — uma loja pode se tornar uma view de um chassi GUI maior por meio de
baseMenuId. - Comandos de admin — liste, inspecione, abra, redefina, edite o estoque e leia o histórico de transações.
- Anúncios no Discord — as transações são anunciadas como um evento que a extensão Discord repassa a um webhook.
Instalação
- Instale a extensão GUI (versão 0.17 ou mais recente) e o TypeWriter em um servidor Paper ou Folia.
- Opcional, para a moeda
VAULT: instale o Vault e um plugin de economia que se registre nele. - Opcional, para placeholders em títulos e lore e para a moeda
PLACEHOLDER: instale o PlaceholderAPI. - Baixe o JAR do Shops nas releases do GitHub (o botão no painel de resumo acima), coloque-o em
plugins/Typewriter/extensions/e reinicie o servidor. - No painel web, crie uma entry Shop Artifact e chame-a de
shop_artifact. O Shops lê e grava seu estoque, limites e pontos por meio dessa entry.
Primeiros passos
Monte uma pequena loja de armas paga com dinheiro do Vault:
- Em uma page static, adicione uma entry Shop Artifact chamada
shop_artifact. - Adicione uma entry Shop Definition. Defina
titlecomo<gold>Weapons,rowscomo3ecurrencycomoVAULT. - Em
items, adicione um item. Escolha uma espada de diamante emitem, definanamecomo<aqua>Sword,priceModecomoFIXED,fixedBuyPricecomo500efixedSellPricecomo100. DeixeprimaryActionemBUY_1esecondaryActionemSELL_1. - Em
layoutPool, adicione um layoutsimplecom oidmaine escrevamainemmainLayoutId. Adicione a ele um item combuttonPrefixshop_button:,buttonTypeSHOP_ITEM,x1,y1,count7 edirectionright. Essa linha de marcadores é onde os produtos aparecem. - Adicione mais três itens ao layout com
buttonPrefixshop_button:ebuttonTypedefinido comoPREV_PAGE,NEXT_PAGEeCLOSE, colocados na linha inferior. Dê a cada um umiteme umdisplayName. - Defina
fillerItemcomo um painel de vidro colorido cinza para que os slots não usados sejam preenchidos. - Publique e depois execute
/tw shop admin listno jogo para ler o id da loja e abra-a com/tw shop <id>. Para abri-la a partir de uma quest ou de um NPC, adicione uma ação Open Shop apontando para a loja.
O clique esquerdo compra uma espada, o clique direito vende uma e shift + clique esquerdo abre o submenu de compra, se você configurou um.
Uma loja mostra tantos produtos por página quantos slots de marcador SHOP_ITEM ela tiver, e os botões de paginação percorrem o restante. Se não existir nenhum marcador, o menu abre sem produto algum.
Como funciona
Ao abrir, a loja verifica seus criteria de acesso, aplica um reset pendente e então monta o menu para aquele jogador. Um clique envia a ação ao tratador de transações, que verifica os limites, calcula o preço com promoções e imposto, cobra o pagamento, entrega o item e registra o estoque, os contadores de limite e o histórico.
Menus
Layout e botões
Um menu de loja é um layout simple no layoutPool da Shop Definition, selecionado por mainLayoutId. Os itens do layout carregam um buttonPrefix de shop_button: e um buttonType:
buttonType | Função |
|---|---|
SHOP_ITEM | Um slot onde um produto é colocado. Repita-o com count, direction, gap e repeatY. O prefixo pode ficar vazio para este marcador. |
NEXT_PAGE, PREV_PAGE | Percorrem as páginas de produtos. |
INFO | Envia as linhas de infoMessage. |
CLOSE | Fecha o menu. |
BACK | Volta ao menu anterior, por exemplo a partir de um submenu. |
BUY_1, SELL_1 | Compram ou vendem uma unidade. Em um submenu, BUY_1:10 e SELL_1:10 negociam 10 unidades; qualquer número funciona. |
BUY_STACK, SELL_STACK | Negociam uma pilha completa do item. |
BUY_MAX, SELL_ALL | Compram o máximo possível ou vendem tudo o que corresponde. |
BUY_CUSTOM, SELL_CUSTOM | Pedem ao jogador uma quantidade em um diálogo. |
BUY_SUBMENU, SELL_SUBMENU | Abrem o submenu do item. |
Os botões diferentes de SHOP_ITEM, NEXT_PAGE, PREV_PAGE, INFO, CLOSE e BACK agem sobre o item que o jogador selecionou, portanto pertencem ao layout do submenu. Defina sempre o buttonPrefix como shop_button:: o prefixo padrão pertence a outra extensão e o botão ficaria inerte.
Submenu
Crie um segundo layout simple no pool, coloque nele os botões de quantidade e escreva o id dele em subMenuLayoutId. O título vem de subMenuTitle, em que {item_name} é o name do item. Os itens o abrem com as ações BUY_SUBMENU e SELL_SUBMENU, que são o shift + clique padrão.
Ações de clique
Cada item tem três slots de ação:
| Campo | Padrão | Clique padrão |
|---|---|---|
primaryAction | BUY_1 | Clique esquerdo |
secondaryAction | SELL_1 | Clique direito |
shiftAction | BUY_SUBMENU | Shift + clique esquerdo |
As ações possíveis são NONE, BUY_1, SELL_1, BUY_STACK, SELL_STACK, BUY_MAX, SELL_ALL, BUY_SUBMENU, SELL_SUBMENU, BUY_CUSTOM e SELL_CUSTOM. O interactionConfig de toda a loja decide qual clique dispara cada ação (comprar 1, vender 1, comprar pilha, vender tudo, submenu, quantidade personalizada, navegação). Cada tipo de clique só pode executar uma ação por item, então, com a configuração padrão, várias ações mapeadas para o clique esquerdo se substituem entre si: altere interactionConfig se você usar mais de três ações.
buyMaxEnabled desativa BUY_MAX para um item.
Diálogo de quantidade
BUY_CUSTOM e SELL_CUSTOM abrem um diálogo com um campo de texto. Personalize-o com buyAmountPrompt, sellAmountPrompt, amountConfirmButton, amountInputLabel, amountInputPlaceholder, amountInputWidth e amountInputMaxLength. A resposta deve ser um número inteiro positivo; caso contrário, invalidAmountMessage é enviada. As verificações normais de preço, limite e saldo são executadas quando a quantidade é confirmada.
Exibição dos itens
As linhas de priceLore são acrescentadas a cada produto, depois da lore do próprio item e do seu lore. defaultNameFormat e defaultLoreFormat valem para itens sem name ou lore próprios. Nesses campos e no name e lore de um item, os tokens a seguir são substituídos; uma linha que pede um preço inexistente é descartada.
| Token | Substituído por |
|---|---|
{item} | O nome do próprio item. |
{buy}, {sell} | Preço unitário formatado. Descartado quando o item não pode ser comprado ou vendido, quando o preço é zero e em itens de escambo. |
{item_price} | O preço em itens, uma linha por item solicitado, como - 12 × Copper Ingot (texto definido por itemPriceLineFormat). Descartado em itens que não são pagos em itens. |
{stock}, {stock_max} | Estoque atual e máximo. |
{currency} | O currencySymbol. |
priceFormat molda o preço exibido: {amount} é o número com duas casas decimais e {currency} é o símbolo.
Preços e economia
Modos de preço. FIXED usa fixedBuyPrice e fixedSellPrice. DYNAMIC usa dynamicPricing: o preço começa em price (e sellPrice para vendas) quando o estoque está cheio e se move em direção a max conforme o estoque cai, em passos de step de stockMax, limitado por min e max e arredondado para rounding. ITEMS é o escambo.
Escambo. Com priceMode ITEMS, liste o custo no itemPrice do item, ou uma única vez para toda a loja em defaultItemPrice. Cada linha é um item e uma amount por unidade comprada. Várias linhas são todas exigidas ao mesmo tempo, e comprar várias unidades multiplica cada linha. A lista própria de um artigo substitui a lista da loja, nunca é somada a ela. Um item sem preço em lugar nenhum é recusado e registrado no log, nunca entregue de graça. O pagamento é verificado em todo o inventário antes de qualquer coisa ser removida, o espaço para o item comprado é verificado primeiro, e os itens de catálogo são comparados por identidade e não apenas por material. BUY_MAX compra tantas unidades quantas o inventário puder pagar. Um item de escambo não pode ser revendido por dinheiro. Os itens que faltam são informados com cannotAffordItemsMessage, em que {missing} os lista e {amount} é a quantidade.
Moedas.
currency | Comportamento |
|---|---|
VAULT | Usa a economia registrada no Vault. Exige o plugin Vault e um provedor. |
PLACEHOLDER | Lê o saldo de balancePlaceholder e o altera executando addCommand e removeCommand pelo console, onde {player} e {amount} são substituídos. Os três devem ser definidos. Números como 1,250.5 e 12.5k são compreendidos. |
POINTS | Um saldo mantido pelo Shops em seu artifact. Começa em 0 e cresce quando os jogadores vendem itens; a release não tem comando para conceder pontos. |
Impostos. taxRate é uma porcentagem acrescentada às compras e subtraída das vendas. Com taxMode PER_ITEM, o taxRateOverride de um item (0 ou mais) o substitui para esse item; -1 mantém a taxa da loja.
Promoções. Uma Shop Promotion dá um desconto percentual no preço de compra e na recompensa de venda de uma loja, para todos os itens ou para os targetItemIndices listados (posição em items, a partir de 0).
Estoque, limites e resets
dynamicPricing.stockMaxdefine o estoque de um item. Ele começa cheio, diminui quando os jogadores compram e aumenta quando vendem.0significa sem controle de estoque. ComperPlayerativado, cada jogador tem o seu próprio estoque de cada item; um reset reabastece o de todos. Enquanto uma loja está aberta,defaultRefreshTicks(e orefreshTicksde um item) fazem com que ela seja redesenhada quando o estoque exibido muda, de modo que se vejam as compras de outros jogadores. OguiSlotde um item o fixa em um slot específico, esellAllEnableddesativa a ação de vender tudo. Detalhes em Shop Definition.playerLimiteglobalLimitlimitam quantas unidades de um item um jogador, ou todos juntos, podem comprar por ciclo de reset.globalPlayerLimit,globalBuyLimiteglobalSellLimitlimitam a loja inteira;0significa ilimitado.limitReachedMessageé enviada quando um limite é atingido.resetrestaura o estoque e limpa os contadores de limite. As políticas sãonone,cron(uma expressão como0 0 * * *),interval(segundos),daily,weekly(o dia 1 é segunda-feira) emonthly. Os horários usam o fuso horário do servidor. A primeira verificação de um ciclo acontece quando a loja é aberta, e uma verificação também é executada a cada minuto.criteriarestringe o acesso à loja e enviacriteriaFailMessagequando não correspondem. Um item cujos próprioscriterianão correspondem é exibido comolockedIteme não pode ser comprado.
Comandos
Subcomandos de /typewriter, normalmente digitado como /tw.
| Comando | Descrição |
|---|---|
/tw shop <shop> | Abre uma loja para você. Exige typewriter.shop.open. |
/tw shop admin | Lista os comandos de admin. Exige typewriter.shop.admin. |
/tw shop admin list | Lista as lojas carregadas com id, nome, número de itens e número de pools. |
/tw shop admin info <shop> | Mostra a definição de uma loja e seus itens com o índice. |
/tw shop admin open <shop> [target] | Abre uma loja para um jogador. |
/tw shop admin refresh [target] | Redesenha a loja aberta de um jogador. |
/tw shop admin close [target] | Fecha a loja aberta de um jogador. |
/tw shop admin reset <shop> | Redefine o estoque e os limites agora. |
/tw shop admin stock <shop> <item> get | Mostra o estoque do item nesse índice. |
/tw shop admin stock <shop> <item> set <amount> | Define o estoque. Também add e remove. |
/tw shop admin history [target] | Mostra as últimas 10 transações de um jogador desde o último reinício. |
<shop> é o entry id, completado com a tecla Tab. <item> é a posição do item em items da loja, começando em 0.
Textos editáveis
Nenhum texto exibido no jogo está fixo no código. Três tipos de texto podem ser alterados sem recompilar nada.
O que um jogador lê ao negociar é um campo da Shop Definition: purchaseMessage, sellMessage, cannotAffordMessage, limitReachedMessage, priceLore e os demais descritos acima.
Os textos de preço, os ícones de tendência e as linhas de pool são campos da entrada a que pertencem. O padrão é o texto que a extensão sempre exibiu.
| Campo | Entrada | Padrão | Uso |
|---|---|---|---|
trendUpIcon | Shop Definition | <red>▲</red> | O placeholder trend_icon de um item cujo preço subiu desde a última compra ou venda. |
trendDownIcon | Shop Definition | <green>▼</green> | O mesmo placeholder quando o preço caiu. |
trendStableIcon | Shop Definition | <gray>●</gray> | O mesmo placeholder quando o preço não mudou, ou quando nenhum preço anterior é conhecido. |
itemPriceLineFormat | Shop Definition | - {amount} × {name} | Uma linha do token de lore {item_price}, para cada item que um preço em itens pede. {amount} é a quantidade e {name} o nome do item. |
unknownItemName | Shop Definition | unknown item | O nome de um item de preço cujo nome próprio não pode ser lido, em {item_price} e na lista de itens faltantes. |
missingItemFormat | Shop Definition | {amount} × {name} | Um elemento da lista {missing} de cannotAffordItemsMessage. {amount} é a quantidade que falta. |
missingItemSeparator | Shop Definition | , | O que fica entre dois elementos da lista {missing}. |
defaultItemName | Shop Definition | Item | O {item_name} de subMenuTitle para um item sem name. |
noPriceText | Shop Definition | — | Exibido no lugar de um número onde um preço em itens não tem um: os placeholders buy_price e sell_price, e {price} na mensagem de inventário cheio de um item assim. |
cooldownFormat | Shop Definition | {d}d:{h}h:{m}m:{s}s | O padrão do placeholder cooldown quando o placeholder não informa nenhum. {d} dias, {h}, {m}, {s} preenchidos com 2 dígitos. |
limitedLore | Shop Pool | <yellow>Limited: <red>{limit} | A última linha de lore de um item limitado do pool. {limit} é a quantidade disponível. |
unlimitedLore | Shop Pool | <yellow>Unlimited | A última linha de lore de um item do pool sem limite. |
Use %typewriter_shop:<shop>:<n>:trend_icon% no lore de um item para exibir o ícone. %typewriter_shop:<shop>:<n>:trend% retorna up, down, stable ou unknown, e essas quatro palavras são fixas porque as condições as comparam.
O que os comandos /tw shop respondem, os comandos /tw shop admin incluídos, é um snippet do TypeWriter. Abra plugins/Typewriter/snippets.yml, encontre a chave em content.shop, altere o valor e execute /tw reload. A extensão registra todos os seus snippets com o texto padrão ao iniciar, então eles aparecem no arquivo após a primeira inicialização. Mantenha os padrões e nada muda.
As respostas são MiniMessage e são enviadas sem o prefixo do Typewriter, então a cor de uma resposta faz parte do seu texto. Um {name} em um texto é substituído pelo valor indicado na tabela; um placeholder que não existe permanece como escrito, e um valor nunca é examinado de novo em busca de placeholders. Um valor vindo das suas páginas (o nome de uma loja, o nome de um jogador, o título de um inventário) é exibido como escrito: suas tags nunca são interpretadas. O log do console do servidor continua em inglês.
Snippet (em content.shop.) | Padrão | Placeholders |
|---|---|---|
help | <gold>Shop commands:</gold> <yellow>/tw shop <id></yellow> to open a shop, <yellow>/tw shop admin</yellow> for operator tools. | nenhum |
unknown_shop_error | Unknown shop: {shop} (texto simples) | {shop} (o que foi digitado) |
admin.help | a lista de comandos de administração, um por linha | nenhum |
admin.unknown_shop | <red>Unknown shop: {shop} | {shop} |
admin.list_empty | <yellow>No shop definitions are currently loaded. | nenhum |
admin.list_header | <gold>Loaded shops ({count}): | {count} |
admin.list_line | <white>- {id} | {name} | items={items} | pools={pools} | {id}, {name}, {items}, {pools} |
admin.opened | <green>Opened {shop} for {player}. | {shop}, {player} |
admin.refreshed | <green>Refreshed the shop session for {player}. | {player} |
admin.closed | <green>Closed the shop session for {player}. | {player} |
admin.reset | <green>Reset runtime stock and limits for {shop}. | {shop} |
admin.history_header | <gold>Recent transactions for {player} ({count}): | {player}, {count} |
admin.history_empty | <yellow>No transactions recorded in the current runtime. | nenhum |
admin.history_line | <white>{time} | {type} | {shop}[{index}] | amount={amount} | price={price} | {time}, {type}, {shop}, {index}, {amount}, {price} |
admin.info_title | <gold>=== Shop {shop} === | {shop} |
admin.info_name | <white>Name: {name} | {name} |
admin.info_inventory_title | <white>Title: {title} | {title} |
admin.info_currency | <white>Currency: {currency} | rows={rows} | {currency}, {rows} |
admin.info_items | <white>Items: {items} direct | pools={pools} | access criteria={criteria} | {items}, {pools}, {criteria} |
admin.info_reset | <white>Reset policy: {policy} | {policy} |
admin.info_item | <white>[{index}] {name} | buy={buy} sell={sell} | playerLimit={playerLimit} globalLimit={globalLimit} | item criteria={criteria} | {index}, {name}, {buy}, {sell}, {playerLimit}, {globalLimit}, {criteria} |
admin.info_item_unnamed | <unnamed> (texto simples) | nenhum; é o {name} de um item sem nome |
admin.stock_unlimited | <yellow>{shop}[{index}] uses unlimited stock. | {shop}, {index} |
admin.stock_value | <green>{shop}[{index}] stock: {stock}/{max}. | {shop}, {index}, {stock}, {max} |
admin.stock_out_of_range | <red>Stock must stay between 0 and {max}. | {max} |
admin.stock_updated | <green>{shop}[{index}] stock set to {stock}/{max}. | {shop}, {index}, {stock}, {max} |
admin.unknown_item | <red>Unknown direct item index {index} in {shop}. | {index}, {shop} |
unknown_shop_error é um erro de comando, exibido em vermelho pelo jogo enquanto o jogador digita: é texto simples, sem MiniMessage.
Permissões
| Permissão | Concede |
|---|---|
typewriter.shop.open | /tw shop <shop>. Concedida a todos por padrão. |
typewriter.shop.admin | Todos os comandos /tw shop admin. Apenas operadores por padrão. |
Placeholders
Placeholders do PlaceholderAPI, com a expansão typewriter. <shop> é o nome ou id da entry da loja e <n> a posição do item em items, a partir de 0.
| Placeholder | Retorna |
|---|---|
%typewriter_shop:<shop>:name% | Nome da entry. |
%typewriter_shop:<shop>:entryid% | Id da entry. |
%typewriter_shop:<shop>:cooldown% | Tempo até o próximo reset, por padrão no formato 0d:00h:00m:00s (o campo cooldownFormat da loja; versões anteriores usavam j para dias). Adicione um formato depois de um sublinhado, por exemplo cooldown_{h}h{m}m, usando {d}, {h}, {m} e {s}. |
%typewriter_shop:<shop>:<n>:buy_price% | Preço de compra do item; o noPriceText da loja (— por padrão) nos itens de troca. |
%typewriter_shop:<shop>:<n>:sell_price% | Preço de venda do item; o noPriceText da loja (— por padrão) nos itens de troca. |
%typewriter_shop:<shop>:<n>:stock% | Estoque atual. |
%typewriter_shop:<shop>:<n>:stock_max% | Estoque máximo. |
%typewriter_shop:<shop>:<n>:has_promotion% | true quando uma promoção se aplica ao item. |
Integração
- GUI — o Shops abre seus menus pelo serviço de sessões do GUI, então
gui:back, sons, chassis estendidos ebaseMenuIdse comportam como em qualquer outro menu. DefinabaseMenuIdcomo um shell Open GUI compartilhado, adicioneviewse a loja se torna uma aba:contentX,contentY,contentColumnsecontentRowsposicionam os produtos dentro do shell. - Discord — após cada compra ou venda, o Shops dispara um
ShopTransactionEvent. Quando a extensão Discord está instalada e a loja definenotificationWebhookId, uma entry Shop Notification formata o anúncio. - Sons —
buySound,sellSoundedeniedSoundtocam no resultado correspondente.
Entries
6 entradas, geradas a partir do código-fonte da extensão.
Ações1
- Open ShopOpen a shop for a player
Artefatos1
- Shop ArtifactRuntime storage for shops
Manifestos4
- Item PoolA weighted pool of items for shops
- Shop CategoryA category within a shop
- Shop DefinitionDefines a shop
- Shop PromotionA shop discount promotion
Solução de problemas
O menu abre, mas não mostra produto. O layout não tem marcador SHOP_ITEM, mainLayoutId não corresponde a nenhum id de layout em layoutPool, ou o layout não é um layout simple. Os produtos só aparecem nos slots de marcador.
Um botão não faz nada. Seu buttonPrefix não é shop_button:, ou seu buttonType está escrito errado (os tipos são em maiúsculas). Um botão de paginação ou de fechar também precisa do prefixo; só SHOP_ITEM tolera um prefixo vazio.
A loja diz "No economy available". Com VAULT, o Vault ou seu provedor de economia está ausente. Com PLACEHOLDER, um entre balancePlaceholder, addCommand ou removeCommand está vazio. Em um item de escambo, a mensagem também aparece quando nem itemPrice nem defaultItemPrice estão definidos, e o console registra o id da loja e o número do item.
Estoque e limites se perdem ao reiniciar, ou nunca são salvos. Deve existir uma entry Shop Artifact cujo id ou nome seja shop_artifact.
Um item não pode ser vendido. O preço de venda dele é zero (os itens de escambo sempre são), sellEnabled está desativado ou o jogador não possui itens correspondentes suficientes. Só contam itens com tipo e dados de item idênticos.
O console avisa que um artigo não pode ser exibido ou foi movido. Um item com guiSlot ocupa um marcador SHOP_ITEM. Quando os itens fixados ocupam todos os marcadores, os demais itens são colocados nas células livres da área de conteúdo; se não houver nenhuma célula livre, o item não é exibido. Adicione marcadores SHOP_ITEM ou libere um slot.
Itens de itemPools aparecem, mas não podem ser comprados. Nesta release, apenas as entradas de items são tratadas pelas ações de compra e venda; os itens dos pools são exibidos depois delas.
Os limites nunca são redefinidos. reset é none. Escolha uma política ou use /tw shop admin reset <shop>.
/tw shop <id> diz que a loja é desconhecida. O comando recebe o entry id, não o título. Use /tw shop admin list.
Extensões relacionadas
- GUI — layouts, sessões e o mecanismo de marcadores usado pelos menus de loja.
- Discord — anuncia as transações da loja em um webhook.
- Quest Codex — usa a mesma ideia de chassi para os menus de quests.