Para este projeto, você deverá aplicar os princípios da arquitetura SOLID
e os princípios de POO
em uma estrutura de jogos de interpretação de papéis, mais conhecidos como jogos RPG
(Role Playing Game).
-
Durante a execução dos testes, serão criados arquivos
.js
no repositório do projeto:-
Ao final da execução de cada teste é rodado um script que apaga todos os arquivos
.js
do repositório (com exceção dos que já vão com o projeto); -
O script utiliza o binário
find
do linux;
-
🐋 Rodando no Docker vs Localmente
Rode o serviço
node
com o comandodocker-compose up -d
.
- Esse serviço irá inicializar um container chamado
trybers_and_dragons
. - A partir daqui você pode rodar o container
trybers_and_dragons
via CLI ou abri-lo no VS Code.
Use o comando
docker exec -it trybers_and_dragons bash
.
- Ele te dará acesso ao terminal interativo do container criado pelo compose, que está rodando em segundo plano.
Instale as dependências [Caso existam] com
npm install
⚠ Atenção ⚠ Caso opte por utilizar o Docker, TODOS os comandos disponíveis no package.json
(npm start, npm test, npm run dev, ...) devem ser executados DENTRO do container, ou seja, no terminal que aparece após a execução do comando docker exec
citado acima.
⚠ Atenção ⚠ O git dentro do container não vem configurado com suas credenciais. Ou faça os commits fora do container, ou configure as suas credenciais do git dentro do container.
⚠ Atenção ⚠ Não rode o comando npm audit fix! Ele atualiza várias dependências do projeto, e essa atualização gera conflitos com o avaliador.
✨ Dica: A extensão Remote - Containers
(que estará na seção de extensões recomendadas do VS Code) é indicada para que você possa desenvolver sua aplicação no container Docker direto no VS Code, como você faz com seus arquivos locais.
Instale as dependências [Caso existam] com
npm install
⚠ Atenção ⚠ Não rode o comando npm audit fix! Ele atualiza várias dependências do projeto, e essa atualização gera conflitos com o avaliador.
✨ Dica: Para rodar o projeto desta forma, obrigatoriamente você deve ter o node
instalado em seu computador.
✨ Dica: O avaliador espera que a versão do node
utilizada seja a 16.
👀 Observações importantes:
-
O projeto deve ser desenvolvido na ordem dos requisitos (do 1 ao 13);
-
As importações e exportações dos arquivos devem ser feitas exatamente como estão sendo solicitadas e os nomes dos arquivos/diretórios também devem seguir à risca o que é pedido no
README.md
; -
Sempre que encontrar o símbolo
⚠️ pare e leia com muita atenção o que é pedido; -
Atente ao vocabulário usado no projeto, ele é super importante para te ajudar na hora de suas pesquisas. Qualquer dúvida procure a pessoa instrutora de sua turma no
Slack
ou nasmentorias
; -
Preste atenção às convenções, isso tem ligação direta com as boas práticas de código e de comunicação entre equipes;
-
Ao longo do projeto algumas refatorações serão necessárias para que ele funcione como é esperado;
-
Dentro do diretório
src/Battle
existe um arquivoBattle.ts
com uma classe abstrata de batalha criada. Os arquivos deste diretório estão comentados e podem ser usados de exemplo para a construção do projeto. Durante a execução do projeto, no requisito 6 - Crie a interfaceFighter
, será pedido para você descomentar os arquivos. Só descomente quando chegar lá, senão haverá erro de lint; -
Preste atenção ao padrão do projeto, onde cada diretório possui um arquivo
index.ts
exportando as informações necessárias, tomando cuidado para não ter problemas na execução dos testes.
🛠 Testes
Para executar os testes localmente, digite no terminal o comando npm test
.
Especialmente no início, quando a maioria dos testes está falhando, a saída após executar os testes é bastante poluída. Você pode utilizar duas formas:
- Desabilitar temporariamente um teste utilizando a função
skip
junto à funçãodescribe
. Como o nome indica, esta função "pula" um teste:
describe.skip('...', () => {})
- Utilizar o comando
npm run test:fast
. Através deste comando, todos os testes serão executados, entretanto, quando algum teste não for aprovado, a execução dos testes será imediatamente finalizada.
🗣 Nos dê feedbacks sobre o projeto!
Ao finalizar e submeter o projeto, não se esqueça de avaliar sua experiência preenchendo o formulário. Leva menos de 3 minutos!
FORMULÁRIO DE AVALIAÇÃO DE PROJETO
🗂 Compartilhe seu portfólio!
Você sabia que o LinkedIn é a principal rede social profissional e compartilhar o seu aprendizado lá é muito importante para quem deseja construir uma carreira de sucesso? Compartilhe esse projeto no seu LinkedIn, marque o perfil da Trybe (@trybe) e mostre para a sua rede toda a sua evolução.
🐉 Contextualizando 🐲
No universo de Trybers and Dragons - T&D, quase todos os seres que andam por essas terras pertencem a uma raça definida.
As diversas raças (como, por exemplo, Élfica, Orc ou Dwarf) definem as características das personagens dentro do jogo desde a sua criação, como os seus pontos de vida e a sua destreza. No entanto, existem seres bestiais denominados monstros que não possuem uma raça específica, mas podem lutar.
Alguns seres também possuem uma energia e, ao treinarem o uso da energia, passam a possuir um arquétipo. De modo geral, os arquétipos definem a vocação de uma personagem, suas habilidades e visão de mundo: como encaram as situações, exploram masmorras ou enfrentam monstros. Como exemplos de arquétipos presentes em T&D, podemos citar guerreiro, mago e necromante.
Boa parte dos seres podem ser considerados lutadores, bastando para isso possuir alguns atributos específicos. Em muitas ocasiões podem acontecer lutas entre personagens diversas, bem como entre personagens e monstros.
Agora, cabe a você, nobre dev, explorar essas terras e cumprir as quests que surgirão ao longo da sua incrível jornada leitura do README.
Now, follow the blind the dungeon master!
➕ Detalhes
No universo de Trybers and Dragons - T&D, quase todos os seres racionais têm uma raça e, embora todas as raças de personagens sejam humanoides, cada uma tem as suas particularidades.
A raça influencia desde a aparência geral até fatores como longevidade média, talento em determinadas habilidades ou mesmo a presença de algum sentido mais aguçado nos habitantes desse universo.
Para entender melhor um pouco da incrível diversidade que temos e as características únicas de algumas das raças de T&D, vamos começar nossa jornada com a missão de criar a classe abstrata Race
.
Para que você tenha sucesso nesta quest, é importante saber que:
- O arquivo deve ser criado no diretório
src/Races/
e se chamarRace.ts
; - A classe
Race
deve ter os atributos privados:name
edexterity
, ambos inicializados em seu construtor;- O atributo
name
dever ser do tipostring
; - O atributo
dexterity
dever ser do tiponumber
; name
edexterity
devem ser recebidos como parâmetros e inicializados no construtor.
- O atributo
- Os atributos da classe
Race
podem ser lidos, mas não podem ser alterados:name
deve retornar o tipostring
;dexterity
deve retornar o tiponumber
.
- A classe
Race
deve ter um método estático chamadocreatedRacesInstances
, que retorna umnumber
;- Esse número corresponde à quantidade de instâncias criadas a partir das classes estendidas da classe
Race
; - Cada raça terá seu número máximo de instâncias, que será definido dentro de cada classe especializada;
- Na classe
Race
, o método deve lançar um erro com a mensagemNot implemented
.
- Esse número corresponde à quantidade de instâncias criadas a partir das classes estendidas da classe
- A classe
Race
deve ter um getter abstrato chamadomaxLifePoints
que retorna umnumber
;- Esse número corresponde à quantidade máxima de pontos de vida da raça;
- Cada raça terá seu número máximo de pontos, que será definido dentro de cada classe especializada;
- Na classe
Race
deve estar apenas a assinatura do método.
Dica: use a convenção de atributos privados para criar os atributos com
_
e os getters para expor os atributos sem o_
.
⚠️ Atenção:
- Para que os testes funcionem corretamente, a classe
Race
deve ser exportada de forma padrão (comexport default
);- Deve ser criado o arquivo chamado
index.ts
dentro do diretóriosrc/Races/
;- A classe
Race
deve ser importada dentro deste arquivo e exportada também de forma padrão, da mesma forma que no diretóriosrc/Battle/
.
🔎 O que será verificado
🐲 Para a classe Race:
- A classe
Race
existe; - A classe
Race
é abstrata; - O método
maxLifePoints
da classeRace
é abstrato; - O método
maxLifePoints
ao ser implementado retorna um valor numérico; - O atributo
name
da classeRace
pode ser lido; - O atributo
name
da classeRace
NÃO pode ser alterado; - O atributo
dexterity
da classeRace
pode ser lido; - O atributo
dexterity
da classe Race NÃO pode ser redefinido; - O método
createdRacesInstances
deve existir e ser estático; - O método
createdRacesInstances
deve lançar um erro com a mensagem "Not implemented".
➕ Detalhes
Já foi dito anteriormente que há uma diversidade de raças neste universo e agora chegou a hora de você saber mais a respeito de algumas delas. Nesta segunda quest, você irá criar classes para quatro raças que existem no mundo de T&D.
Antes de prosseguir com a missão, é muito importante saber que:
- Os arquivos devem ser criados no diretório
src/Races/
; - Todas as raças devem estender da classe abstrata
Race
; - As classes
Dwarf
,Elf
,Halfling
eOrc
devem ser criadas em arquivos com exatamente esses nomes. - Cada raça deve possuir um número máximo de pontos de vida (
maxLifePoints
), que deve ser inicializado em seu construtor:- A raça
Dwarf
deve receber80
pontos de vida; - A raça
Elf
deve receber99
pontos de vida; - A raça
Halfling
deve receber60
pontos de vida; - A raça
Orc
deve receber74
pontos de vida.
- A raça
- Não se esqueça de implementar o(s) método(s) necessário(s) após estender a classe abstrata
Race
; - Não se esqueça de fazer a sobrescrita (
override
) do(s) método(s) necessário(s).
⚠️ Atenção:
- Assim como no requisito anterior, cada uma das classes criadas (
Dwarf
,Elf
,Halfling
eOrc
) para este requisito deve ser exportada de forma padrão (comexport default
).- As classes (
Dwarf
,Elf
,Halfling
eOrc
) devem ser importadas dentro desrc/Races/index.ts
e exportadas de forma explícita (export { class1, class2, classN }
).- Não se esqueça de implementar o método
createdRacesInstances
nas classes herdeiras;
🔎 O que será verificado
🐲 Para as classe que herdam de Race:
- A classe
Dwarf
existe; - A classe
Dwarf
herda deRace
; - O atributo
name
da classeDwarf
pode ser lido; - O atributo
dexterity
da classeDwarf
pode ser lido; - O método
createdRacesInstances
retorna o número correto de instâncias criadas da classeDwarf
; - O atributo
maxLifePoints
da classeDwarf
existe e é igual a 80; - A classe
Elf
existe; - A classe
Elf
herda deRace
; - O atributo
name
da classeElf
pode ser lido; - O atributo
dexterity
da classeElf
pode ser lido; - O método
createdRacesInstances
retorna o número correto de instâncias criadas da classeElf
; - O atributo
maxLifePoints
da classeElf
existe e é igual a 99; - A classe
Halfling
existe; - A classe
Halfling
herda deRace
; - O atributo
name
da classeHalfling
pode ser lido; - O atributo
dexterity
da classeHalfling
pode ser lido; - O método
createdRacesInstances
retorna o número correto de instâncias criadas da classeHalfling
; - O atributo
maxLifePoints
da classeHalfling
existe e é igual a 60; - A classe
Orc
existe; - A classe
Orc
herda deRace
; - O atributo
name
da classeOrc
pode ser lido; - O atributo
dexterity
da classeOrc
pode ser lido; - O método
createdRacesInstances
retorna o número correto de instâncias criadas da classeOrc
; - O atributo
maxLifePoints
da classeOrc
existe e é igual a 74;
➕ Detalhes
Energia é um atributo vital para a maioria dos seres. No contexto de Trybers and Dragons
, a energia gasta ao se andar, nadar, escalar ou lutar é chamada de "stamina" .
Contudo, esse universo também abriga seres capazes de usar magia. Nesses casos, a energia gasta é chamada de "mana".
Sua próxima missão é tornar possível o uso destes dois tipos de energia: "stamina" e "mana". Para isso:
- Crie uma
interface
chamadaEnergy
, para isso:- Crie o arquivo
Energy.ts
na raiz do diretóriosrc/
. - A interface deverá possuir os atributos:
type_
, do tipoEnergyType
; ✨✨- Esse novo tipo
podedeve receber os valores:'mana'
ou'stamina'
; - O tipo
EnergyType
também deve ser exportado.
- Esse novo tipo
amount
, do tiponumber
.
- Crie o arquivo
✨ Dica de mestre: ✨
- Para implementar a
interface Energy
, é necessário criar um tipo novo, otype EnergyType
;
⚠️ Atenção:
- Para que os testes funcionem corretamente, a interface
Energy
deve ser exportada de forma padrão ( comexport default
).EnergyType
também deve ser exportado, mas este de forma explícita (export
).
🔎 O que será verificado
🐲 Para a interface Energy:
- É possível criar uma variável com o tipo
EnergyType
e atribuir a ela o valor'mana'
; - É possível criar uma variável com o tipo
EnergyType
e atribuir a ela o valor'stamina'
; - É possível criar uma variável com o tipo da interface
Energy
e atribuir a ela o valor{ amount: 10, type_: 'stamina'}
; - É possível criar uma variável com o tipo da interface
Energy
e atribuir a ela o valor{ amount: 45, type_: 'mana'}
; - Não é possível criar uma variável com o tipo
EnergyType
e atribuir a ela um valor diferente de'mana'
ou'stamina'
; - Não é possível criar uma variável com o tipo da interface
Energy
sem atribuir a ela umamount
; - Não é possível criar uma variável com o tipo da interface
Energy
sem atribuir a ela umtype_
.
➕ Detalhes
Dentro do nosso universo, os seres têm talentos especiais e cada um desses talentos tem o seu nome dentro de T&D.
Aqui vamos ter alguns atributos super legais e necessários, que representarão o nome, a potência do seu ataque especial e o custo energético para utilizá-lo. Por isso, sua próxima quest será criar a classe abstrata Archetype
.
Para que você tenha sucesso nesta quest, é importante saber que:
- O arquivo
Archetype.ts
deve ser criado no diretóriosrc/Archetypes/
; - A classe
Archetype
deve ter os atributos privados:name
,special
,cost
, que serão inicializados em seu construtor;- O atributo
name
dever ser do tipostring
; - O atributo
special
dever ser do tiponumber
; - O atributo
cost
dever ser do tiponumber
; name
deve ser recebido como parâmetro e inicializado no construtor;special
ecost
devem ser apenas inicializados no construtor com o valor0
.
- O atributo
- Os atributos da classe
Archetype
podem ser lidos, mas não podem ser alterados:name
deve retornar o tipostring
;special
deve retornar o tiponumber
;cost
deve retornar o tiponumber
.
- A classe
Archetype
deve ter um método estático chamadocreatedArchetypeInstances
que retorna umnumber
:- Esse número corresponde à quantidade de instâncias criadas a partir das classes estendidas da classe abstrata
Archetype
; - Cada arquétipo terá seu número máximo de instâncias, que será definido dentro de suas classes especializadas;
- Na classe abstrata
Archetype
, o método deve apenas lançar um erro com a mensagemNot implemented
.
- Esse número corresponde à quantidade de instâncias criadas a partir das classes estendidas da classe abstrata
- A classe
Archetype
deve ter um getter abstrato chamadoenergyType
que retorna umaEnergyType
:- Esse tipo EnergyType corresponde ao tipo de energia que este arquétipo deve ter. (
mana
oustamina
) - Cada arquétipo terá o seu tipo de energia, que será definido dentro de suas classes especializadas;
- A classe abstrata
Archetype
deve conter apenas a assinatura do método.
- Esse tipo EnergyType corresponde ao tipo de energia que este arquétipo deve ter. (
⚠️ Atenção:
- Para que os testes funcionem corretamente, a classe
Archetype
deve ser exportada de forma padrão ( comexport default
);- Um arquivo
index.ts
deve ser criado dentro do diretóriosrc/Archetypes/
;- A classe
Archetype
deve ser importada dentro deste arquivo e exportada também de forma padrão, como feito comRace
.
🔎 O que será verificado
🐲 Para a classe Archetype:
- A classe
Archetype
existe; - A classe
Archetype
é abstrata; - O atributo
name
da classeArchetype
pode ser lido; - O atributo
name
da classeArchetype
não pode ser alterado; - O atributo
special
da classeArchetype
pode ser lido; - O atributo
cost
da classeArchetype
pode ser lido; - O tipo do retorno do método
energyType
éEnergyType
;
➕ Detalhes
Como você pode imaginar, há diversos arquétipos diferentes no mundo de Trybers and Dragons, cada um com as suas peculiaridades e alinhamentos. Agora, chegou a hora de você conhecer alguns desses arquétipos. E o que poderia ser melhor para isso do que criar classes para eles? Para isto, atenção às instruções a seguir:
- Os arquivos devem ser criados no diretório
src/Archetypes/
; - Todos os arquétipos devem estender da classe abstrata
Archetype
. - No momento, vamos nos ater a quatro arquétipos muito comuns aos seres deste universo: (eles devem estar em quatro arquivos com os mesmos nomes)
Mage
🧙♀️;Necromancer
☠️;Warrior
⚔️;Ranger
🍃.
- Cada arquétipo possui a habilidade de causar danos em seus inimigos de forma diferente, e essa habilidade deve ser inicializada em seu construtor
- Os arquétipos
Mage
🧙♀️ eNecromancer
☠️ causam dano por meio de magia, através do uso demana
; - Os arquétipos
Warrior
⚔️ eRanger
🍃 causam dano por meio de sua força, usandostamina
.
- Os arquétipos
- Não se esqueça de implementar o(s) método(s) necessário(s) após estender a classe abstrata
Archetype
; - Não se esqueça de fazer a sobrescrita (
override
) do(s) método(s) necessário(s);
⚠️ Atenção:
- Assim como no requisito anterior, cada uma das classes criadas (
Mage
,Necromancer
,Warrior
eRanger
) para este requisito deve ser exportada de forma padrão ( comexport default
);- Novamente, as classes (
Mage
,Necromancer
,Warrior
eRanger
) devem ser importadas dentro desrc/Archetypes/index.ts
e exportadas de forma explícita (export { class1, class2, classN }
).- Não se esqueça de implementar o método
createdArchetypeInstances
nas classes herdeiras;
🔎 O que será verificado
🐲 Para as classes que herdam de Archetype:
- A classe
Mage
existe; - A classe
Mage
herda deArchetype
; - O atributo
name
da classeMage
pode ser lido; - O método
energyType
da ClasseMage
existe e retorna umEnergyType
; - O método
createdArchetypeInstances
deve retornar o número correto de instâncias criadas da classeMage
; - A classe
Necromancer
existe; - A classe
Necromancer
herda deArchetype
; - O atributo
name
da classeNecromancer
pode ser lido; - O atributo
energyType
da classeNecromancer
pode ser lido; - O método
createdArchetypeInstances
deve retornar o número correto de instâncias criadas da classeNecromancer
; - A classe
Ranger
existe; - A classe
Ranger
herda deArchetype
; - O atributo
name
da classeRanger
pode ser lido; - O atributo
energyType
da classeRanger
pode ser lido; - O método
createdArchetypeInstances
deve retornar o número correto de instâncias criadas da classeRanger
; - A classe
Warrior
existe; - A classe
Warrior
herda deArchetype
; - O atributo
name
da classeWarrior
pode ser lido; - O atributo
energyType
da classeWarrior
pode ser lido; - O método
createdArchetypeInstances
deve retornar o número correto de instâncias criadas da classeWarrior
;
➕ Detalhes
Um universo tão rico e cheio de diferentes seres, com diferentes alinhamentos, convicções e personalidades pode não ser um lugar sempre amigável. Por isso, seus habitantes têm que ser capazes de se defender ou de inventar artimanhas para se livrarem de brigas, confusões e armadilhas. Sendo assim, podemos dizer que todos os seres de T&D são, em essência, lutadores.
Para fixar bem esse conceito, preparamos para você a missão especial de criar a interface Fighter
. Mas não se preocupe! Não deixaremos você dar mais nem um passo sem as informações necessárias para tirar isso de letra! Observe as orientações abaixo:
- Crie uma
interface
chamadaFighter
; - O arquivo
Fighter.ts
deve ser criado no diretóriosrc/Fighter/
; - A interface deverá possuir os atributos:
lifePoints
, do tiponumber
;strength
, do tiponumber
;defense
, do tiponumber
;energy
, do tipoEnergy
. ✨✨
- A interface deverá possuir os métodos:
attack()
, que recebe umenemy
do tipoFighter
como parâmetro e não possui retorno (void
);special()
, que recebe umenemy
do tipoFighter
como parâmetro e não possui retorno (void
); ✨✨levelUp()
, que não recebe parâmetro e não possui retorno (void
);receiveDamage()
, que recebe umattackPoints
do tiponumber
como parâmetro e retorne umnumber
.
✨ Dica de mestre: ✨
- O atributo
energy
e o métodospecial()
devem ser opcionais;- Pesquise sobre:
Optional Properties
ouOptional parameters
em interfaces;
- Pesquise sobre:
- Agora você pode descomentar os trechos de código dos arquivos do diretório
Battle
; (Battle.ts
eindex.ts
).
⚠️ Atenção:
- Para que os testes funcionem corretamente, a interface
Fighter
deve ser exportada de forma padrão (comexport default
);- Um arquivo chamado
index.ts
deve ser criado dentro do diretóriosrc/Fighter/
;- A interface
Fighter
deve ser importada dentro deste arquivo e exportada também de forma padrão, como feito em requisitos anteriores.
🔎 O que será verificado
🐲 Para a interface Fighter:
- A interface
Fighter
existe; - A interface
Fighter
possui o atributolifePoints
; - A interface
Fighter
possui o atributostrength
; - A interface
Fighter
possui o atributodefense
; - A interface
Fighter
possui o métodoattack()
, que recebe umenemy
do tipoFighter
; - A interface
Fighter
possui o métodospecial()
, que recebe umenemy
do tipoFighter
- A interface
Fighter
possui o métodoreceiveDamage()
, que recebe umattackPoints
do tipo number; - O atributo
energy
deverá ser do tipoEnergy
, definido no arquivosrc/Energy.ts
; - A interface
Fighter
possui o métodolevelUp()
, que não recebe parâmetros nem retorna nada;
➕ Detalhes
Maravilha! Agora já temos tanto as nossas raças quanto os nossos arquétipos e interfaces definidos. Mas antes de sair por aí entrando em tavernas e calabouços, temos outra quest: criar uma personagem!
Cada personagem será composta tanto por uma raça quanto por um arquétipo. Essa classe reunirá um conjunto de características que terão o poder de fazer desse ser o mais único possível. Além disso, personagens devem possuir tudo o que se espera de alguém que luta.
As dicas para completar essa quest são:
- O arquivo deve ser criado na raiz do diretório
src/
e se chamarCharacter.ts
; - A classe deve implementar a interface
Fighter
; - A classe
Character
deve ter os atributos privados:race
,archetype
,maxLifePoints
,lifePoints
,strength
,defense
,dexterity
eenergy
, todos inicializados em seu construtor;- O atributo
race
deve ser do tipoRace
; - O atributo
archetype
deve ser do tipoArchetype
; - O atributo
maxLifePoints
deve ser do tiponumber
; - O atributo
lifePoints
deve ser do tiponumber
; - O atributo
strength
deve ser do tiponumber
; - O atributo
defense
deve ser do tiponumber
; - O atributo
dexterity
deve ser do tiponumber
; - O atributo
energy
deve ser do tipoEnergy
; - O atributo
name
deve ser recebido como parâmetro no construtor e deve ser usado para dar nome à sua personagem. - Devem ser inicializados no construtor:
dexterity
com um valor aleatório de no mínimo 1 e no máximo 10 pontos. ✨✨;race
por padrão com uma instância deElf
(A destreza deElf
deve ser a mesma definida emdexterity
);archetype
por padrão com uma instância deMage
;maxLifePoints
por padrão com metade domaxLifePoints
da raça instanciada;lifePoints
por padrão com o mesmo valor demaxLifePoints
da classe;strength
,defense
com valores aleatórios de no mínimo 1 e no máximo 10 pontos; ✨✨energy
por padrão:type_
com o mesmo valor do arquétipo instanciado;amount
com um valor aleatório de no mínimo 1 e no máximo 10 pontos. ✨✨
- O atributo
- Os atributos da classe
Character
podem ser lidos mas não podem ser alterados:race
deve retornar o tipoRace
;archetype
deve retornar o tipoArchetype
lifePoints
deve retornar o tiponumber
;strength
deve retornar o tiponumber
;defense
deve retornar o tiponumber
;dexterity
deve retornar o tiponumber
;energy
deve retornar o tipoEnergy
.- ✨ Lembre-se que
energy
é um objeto, portanto se você retornar ele diretamente o javascript permite que as propriedades desse objetos sejam alteradas, mesmoenergy
sendo privado.
- ✨ Lembre-se que
- A classe
Character
também deve implementar os métodos estendidos dainterface Fighter
;receiveDamage 😵
este método recebe por parâmetro um valor (attackPoints
) e as regras são:- Para calcular o dano recebido (
damage
), o valor da defesa (defense
) do personagem deve ser subtraído do valor do ataque recebido (attackPoints
); - Se o dano calculado (
damage
) for maior que0
, você perde esse valor em pontos de vida (lifePoints
). Se o dano calculado (damage
) for igual ou menor a zero, você deve perder apenas1
ponto de vida (lifePoints
); - Ao receber o ataque e perder pontos de vida (
lifePoints
), e se sua vida chegar a0
ou menos, você deve fixá-la com o valor-1
; - Ao final sempre retorne o valor atualizado de seus pontos de vida.
- Para calcular o dano recebido (
attack 🪄
este método recebe por parâmetro uma pessoa inimiga (enemy
) e as regras são:- Toda vez que acontecer um ataque, o inimigo recebido por parâmetro recebe um dano;
- Este dano deve ser equivalente a força (
strength
) de quem ataca.
levelUp 🆙
este método não recebe parâmetro e as regras são:- Sempre que este método for chamado os atributos
maxLifePoints
,strength
,dexterity
edefense
terão um incremento de no mínimo 1 e no máximo 10 pontos; ✨✨ - Assim como os atributos anteriores o montante de energia (
amount
dentro deenergy
) deve ser alterado também, ele deve ficar cheio, valendo exatamente10
; - O atributo
maxLifePoints
do Character nunca poderá ser maior que omaxLifePoints
de sua raça (race
). Se, ao incrementar o valor demaxLifePoints
do Character esse valor ficar maior do que omaxLifePoints
da raça, ele deve receber o valor igual ao do da raça. Exemplo: se omaxLifePoints
da raça é 100, e o do Character é 95, e ao fazer o levelUp ele ficaria 8 pontos maior, isso daria 103, que é maior do que o da raça, portanto você deveria deixar em 100. - Ao final, o atributo
lifePoints
também deve ser atualizado, recebendo o novo valor demaxLifePoints
(de acordo com as regras anteriores).
- Sempre que este método for chamado os atributos
special ⚡
este método não recebe parâmetro e as regras é você quem decide:- Aqui você pode expandir sua mente e realizar a lógica que achar mais interessante para um ataque especial, use tudo que aprendeu no mundo de T&D! 🐲
- Esta parte do requisito não esta sendo avalida é apenas para você se divertir aprendendo. 💚
✨ Dica de mestre: ✨
- Para gerar valores aleatórios, use a função
getRandomInt
fornecida no arquivosrc/utils.ts
.
⚠️ Atenção:
- Para que os testes funcionem corretamente, a classe
Character
deve ser exportada de forma padrão ( comexport default
).
🔎 O que será verificado
🐲 Para a classe Character:
- A classe
Character
existe; - A classe
Character
implementa a interfaceFighter
; Character
possui umaRace
;Character
possui umArchetype
;Character
possui um atributolifePoints
, que pode ser lido, mas não pode ser setado;Character
possui um atributostrength
, que pode ser lido, mas não pode ser setado;Character
possui um atributodefense
, que pode ser lido, mas não pode ser setado;Character
possui um atributoenergy
, que pode ser lido, mas não pode ser setado nem ter um de seus valores internos alterados;Character
possui um atributodexterity
, que pode ser lido, mas não pode ser setado;Character
pode subir de nível através do métodolevelUp
, e seus atributos (amount
,maxLifePoints
,strength
,dexterity
,defense
) terão um incremento;Character
pode receber danos através do métodoreceiveDamage
;Character1
pode atacarCharacter2
;
➕ Detalhes
Uau, o nosso universo de T&D está ficando fabuloso! No entanto, nem todo mundo que luta possui capacidades avançadas, como ter uma defesa ou realizar ataques especiais. Dito isto, vamos para mais uma quest: criar a interface lutador simples
As dicas para completar essa quest são:
- Crie uma
interface
chamadaSimpleFighter
; - O arquivo
SimpleFighter.ts
deve ser criado no diretóriosrc/Fighter/
. - A interface deverá possuir os atributos:
lifePoints
, do tiponumber
;strength
, do tiponumber
.
- A interface deverá possuir os métodos:
attack()
que recebe umenemy
do tipoSimpleFighter
como parâmetro e não possui retorno (void
);receiveDamage()
que recebe umattackPoints
do tiponumber
como parâmetro e retorne umnumber
;
- Aqui é um bom momento para treinarmos algumas skills deste bloco e aplicar uma refatoração, além disso você acaba adiantando uma parte do próximo requisito ✨. Utilize a segregação de interfaces, volte e observe nossa
interface Fighter
.
⚠️ Atenção:
- Para que os testes funcionem corretamente, a interface
SimpleFighter
deve ser exportada de forma padrão (comexport default
);- A interface
SimpleFighter
deve ser importada dentro desrc/Fighter/index.ts
e deve ser exportada de forma explícita (export { SimpleFighter }
), como feito em requisitos anteriores.
🔎 O que será verificado
🐲 Para a interface SimpleFighter:
- A interface
SimpleFighter
existe; - A interface
SimpleFighter
possui o atributolifePoints
; - A interface
SimpleFighter
possui o atributostrength
; - A interface
SimpleFighter
possui o métodoattack
, que recebe umenemy
do tipoSimpleFighter
; - A interface
SimpleFighter
possui o métodoreceiveDamage
, que recebe umattackPoints
do tiponumber
;
➕ Detalhes
Se existem seres que implementam a interface Fighter
, deve existir seres que implementam a interface SimpleFighter
também, não é ? Estes são os Monsters
, criaturas bestiais que apenas atacam outros seres. Então, sua próxima quest é: criar a classe Monster!
O que você deve saber para seguir em frente:
- O arquivo deve ser criado na raiz do diretório
src/
e chamarMonster.ts
; - A classe deve implementar a interface
SimpleFighter
; - A classe
Monster
deve ter os atributos privadoslifePoints
estrength
, ambos inicializados em seu construtor:- Os atributos
lifePoints
estrength
devem ser do tiponumber
; - Devem ser inicializados no construtor:
lifePoints
por padrão com o valor de85
;strength
por padrão com o valor de63
.
- Os atributos
- Os atributos da classe
Monster
podem ser lidos mas não podem ser alterados:lifePoints
estrength
devem retornar o tiponumber
.
- A classe
Monster
também deve implementar os métodos estendidos dainterface SimpleFighter
:receiveDamage 😵
este método recebe por parâmetro um valor (attackPoints
) e as regras são:- Este valor deve ser decrescido de seus pontos de vida (
lifePoints
), assim causando um dano (damage
); - Ao receber o ataque, sua vida nunca poderá chegar a
0
, se isto acontecer seuslifePoints
devem valer-1
; - Ao final o método deve retornar o valor atualizado dos pontos de vida.
- Este valor deve ser decrescido de seus pontos de vida (
attack 🪄
este método recebe por parâmetro uma pessoa inimiga (enemy
) e as regras são:- Toda vez que acontecer um ataque, o inimigo recebido por parâmetro recebe um dano;
- Este dano deve ser calculado a partir de
attackPoints
equivalentes à força (strength
) de quem ataca.
✨ Dica de mestre: ✨
- Aqui vamos precisar que os métodos de
Fighter
que recebiam um inimigo do tipoFighter
agora possam receber umSimpleFighter
. Assim umFighter
pode atacar umMonster
😄.
⚠️ Atenção:
- Para que os testes funcionem corretamente, a classe
Monster
deve ser exportada de forma padrão ( comexport default
).
🔎 O que será verificado
🐲 Para a classe Monster:
- A classe
Monster
existe; - A classe
Monster
implementa a interfaceSimpleFighter
; Monster
possui um atributolifePoints
, que pode ser lido, mas não pode ser setado;Monster
possui um atributostrength
, que pode ser lido, mas não pode ser setado;Monster
pode receber danos através do métodoreceiveDamage
, fazendo com que seuslifePoints
diminuam;Monster
pode atacar umCharacter
, e oCharacter
receberá dano;Character
pode atacar umMonster
, e oMonster
receberá de dano;
➕ Detalhes
A ideia do mundo de T&D ser completamente pacífico provavelmente já deve ter desaparecido da sua mente depois das suas últimas quests.
Nesse mundo, existem lutas, muitas delas inclusive épicas, denominadas Battles
(batalhas). Sua representação geral/abstrata já foi fornecida anteriormente, entretanto, existem tipos específicos de batalhas. Uma dessas batalhas chamamos de PVP
, batalhas entre personagens (ou player versus player), que só podem acontecer entre personagens lutadores (Fighters
). 🧙♀️ ⚔️ 🧙♂️
Sua quest agora é justamente criar a classe PVP, então, você que lute ! 🗡️😂 Brincadeira! Estamos aqui para te ajudar e por isso trazemos abaixo algumas dicas preciosas para garantir a sua vitória neste requisito:
- O arquivo deve ser criado no diretório
src/Battle/
e se chamarPVP.ts
; - A classe
PVP
deve herdar deBattle
; - A classe
Battle
já esta criada, dê uma espiada nela; 🧐 - Na criação de uma instância de
PVP
é esperado que em seu construtor sejam recebidos doisCharacters
lutadores, ambos inicializados lá; - Não se esqueça de fazer a sobrescrita (
override
) do(s) método(s) necessário(s). ✨✨
✨ Dica de mestre: ✨
-
Use um dos players para ser parâmetro do
super
na inicialização e use o métodofight
do super para dar o veredito da batalha, ou seja, sesuper.fight()
retornar 1 o player quer foi usado como parâmetro dosuper
na inicialização ganhou, e se retornar -1 a vitória foi do player que não foi o parâmetro dosuper
; -
Aqui
podemosdevemos sobrescrever o métodofight
;- No método
fight
sobrescrito, implemente uma lógica de ataque entre personagens lutadores da classe; - As personagens
devem batalhar
até uma das duas serderrotada
, em outras palavras, a batalha só deverá terminar, quando alguma personagem ter seus pontos de vida (lifePoints
) igual a-1
;
- No método
-
Se necessário, refatore o que já foi feito com as interfaces
Fighter
eSimpleFighter
para se adequarem melhor à sua nova implementação de batalha; -
Não esqueça de descomentar os trechos de código dos arquivos do diretório
Battle
como citado nas "Dica de mestre" do requisito 6 - Crie a interfaceFighter
.
⚠️ Atenção:
- Para que os testes funcionem corretamente, a classe
PVP
deve ser exportada de forma padrão (comexport default
);- Novamente, dentro de
src/Battle/index.ts
, a classe (PVP
) deve ser importada, porém esta deve ser exportada de forma normal (export { PVP }
), como feito em requisitos anteriores.
🔎 O que será verificado
🐲 Para a classe PVP:
- A classe
PVP
existe e pode ser criada uma nova instância, passando doisCharacters
lutadores; - A classe
PVP
pode ser utilizada onde a classeBattle
é esperada e uma personagem que chamou várias vezes o levelUp e possui melhores atributos tem maiores chances de vencer; - A classe
PVP
pode receber tanto doisCharacters
quanto duas instâncias de uma implementação diferente deFighter
;
➕ Detalhes
Nem todas as batalhas são entre personagens lutadoras (Character
), afinal, há perigos à solta que espreitam ao escurecer, em densas florestas ou em calabouços profundos.
Monstros representam alguns destes perigos, assim, temos as batalhas do tipo PVE
(player versus environment), em que personagens (sempre do tipo Fighter
) podem lutar contra um ou mais monstros assustadores (SimpleFighter
). Parece interessante, não é? Tornar isso possível é a sua próxima quest! 🧙♀️ ⚔️ 👾👹👻
Antes de prosseguir para essa nova batalha, leia atentamente as dicas abaixo !!! Só assim obteremos sucesso e prosperidade:
- O arquivo deve ser criado no diretório
src/Battle/
e se chamarPVE.ts
; - Lembre-se a classe
Battle
já esta criada; - Na criação de uma instância de
PVE.ts
é esperado que em seu construtor seja recebido uma pessoa personagem lutadora (Character Fighter
) e um array com pelo menos um monstro (Monster
), ambos inicializados no construtor;- Como estamos falando de uma batalha player versus environment, este array de monstros também aceita instâncias de pessoas personagens lutadoras sendo elas simples ou não; (
Fighter
,SimpleFighter
)
- Como estamos falando de uma batalha player versus environment, este array de monstros também aceita instâncias de pessoas personagens lutadoras sendo elas simples ou não; (
- Não se esqueça de fazer a sobrescrita (
override
) do(s) método(s) necessário(s);- Como na "Dica de mestre" do requisito anterior (
PVP
), não esqueça de implementar uma lógica de luta para este requisito também; - Lembre-se, aqui a luta é de uma personagem contra apenas um oponete ou uma legião deles. Logo, para a batalha ser finalizada, a personagem principal, ou seus oponentes, deverão ter perdido os seus respectivos pontos de vida (
lifePoints
).
- Como na "Dica de mestre" do requisito anterior (
⚠️ Atenção:
- Para que os testes funcionem corretamente, a classe
PVE
deve ser exportada de forma padrão (comexport default
);- Novamente dentro de
src/Battle/index.ts
a classe (PVE
) deve ser importada, porém desta vez de forma normal (export { PVP }
), como feito em requisitos anteriores.
🔎 O que será verificado
🐲 Para a classe PVE:
- A classe
PVE
existe e se pode ser criada uma nova instância, passando umCharacter
e um array com umMonster
; - A classe
PVE
pode ser utilizada onde a classeBattle
é esperada. Além disso, uma personagem (Character
) que chamou várias vezes o métodolevelUp
e possui melhores atributos tem maiores chances de vencer uma luta contra somente umMonster
, enquanto uma personagem com atributos menores perde uma luta contra diversosMonsters
; - A classe
PVE
pode receber tantoCharacter
e um array com umMonster
quanto implementações diferentes deFighter
eSimpleFighter
que não sãoCharacter
nemMonster
;
➕ Detalhes
Seria muito estranho se esse mundo se chamasse Trybers and Dragons e não existissem Dragons
, não é mesmo?
Estes seres magníficos são representados como monstros aqui, mas com a característica especial de possuírem elevados valores de pontos de vida.
Nesta quest, você deve criar a classe Dragon
, cuidando para garantir que:
- O arquivo deve ser criado na raiz de
src/
e se chamarDragon.ts
; - A classe
Dragon
deve herdar deMonster
; - Como citado acima, um Dragão tem elevados valores de pontos de vida, então em seu construtor defina o valor de
_lifePoints
sendo igual a 999; 🐲🐲
🐲 Dica de mestre: 🐲
- Aqui é interessante voltar no conteúdo do course sobre Herança e Interfaces e relembrar um pouco de Atributos protegidos;
⚠️ Atenção:
- Para que os testes funcionem corretamente, a classe
Dragon
deve ser exportada de forma padrão ( comexport default
).
🔎 O que será verificado
🐲 Para a classe Dragon:
- A classe
Dragon
existe; - A classe
Dragon
herda deMonster
; Dragon
deve ter 999 no valor do atributolifePoints
;
➕ Detalhes
Você já modelou todo o mundo de T&D, maravilha!
Agora repare que, por mais que a gente saiba o que são Monster
, Character
, Dragon
, PVE
, etc, nenhum desses foi visto em ação. Então a sua última quest para completar essa aventura é dar vida às suas personagens e criar algumas instâncias das classes criadas anteriormente. 🪄
Algumas dicas se fazem necessárias para completar sua última missão no mundo de T&D. Elas são:
- O arquivo deve ser criado na raiz de
src/
e se chamarindex.ts
; ⚠️ Preste bastante atenção nos nomes das variáveis/métodos e nas exportações pedidas deste último requisito; 😉.- Crie
3
objetos do tipoCharacter
:- As variáveis devem-se chamar
player1
,player2
eplayer3
; - Execute algumas vezes o método
levelUp
doplayer1
; - Ao final do arquivo
index.ts
exporteplayer1
,player2
eplayer3
.
- As variáveis devem-se chamar
- Crie
2
objetos do tipoMonster
:- As variáveis devem se chamar
monster1
emonster2
; monster1
deve ser umMonster
emonster2
deve ser umDragon
;- Ao final do arquivo
index.ts
exportemonster1
emonster2
.
- As variáveis devem se chamar
- Crie um objeto do tipo
PVP
:- A variável deve se chamar
pvp
; - Como parâmetro do construtor passe
player2
eplayer3
; - Ao final do arquivo
index.ts
exportepvp
. - NÃO execute o método
pvp.fight
;
- A variável deve se chamar
- Crie um objeto do tipo
PVE
:- A variável deve se chamar
pve
; - Como parâmetro do construtor passe
player1
e um array contendomonster1
emonster2
; - Ao final do arquivo
index.ts
exportepve
. - NÃO execute o método
pve.fight
;
- A variável deve se chamar
- Crie uma função chamada
runBattles
:- A função recebe por parâmetro um array de batalhas (
battles
) e este array é do tipoBattle
; ✨✨ - Dentro da função, crie uma repetição percorrendo este array e chame o método
fight
; - Ao final do arquivo
index.ts
exporterunBattles
.
- A função recebe por parâmetro um array de batalhas (
✨ Última dica de mestre: ✨
- Lembre-se
Battle
não pode ser instanciada, pois é uma classe abstrata;
⚠️ Atenção:
- Para que os testes funcionem corretamente, os objetos/métodos criados em
src/index.ts
devem ser exportados como explicado no requisito;
🔎 O que será verificado
🐲 Para a criação de objetos no arquivo index:
- Existem 3 objetos do tipo
Character
no arquivoindex
, exportados comoplayer1
,player2
eplayer3
e o métodolevelUp
foi chamado algumas vezes emplayer1
- Existem 2 objetos do tipo
Monster
no arquivoindex
, exportados comomonster1
,monster2
, sendo que o objetomonster2
é umDragon
; - Existe um objeto do tipo
PVP
(com osCharacters
player2
eplayer3
), exportados no arquivo index comopvp
e nele NÃO foi executado o métodopvp.fight
; - Existe um objeto do tipo
PVE
(com oCharacter
player1
e com osMonsters
monster1
emonster2
), exportado no arquivoindex
comopve
e nele NÃO foi executado o métodopve.fight
; - Existe uma função chamada
runBattles
, que recebe umarray de Battles
e chama em seu interior o métodobattle.fight
;