⚠️ Este plugin está em desenvolvimento ativo. Ainda não foi publicado no Diretório de Plugins do Moodle. Algumas funcionalidades descritas abaixo são planejadas e ainda não estão implementadas — veja Funcionalidades pra saber exatamente quais são quais.
O PlayerPuzzle (mod_playerpuzzle) é uma atividade gamificada Match-3 RPG por turnos para o
Moodle: o estudante combina peças num tabuleiro 8×8 para atacar um chefe controlado por uma IA
simples, respondendo questões puxadas do próprio Banco de Questões do Moodle no curso pra
desferir ataques críticos. O professor escolhe entre uma Partida Única autocontida ou uma
Campanha de até 10 níveis (10 fases cada); a progressão permanente opcional (moedas, nível
de espada/escudo) é resolvida inteiramente pelo block_playerhud companheiro,
quando presente no curso — o PlayerPuzzle não mantém economia própria.
👈 Use a barra lateral para ir direto a qualquer seção desta página.
🖼️ Capturas de Tela
Navegue com as setas, os pontos, ou as teclas esquerda/direita. Clique na imagem para ampliar.
O Lobby: progresso atual da Campanha, o aviso de mínimo de questões e o botão de jogar, antes mesmo do estudante entrar na partida
✨ Funcionalidades
✅ Implementado
- ⚔️ Combate por Turnos em Match-3: Um tabuleiro 8×8 (Phaser 3) onde o estudante troca peças para atacar um chefe. Combinar peças de Orbe de Interrogação carrega um desafio de pergunta; uma resposta correta causa dano extra. Veja Como o Combate Funciona.
- 🔄 IA do Chefe Simétrica: as sete peças resolvem exatamente do mesmo jeito no turno do chefe que no turno do estudante — o chefe causa dano, acumula multiplicador de crítico, envenena o estudante, se protege, se cura e acumula sua própria moeda pra compensar o saldo final do estudante, em vez da maioria das peças ficar inerte quando a IA as combina.
- 🎮 Dois Modos de Jogo: Campanha (uma jornada contínua por até 10 níveis × 10 fases
cada, onde vencer nunca consome uma nova tentativa — só perder consome) e Partida Única
(uma rodada autocontida reaproveitando o padrão
grademethoddo ecossistema PlayerGames). Veja Modos de Jogo. - 📈 Escala Linear de HP: o HP do chefe e do estudante escalam com o nível/fase atual usando
uma fórmula linear fixa (
base × (1 + taxa × (nível−1) + taxa × (fase−1))), calculada uma vez no servidor e nunca recalculada no cliente. - 🔄 Retomada de Campanha: fechar o navegador no meio de uma campanha e voltar retoma exatamente o nível/fase em que o estudante estava — o servidor rotaciona o token anti-replay e preserva o progresso de forma transparente.
- 🎯 Integração com o Banco de Questões Real: as questões vêm do próprio Banco de Questões do
Moodle (
core_question), reaproveitando categorias que o professor já tem no curso — veja Motor de Questões. - 🛡️ Anti-Trapaça em Três Pilares: JSON Cego (a resposta correta nunca chega ao cliente antes do servidor validar), clamp de dano no servidor contra o HP do chefe escalado pela fase, e tokens anti-replay de uso único, rotacionados a cada chamada que altera estado.
- 🗨️ Modal de Pergunta Acessível: o desafio de pergunta é renderizado como um
<dialog>HTML nativo — captura de foco, tratamento de ESC e centralização vêm todos do próprio navegador, com o foco salvo e restaurado pro elemento que abriu o modal. - 📊 Indicador de Progresso no HUD: “Nível X — Fase Y de 10” exibido durante o combate da Campanha.
- 💰 Integração de Economia com o PlayerHUD: totalmente opcional. Quando o block_playerhud está presente no curso, o professor escolhe quais itens do próprio bloco representam moedas, nível de espada e nível de escudo — vencer uma partida credita moedas, e um item configurável pode ser concedido a cada vitória (com o XP suprimido quando o limite de tentativas está ilimitado, pra evitar farming). Sem o PlayerHUD, o plugin continua funcionando sozinho, sem nenhuma progressão permanente.
- 🏛️ Lobby: mostra o saldo do estudante no PlayerHUD (só os itens que o professor configurou), o progresso atual da Campanha, e o aviso configurado de mínimo de questões antes da partida começar.
- 🔐 Privacidade (LGPD/GDPR): Privacy Provider completo — declaração de metadados, exportação e exclusão de todos os dados pessoais armazenados.
- 🧪 Testes Automatizados: suíte PHPUnit com 104 casos, verde em toda a matriz de CI — veja a seção Testes Automatizados.
⏳ Em Desenvolvimento / Planejado
- 🧮 Multiplicador de Combate do PlayerHUD:
hud_service::get_upgrade_level()já lê o nível de espada/escudo do estudante, mas ocombat.jsainda não aplica isso como multiplicador de dano/defesa durante a partida. - 🎬 Debrief Pós-Partida: uma tela de revisão não-automática ao vencer uma fase — todas as
perguntas respondidas, certo vs. escolhido, dano causado, moedas ganhas — com botões “Jogar
Próxima Fase” / “Sair”. O endpoint
advance_phaseque alimenta a transição de “próxima fase” já existe; a tela em si ainda não. - 🛍️ Consumíveis Durante o Combate: Escudo, Magia Rápida, Dica e Poção, compráveis no meio da partida com um saldo de moedas local à sessão (a Poção também poderá ser consumida de um estoque permanente do PlayerHUD).
- ❤️🩹 Revive do Chefe / Aplicação do Mínimo de Questões: a configuração de “mínimo de questões por partida” já existe no formulário da atividade e mostra um aviso no Lobby, mas a regra de jogo em si (reviver o chefe com metade do HP se o mínimo ainda não foi atingido) ainda não está implementada.
- 🎓 Integração com o Livro de Notas:
grade_item_update()/update_grades(), escaladas pela Nota Máxima configurada — as duas fórmulas de nota (baseada em progresso pra Campanha, baseada emgrademethodpra Partida Única) já estão desenhadas, mas ainda não são enviadas pro livro de notas do Moodle. - ✅ Regras de Conclusão Customizadas:
FEATURE_COMPLETION_HAS_RULEShoje é declaradafalse(honestamente, em vez de anunciar uma funcionalidade quebrada) até a implementação real existir. - 💾 Backup e Restauração:
FEATURE_BACKUP_MOODLE2hoje éfalsepelo mesmo motivo. - 📋 Relatório do Professor: uma página de relatório dedicada resumindo o desempenho da turma.
- ♿ Camada Completa de Acessibilidade: uma camada HTML paralela, sempre presente (uma
<table role="grid">visualmente oculta espelhando o tabuleiro, anúnciosaria-livejogada a jogada, entrada por teclas numéricas1–9) pra jogar via leitor de tela sem tocar no Canvas. O modal de pergunta já segue esse desenho; o resto do loop de combate ainda não. - 📚 Banco de Questões Próprio + Geração com IA: uma segunda fonte de questões, própria do
PlayerPuzzle (cadastro manual ou geração assistida por IA via
local_aihub), coexistindo com o Banco de Questões real em vez de substituí-lo. - 🏆 Ranking: um placar separado (não vinculado à nota configurada), com agregação própria por modo de jogo.
- 🥊 Modo Disputa (V2): um futuro modo de confronto direto — arquitetura ainda não fechada.
O plugin é um software em estágio Alpha: tudo em "Implementado" acima funciona hoje e é coberto pela suíte de testes automatizados; tudo em "Planejado" está desenhado (ver o roteiro interno do projeto), mas ainda não construído.
⚔️ Como o Combate Funciona
O combate roda num tabuleiro Match-3 8×8 (Phaser 3), priorizando retrato (540×960), se adaptando a um layout paisagem em telas mais largas.
Estrutura de Turnos
- O estudante faz uma jogada no tabuleiro.
- Combos e cascatas mantêm o turno do estudante rolando.
- Quando o tabuleiro estabiliza, é o Turno do Chefe: uma IA simples varre o tabuleiro e executa uma troca válida. O que ela combina resolve pelas mesmas sete peças e os mesmos efeitos do turno do estudante (veja abaixo) — o chefe pode causar dano, acumular multiplicador, envenenar o estudante, se proteger, se curar e acumular moeda, exatamente como o estudante faz no próprio turno.
As Sete Peças
Efeitos simétricos: cada peça faz a mesma coisa não importa de qual lado está jogando — o que muda é só quem ganha o efeito (quem estiver no turno atual).
| Peça | Efeito |
|---|---|
| ⭐ Estrela | Soma +0,1 a um multiplicador de dano, acumulando entre turnos; consumido no acerto crítico daquele lado e resetado a 1 quando esse lado erra uma pergunta |
| 📖 Grimório | Enche um medidor de veneno próprio de 0–100 (+10 por peça); ao chegar em 100, arma 3 rodadas de dano contra o oponente (uma por turno dele) e reseta, preservando o excedente |
| ❓ Orbe de Interrogação | Enche uma barra de energia de 100 pontos própria de cada lado; ao chegar em 100, pausa o combate e abre o Desafio de Pergunta — o estudante responde de verdade, o chefe “responde” escolhendo uma opção ao acaso, validada do mesmo jeito no servidor |
| ⚔️ Espadas | Dano direto no oponente — sem precisar de pergunta. Escala com nível/fase, e uma combinação de 4 ou 5 peças causa 1,5x/2x o dano de uma combinação de 3 |
| 🛡️ Escudo | Enche um medidor próprio de 0–100 (+10 por peça); ao chegar em 100, nega por completo o próximo golpe recebido por esse lado, não importa o valor, e reseta |
| 🧪 Poção | Cura o HP do próprio lado — escala do mesmo jeito que o dano de Espada, na metade da taxa de uma combinação de Espada do mesmo tamanho |
| 🪙 Moeda | Soma ao contador de ouro próprio da partida — veja a fórmula por combinação e a compensação líquida em Integração com o PlayerHUD |
O Desafio de Pergunta
Quando a barra de Orbe de Interrogação de qualquer um dos lados chega a 100%, a partida pausa e abre o modal de pergunta:
- Resposta correta — um acerto crítico: dano base triplicado, multiplicado pelo bônus de Estrela que esse lado acumulou.
- Resposta errada — esse lado sofre dano, e seu multiplicador de Estrela volta pra 1.
É o momento em que o plugin conecta a habilidade no Match-3 com o conhecimento real de conteúdo: combinar peças bem enche a barra e acumula o multiplicador, mas o retorno de verdade só vem se o estudante também responder certo.
Verdade do Servidor
Todo número que governa o combate — o HP máximo do chefe e do estudante, e o valor base de dano do qual Espada/Estrela/Grimório/Poção escalam — é calculado uma única vez no servidor pro nível e fase atuais (veja Modos de Jogo pra como esses valores escalam) e entregue ao cliente como configuração; o cliente nunca recalcula nada disso. O dano que o cliente reporta de volta é limitado no servidor contra esse mesmo HP do chefe escalado pela fase antes de ser aceito — veja Segurança e Anti-Trapaça.
🎯 Motor de Questões
Fonte
O PlayerPuzzle lê as questões do próprio Banco de Questões do Moodle (core_question) — o
professor escolhe uma categoria já existente nas configurações da atividade, e qualquer questão
de Múltipla Escolha ou Verdadeiro/Falso nela pode ser usada durante o combate. Isso significa que
um professor que já mantém um banco de questões pro Quiz pode apontar o PlayerPuzzle pra mesma
categoria e reaproveitá-la na hora, sem migrar conteúdo nenhum.
Uma segunda fonte de questões, própria do PlayerPuzzle (cadastro manual mais geração assistida por IA), está planejada pra coexistir ao lado do Banco de Questões real — veja Funcionalidades.
JSON Cego — a Resposta Nunca Vaza
O texto da pergunta e todas as opções de resposta são enviados ao navegador, mas o id da
resposta correta não é. O question_fetcher.php remove esse dado no servidor antes da
pergunta sequer chegar ao cliente. Quando o estudante envia uma escolha, o
mod_playerpuzzle_validate_answer confere contra o registro real no banco de dados e devolve só
um booleano mais (numa resposta errada) a opção correta — então nada no código-fonte da página
ou no tráfego de rede revela a resposta com antecedência. Esse é o primeiro dos
três pilares anti-trapaça do plugin.
Mínimo de Questões por Partida
As configurações da atividade permitem que o professor exija um número mínimo de perguntas respondidas antes que uma partida possa terminar em vitória, e o Lobby mostra essa exigência ao estudante antes de ele começar. A regra de jogo que aplica isso de fato — reviver o chefe com metade do HP se o mínimo ainda não foi atingido — ainda não está implementada; veja Funcionalidades.
🎮 Modos de Jogo
O professor escolhe um modo por instância da atividade.
Campanha
Uma jornada contínua por até 10 níveis, cada um dividido em 10 fases. Vencer uma fase nunca consome uma nova tentativa — só perder (ou o tempo esgotar) consome, e o limite configurado de Máximo de Tentativas só conta tentativas finalizadas (perdidas/tempo esgotado/abandonadas), nunca uma fase vencida ao longo do caminho.
- Retomada: fechar o navegador no meio de uma campanha e voltar retoma exatamente o nível/fase em que o estudante estava — o servidor rotaciona o token anti-replay e pega a tentativa em andamento mais recente, em vez de reiniciar no Nível 1.
-
Escala de HP: tanto o HP máximo do chefe quanto o do estudante escalam com o nível/fase atual, usando uma fórmula linear fixa calculada uma vez no servidor:
Fórmula HP do Chefe base × (1 + 0.5 × (nível − 1) + 0.1 × (fase − 1))HP do Estudante base × (1 + 0.3 × (nível − 1) + 0.05 × (fase − 1))O chefe escala mais rápido que o estudante — as fases mais avançadas devem parecer mais difíceis, não só mais longas.
- Avançando: ao vencer uma fase, o servidor confere se o dano reportado realmente zerou o HP do chefe daquela fase antes de permitir o avanço, e rotaciona o token de novo — a mesma requisição não pode ser reproduzida pra pular várias fases a partir de uma única vitória real.
Partida Única
Uma única rodada autocontida — sem níveis ou fases. A nota reaproveita o padrão grademethod
já estabelecido pelas atividades irmãs mod_playerwords/mod_playercross: o professor define
um limite de Máximo de Partidas (ou deixa ilimitado) por um seletor 0–10, na mesma
escala de uma rodada curta e repetível, em vez de uma campanha longa.
Por Que Dois Modos em Vez de Um Só
Uma “tentativa” de Campanha e uma “tentativa” de Partida Única são estruturalmente diferentes —
uma jornada contínua atravessando várias fases contra rodadas independentes e repetíveis —
então o plugin modela os dois separadamente em vez de forçar um único esquema de
nota/contagem de tentativas caber nos dois casos. question_fetcher.php, save_progress.php e
o Lobby leem o gamemode configurado pra saber quais regras se aplicam.
💰 Integração com o PlayerHUD
O PlayerPuzzle não tem nenhuma economia própria permanente. Moedas e níveis de upgrade vivem inteiramente no block_playerhud, e o PlayerPuzzle só lê/escreve nele quando o bloco está presente no curso — o plugin funciona sozinho, sem nenhuma configuração, se ele não estiver.
Itens Escolhidos pelo Professor, Nunca Auto-Detectados
Pra cada curso, o professor escolhe explicitamente quais itens do próprio bloco representam:
- Moedas — creditadas quando uma partida é vencida (o ouro coletado durante o combate é depositado aqui).
- Nível de espada — lido como um nível de upgrade pro dano do estudante.
- Nível de escudo — lido como um nível de upgrade pra defesa do estudante.
- Poção — opcional; também pode ser consumida de um estoque permanente do PlayerHUD, em vez de (ou junto com) a compra local por moeda de sessão.
- Custo de retentativa — opcional; cobrado a partir da 2ª tentativa do estudante, sem nunca ampliar o limite de tentativas configurado. Pensado pra ser conquistado através de conteúdo de reforço fora do jogo (um vídeo, outra atividade), não jogando o PlayerPuzzle em si — assim o estudante que mais precisa de tentativas não é também o que menos consegue pagar por elas.
- Prêmio de vitória — opcional; um item fixo concedido a cada vitória, além das moedas.
Cada um desses é um simples dropdown dos itens já configurados no bloco — o mesmo padrão já
usado pelas atividades irmãs mod_playerwords/mod_playercross — então adicionar essa
integração nunca exigiu nenhuma mudança no block_playerhud em si.
Ganho de Moeda e a Compensação do Chefe
Combinar a peça Moeda (veja Como o Combate Funciona) rende moedas numa curva de combo: uma combinação de 3 rende o valor base configurado em “Ganho de Moeda”, uma de 4 rende 1,5x esse valor, e uma de 5 rende 2x — a mesma curva que o dano da Espada usa. Diferente de todo o resto do combate, o Ganho de Moeda deliberadamente não escala por nível ou fase, então o professor pode configurar preços fixos de consumíveis (Poção, Escudo, Magia Rápida, Dica) que continuam equilibrados durante toda a campanha, em vez de ficarem proporcionalmente mais baratos conforme ela avança.
O chefe também acumula sua própria conta de Moeda quando combina a peça no próprio turno — ele
não tem loja e nunca gasta esse valor. Seu único propósito é compensar o saldo do estudante ao
fim da partida: a contagem final de moedas do estudante é max(0, moedas do estudante − moedas
do chefe), creditada via PlayerHUD só em vitória. Isso dá à IA do chefe um motivo pra “competir”
pela mesma peça que o estudante quer, em vez de ela ficar inerte sempre que a IA combiná-la.
O Que Já Está Ligado Hoje
- ✅ Creditar moedas na vitória.
- ✅ Ler o nível de upgrade de espada/escudo do estudante
(
hud_service::get_upgrade_level()). - ⏳ Aplicar esse nível de upgrade como um multiplicador de dano/defesa de verdade durante o
combate — o leitor existe e está testado; o
combat.jsainda não o consome. - ⏳ Itens de Poção/custo de retentativa/prêmio de vitória — configuráveis hoje, ainda não consumidos pela jogabilidade.
Veja Funcionalidades pra a divisão completa entre implementado e planejado.
♿ Acessibilidade
O Desenho
A jogabilidade Match-3 vive num Canvas, que é opaco pra leitores de tela por natureza. A abordagem de acessibilidade do PlayerPuzzle é uma camada HTML paralela, sempre presente, em vez de um complemento pensado depois:
- Uma
<table role="grid">visualmente oculta espelha o estado do tabuleiro, navegável célula a célula. - Eventos jogada a jogada (jogadas disponíveis, dano causado, HP restante do chefe, barra de
energia cheia, uma pergunta respondida) são anunciados por uma região
aria-live="polite", então um usuário de leitor de tela recebe a mesma informação que um jogador vidente lê no HUD. - As teclas numéricas
1–9executam a jogada correspondentemente anunciada;Espaçorelê a lista de jogadas disponíveis. aria-live="assertive"é reservado pra eventos que interrompem o turno (por exemplo, sofrer dano de uma carga de veneno).
O Que Já Está Implementado Hoje
- ✅ O modal de pergunta — o momento em que a jogabilidade mais precisa ser acessível — é um
<dialog>HTML nativo, não uma sobreposição de Canvas. Abri-lo captura o foco e centraliza usando o próprio comportamento do navegador; fechá-lo restaura o foco pro elemento que o abriu.
O Que Está Planejado
- ⏳ O tabuleiro HTML paralelo (
<table role="grid">), os anúnciosaria-livejogada a jogada, e o esquema de entrada por teclas numéricas descritos acima estão desenhados, mas ainda não construídos. - ⏳ Um anúncio de avanço de fase (“Você avançou para o Nível 5, Fase 2”) assim que a tela de debrief pós-partida existir — veja Funcionalidades.
O speechSynthesis nunca é usado como canal padrão de anúncio, pra evitar conflito com
qualquer leitor de tela que o estudante já esteja usando.
🔐 Segurança e Anti-Trapaça
Todo número de combate que o estudante vê é uma afirmação que o cliente faz sobre si mesmo. O PlayerPuzzle não trata nada disso como confiável até o servidor confirmar, através de três pilares:
1. Servidor Como Fonte da Verdade
O HP do chefe e do estudante pro nível/fase atuais são calculados uma única vez, no servidor
(combat::calculate_boss_hp()/calculate_student_hp()), e entregues ao cliente como
configuração somente-leitura. O cliente nunca os recalcula.
2. Dano Verificado por Sanidade
Qualquer dano que o cliente reporte ao fim de uma partida é limitado contra o HP real do chefe,
já escalado pela fase, antes de ser aceito — nunca o HP base, e nunca o que o cliente afirma que
deveria ser o teto. Avançar uma fase (advance_phase) aplica a mesma regra: o servidor exige
que o dano reportado tenha realmente zerado o HP do chefe daquela fase antes de permitir a
transição.
Uma checagem de sanidade mais completa — considerando multiplicadores de upgrade do PlayerHUD e tempo de jogo decorrido — está desenhada, mas ainda não implementada; veja Funcionalidades.
3. Tokens Anti-Replay de Uso Único
Toda chamada que altera estado (iniciar uma partida, retomar uma tentativa de campanha, avançar uma fase) emite um token novo e invalida o anterior. Uma requisição capturada não pode ser reproduzida pra disparar a mesma recompensa duas vezes — retomar uma campanha no meio da jornada rotaciona o token exatamente como terminar uma faz, então a garantia se mantém mesmo numa sessão que atravessa vários carregamentos de página, não só dentro de uma única partida.
JSON Cego
O id da resposta correta nunca é enviado ao cliente — veja Motor de Questões pra como isso é garantido na camada de dados, não só na interface.
🎓 Finalidade Educacional
O PlayerPuzzle é pensado para:
- Transformar acertar uma questão de conteúdo num evento de combate imediato e visualmente recompensador (um acerto crítico), em vez de só mais uma marcação a caminho de uma nota
- Reaproveitar o Banco de Questões que um curso já tem, então atividades de fixação de conteúdo que um professor já mantém pro Quiz podem ser reaproveitadas sem nenhuma migração
- Manter o rigor da avaliação intacto por baixo do jogo — tentativas são limitadas, respostas são validadas no servidor, e a nota é desenhada pra refletir progresso/desempenho real (veja Modos de Jogo), nunca números reportados pelo cliente
- Recompensar engajamento sustentado, escopado por curso, através da integração opcional com o PlayerHUD, sem exigir nenhuma economia permanente pra um curso que não quer uma
Adequado para:
- Qualquer curso que já use o
block_playerhudpra progressão gamificada - Professores que já mantêm uma categoria do Banco de Questões pro mesmo conteúdo e querem uma segunda forma, baseada em jogo, de reforçá-lo
- Instituições explorando fixação de conteúdo gamificada como complemento (não substituto) a provas formais
🕹️ Ecossistema PlayerGames
O PlayerPuzzle faz parte do ecossistema de gamificação PlayerGames para o Moodle. Nenhum dos plugins abaixo é obrigatório — o PlayerPuzzle funciona sozinho — mas instalar os relevantes pra um curso libera as integrações documentadas ao longo desta página.
-
PlayerGames: hub central do ecossistema — XP site-wide, temporadas, minijogos diários, e o Dashboard do Ecossistema que conecta todo plugin Player instalado. 👉 github.com/jeanlucio/moodle-local_playergames
-
PlayerHUD Block: XP, níveis, inventário, drops, missões, classes de RPG e ranking dentro de cada curso. O PlayerPuzzle lê/escreve nele pra toda a sua economia opcional — veja Integração com o PlayerHUD. 👉 github.com/jeanlucio/moodle-block_playerhud
-
PlayerHUD Filter: habilita drops de itens via shortcodes dentro do conteúdo do curso. 👉 github.com/jeanlucio/moodle-filter_playerhud
-
PlayerHUD Availability Restriction: restringe o acesso a atividades do curso com base no nível atual do estudante ou nos itens coletados. 👉 github.com/jeanlucio/moodle-availability_playerhud
-
PlayerWords: uma atividade irmã (adivinhação de palavras) que estabeleceu o padrão de
grademethod/contagem de tentativas que o modo Partida Única do PlayerPuzzle reaproveita. 👉 github.com/jeanlucio/moodle-mod_playerwords -
PlayerCross: uma atividade irmã (palavras cruzadas) compartilhando os mesmos padrões arquiteturais (classes
local\*_page_servicede entrada, convenções de integração com o PlayerHUD). 👉 github.com/jeanlucio/moodle-mod_playercross -
PlayerLand: outra atividade baseada em Phaser no ecossistema, compartilhando o mesmo padrão de carregamento dinâmico de script pro seu próprio motor de jogo embutido. 👉 github.com/jeanlucio/moodle-mod_playerland
-
PlayerGroup: permite que estudantes formem seus próprios grupos de forma autônoma direto na página da atividade — sem precisar de intervenção do professor. 👉 github.com/jeanlucio/moodle-mod_playergroup
-
AI Hub: corretor compartilhado de BYOK (traga sua própria chave) pra funcionalidades de IA em todo o ecossistema. A funcionalidade planejada de geração de questões do PlayerPuzzle vai consumi-lo como dependência opcional, recorrendo ao próprio
core_aido Moodle — veja Funcionalidades. 👉 github.com/jeanlucio/moodle-local_aihub
📦 Requisitos
| Componente | Versão |
|---|---|
| Moodle | 4.5 – 5.2 |
| PHP | 8.2+ |
O block_playerhud é uma dependência opcional — veja
Integração com o PlayerHUD.
🛠️ Instalação e Configuração
⚠️ Este plugin ainda não está publicado no Diretório de Plugins do Moodle. Instale manualmente a partir deste repositório.
- Baixe o arquivo
.zipou clone este repositório. - Extraia na pasta
mod/do seu Moodle. - Renomeie para
playerpuzzle(se necessário). Caminho final:seu-moodle/mod/playerpuzzle/ - Acesse Administração do site → Notificações para concluir a instalação.
- Opcional: instale o block_playerhud se quiser a economia opcional de moedas/upgrades — veja Integração com o PlayerHUD.
- Adicione uma atividade PlayerPuzzle a qualquer curso, escolha um Modo de Jogo, uma categoria do Banco de Questões, e (opcionalmente) quais itens do PlayerHUD usar.
📖 Como Usar
Para Professores
- Adicione uma atividade PlayerPuzzle a um curso.
- Escolha um Modo de Jogo — Campanha ou Partida Única — veja Modos de Jogo.
- Escolha a categoria do Banco de Questões de onde a partida vai puxar questões.
- Opcionalmente, defina um Mínimo de Questões por Partida e se respostas erradas devem contar contra a nota.
- Opcionalmente, configure os itens de Integração com o PlayerHUD, se o
block_playerhudestiver instalado no curso. - Defina a Nota Máxima — as duas fórmulas de nota escalam por ela, nunca por um
100fixo.
Para Estudantes
- Abra a atividade para chegar ao Lobby — ele mostra seu progresso atual (modo Campanha), seu saldo no PlayerHUD se configurado, e qualquer exigência de mínimo de questões.
- Selecione Jogar para começar (ou retomar) uma partida.
- Combine peças para atacar o chefe, encha a barra de energia para disparar um Desafio de Pergunta, e responda certo para um acerto crítico.
- No modo Campanha, vencer uma fase nunca consome uma nova tentativa — só perder consome.
🧪 Testes Automatizados
O PlayerPuzzle vem com uma suíte PHPUnit extensa cobrindo o motor de combate, o fluxo de questões, a segurança anti-trapaça, a integração com o PlayerHUD, backup/restore, conclusão de atividade e privacidade. Todo push no CI roda a matriz completa (Moodle 4.5 → 5.3, PHP 8.1 → 8.4, PostgreSQL e MariaDB).
PHPUnit — Testes Unitários e de Integração (tests/)
| Arquivo de teste | Casos |
|---|---|
access_test.php |
1 |
backup_restore_test.php |
13 |
generator_test.php |
1 |
lib_completion_info_test.php |
6 |
lib_crud_test.php |
8 |
lib_grade_item_update_test.php |
4 |
lib_pluginfile_test.php |
5 |
lib_supports_test.php |
2 |
lib_update_grades_test.php |
4 |
mod_form_test.php |
11 |
phaser_loading_test.php |
2 |
uninstall_test.php |
2 |
| Subtotal | 59 |
Testes de Conclusão (tests/completion/)
| Arquivo de teste | Casos |
|---|---|
custom_completion_test.php |
11 |
| Subtotal | 11 |
Testes de Eventos (tests/event/)
| Arquivo de teste | Casos |
|---|---|
game_completed_test.php |
3 |
game_started_test.php |
2 |
| Subtotal | 5 |
Testes de Web Services (tests/external/)
| Arquivo de teste | Casos |
|---|---|
advance_phase_test.php |
26 |
buy_stock_test.php |
10 |
draw_question_test.php |
8 |
generate_questions_test.php |
2 |
get_phase_questionlog_test.php |
5 |
save_combat_state_test.php |
14 |
save_generated_questions_test.php |
4 |
save_progress_test.php |
29 |
set_sound_preference_test.php |
5 |
transfer_hud_coins_test.php |
8 |
use_stock_test.php |
15 |
validate_answer_test.php |
19 |
| Subtotal | 145 |
Testes de Formulário (tests/form/)
| Arquivo de teste | Casos |
|---|---|
import_form_test.php |
3 |
question_form_test.php |
11 |
| Subtotal | 14 |
Testes de Lógica de Negócio Local (tests/local/)
| Arquivo de teste | Casos |
|---|---|
ai_question_generator_test.php |
19 |
attempt_consumables_test.php |
7 |
attempt_questions_test.php |
1 |
coin_ledger_test.php |
4 |
combat_state_test.php |
5 |
game_page_service_test.php |
27 |
grade_calculator_test.php |
21 |
hud_service_test.php |
18 |
lobby_page_service_test.php |
22 |
move_log_test.php |
20 |
question_bank_sync_test.php |
13 |
question_editor_files_test.php |
3 |
question_list_service_test.php |
3 |
questions_repository_test.php |
21 |
ranking_service_test.php |
9 |
replay_credit_test.php |
8 |
report_service_test.php |
17 |
sound_preferences_test.php |
7 |
user_stock_test.php |
10 |
| Subtotal | 235 |
Testes do Motor de Combate (tests/local/engine/)
| Arquivo de teste | Casos |
|---|---|
board_engine_test.php |
25 |
combat_engine_test.php |
29 |
combat_test.php |
9 |
golden_vectors_test.php |
5 |
prng_test.php |
5 |
question_fetcher_test.php |
20 |
replay_test.php |
28 |
security_test.php |
43 |
| Subtotal | 164 |
Testes de Privacidade (tests/privacy/)
| Arquivo de teste | Casos |
|---|---|
provider_test.php |
36 |
| Subtotal | 36 |
| Total Geral | 669 |
vendor/bin/phpunit --testsuite mod_playerpuzzle_testsuite
Cobertura (moodle-coverage, PHPUnit + Xdebug): 86,79% de linhas, 74,03% de métodos
(21/47 classes totalmente cobertas).
Detalhamento completo teste a teste e tabela de cobertura →
JavaScript — Testes Unitários (tests/js/engine/)
A matemática determinística de match-3/combate/PRNG, rodada sem cabeça via o test runner
nativo do Node (node --test) — sem Jest, sem navegador. Primeiro plugin do ecossistema com
uma camada de teste JS própria.
| Arquivo de teste | Casos |
|---|---|
board_rules.test.js |
25 |
combat_rules.test.js |
29 |
prng.test.js |
5 |
| Subtotal | 59 |
node --test tests/js/engine/board_rules.test.js tests/js/engine/combat_rules.test.js tests/js/engine/prng.test.js
Behat — Testes de Aceitação
| Arquivo de feature | Cenários |
|---|---|
mod_playerpuzzle_accessibility.feature |
4 |
mod_playerpuzzle_gameplay.feature |
4 |
mod_playerpuzzle_match.feature |
3 |
mod_playerpuzzle_ranking.feature |
3 |
mod_playerpuzzle_settings.feature |
1 |
mod_playerpuzzle_smoke.feature |
1 |
| Subtotal | 16 |
php admin/tool/behat/cli/init.php
vendor/bin/behat --tags=@mod_playerpuzzle --profile=chrome
🔎 Divulgação de Serviço de Terceiros
Não aplicável hoje. O PlayerPuzzle não chama nenhum serviço externo atualmente — toda questão vem do próprio Banco de Questões do Moodle (veja Motor de Questões), e nenhuma requisição de rede sai do servidor como parte da jogabilidade.
Planejado
Uma segunda fonte de questões — cadastro manual mais geração assistida por IA opcional
através do plugin companheiro
local_aihub, recorrendo ao próprio core_ai
do Moodle — está desenhada para uma fase futura (veja Funcionalidades). Quando ela
existir, esta seção vai divulgar os provedores exatos, o que é transmitido, e qualquer
implicação de custo, seguindo o mesmo padrão já documentado pelo
local_playergames e
pelo próprio local_aihub. Assim como
nesses plugins, a geração por IA será totalmente opcional e nunca vai incluir dados de
estudante num prompt.
📄 Licença
Este projeto é licenciado sob a GNU General Public License v3 (GPLv3).
Copyright: 2026 Jean Lúcio
Suporte
Encontrou um bug ou tem alguma dúvida? Abra uma issue no rastreador de issues.
Mantenedor
Mantido por Jean Lúcio.