Files
portifolio-evandrodevbr/lib/jogo/valores.ts
T
evandro 67b32fcab3
CI / audit (push) Successful in 10m48s
CI / verify (push) Successful in 19m2s
CI / deploy (push) Successful in 2m14s
CI / e2e (push) Failing after 36m15s
feat(jogo): expediente dos mortos, jogo de zumbis em primeira pessoa
Etapa 1 inteira (logica com 100% de cobertura, cena 3D, toque, sons, bancada de desempenho, e2e) e a base da etapa 2 (mapa novo no Tiled, texturas, imagens dos itens, sons conferidos, golpe recortado e medido). Pagina /jogo fora do menu e do sitemap ate a medicao no celular.
2026-11-10 19:37:10 -03:00

206 lines
6.9 KiB
TypeScript

/** Números do jogo em um lugar só. São valores iniciais: mudam jogando, nunca espalhados pelo código. */
import GOLPE from "./golpe.json";
import type { Dificuldade, TipoItem, TipoZumbi } from "./tipos";
/** Duração de um passo da lógica, em segundos. */
export const PASSO = 1 / 60;
export const PASSOS_POR_SEGUNDO = 60;
export const JOGADOR = {
vida: 100,
/** m/s */
velocidade: 4.2,
raio: 0.35,
/** Altura dos olhos, de onde sai o tiro. */
olhos: 1.6,
/** Limite da inclinação, para cima e para baixo. */
inclinacaoMax: 1.2,
/** Vida devolvida quando uma horda cai. */
curaPorHorda: 25,
} as const;
export const ZUMBIS: Record<
TipoZumbi,
{
vida: number;
velocidade: number;
dano: number;
raio: number;
altura: number;
}
> = {
comum: { vida: 100, velocidade: 1.2, dano: 10, raio: 0.35, altura: 1.8 },
rapido: { vida: 50, velocidade: 2.4, dano: 6, raio: 0.3, altura: 1.7 },
blindado: { vida: 250, velocidade: 0.9, dano: 15, raio: 0.4, altura: 1.9 },
chefao: { vida: 1500, velocidade: 1.0, dano: 25, raio: 0.6, altura: 2.4 },
};
/** Passos de um golpe inteiro (preparo, impacto e volta): 0,8 s. */
const PASSOS_DO_GOLPE = 48;
export const ATAQUE_DO_ZUMBI = {
/** Distância entre as bordas do zumbi e do jogador para o ataque começar. */
alcance: 1.0,
/** Folga máxima, no passo do impacto, para o golpe acertar. Acima disso o golpe pega o ar. */
alcanceDoGolpe: 1.4,
/** Passos entre um golpe e o próximo. Etapa 2: passa a `PASSOS_DO_GOLPE`. */
intervalo: 60,
/**
* Passo do ciclo em que a mão bate. Vem do clipe `atacar` medido no Blender
* (`golpe.json`, gravado por `3d/jogo.py`): a tela toca o clipe no tempo do ciclo,
* então o impacto do clipe e o da lógica caem no mesmo passo.
*/
passoDoGolpe: Math.round((GOLPE.impacto / GOLPE.duracao) * PASSOS_DO_GOLPE),
/** Passos da animação de morte, até o zumbi sair da lista. */
passosMorrendo: 90,
} as const;
/** Acima desta fração da altura do zumbi o acerto é na cabeça e dobra o dano. */
export const FRACAO_DA_CABECA = 0.86;
export const MULTIPLICADOR_DA_CABECA = 2;
export const ARMAS = [
{ nome: "Pistola", dano: 34, intervalo: 20, alcance: 40, gasta: false },
{ nome: "Automática", dano: 20, intervalo: 6, alcance: 40, gasta: true },
{ nome: "Faca", dano: 100, intervalo: 30, alcance: 1.5, gasta: false },
] as const;
/** Meio ângulo do arco da faca, em radianos. */
export const ARCO_DA_FACA = Math.PI / 4;
export const MUNICAO = {
inicial: 90,
porCaixa: 30,
/** Chance de um zumbi morto largar uma caixa. */
chanceDeCaixa: 0.25,
/** Distância para o jogador recolher a caixa. */
raioDeColeta: 0.9,
} as const;
/** O que os zumbis largam ao morrer. */
export const ITENS = {
/** Chance de um zumbi morto largar um item. O chefão não larga. */
chance: 0.3,
/** Peso de cada tipo no sorteio. */
pesos: { municao: 45, kit: 25, cafe: 15, bateria: 15 } as Record<
TipoItem,
number
>,
/** Abaixo desta vida o peso do kit dobra. */
vidaBaixa: 40,
/** Itens no chão ao mesmo tempo; com o teto cheio, o mais antigo some. */
teto: 10,
/** Passos até o item sumir (20 s). */
duracao: 1200,
/** Distância para o jogador recolher. */
raioDeColeta: 0.9,
/** Balas da automática por item de munição. */
balas: 30,
/** Vida devolvida pelo kit. */
vida: 25,
/** Café: fator da velocidade de andar e passos que dura (8 s). */
cafe: { fator: 1.3, duracao: 480 },
/** Bateria: fator da cadência dos drones e passos que dura (10 s). */
bateria: { fator: 2, duracao: 600 },
} as const;
export const DRONE = {
dano: 25,
intervalo: 30,
alcance: 15,
/** m/s */
velocidade: 5,
/** Distância que o drone mantém do jogador. */
distancia: 2,
} as const;
export const HORDAS = {
/** Zumbis das três hordas, antes do multiplicador da dificuldade. */
tamanhos: [12, 16, 20],
/** Comuns que acompanham o chefão. */
escoltaDoChefao: 6,
/** Passos da pausa entre hordas. */
pausa: 300,
/** Passos da fase "inicio", antes da primeira horda. */
preparo: 120,
/** Passos entre dois nascimentos, por horda (a 4ª é a do chefão). */
nascerACada: [90, 50, 30, 30],
/** Fator da velocidade dos zumbis, por horda. */
velocidade: [0.8, 1, 1.15, 1.15],
} as const;
/** Quantas linhas o feed guarda. */
export const LINHAS_DO_FEED = 5;
export const TETO_A_VISTA = 16;
export const DIFICULDADES: Record<
Dificuldade,
{ velocidade: number; dano: number; quantidade: number }
> = {
facil: { velocidade: 0.6, dano: 0.4, quantidade: 0.7 },
normal: { velocidade: 1, dano: 1, quantidade: 1 },
dificil: { velocidade: 1.3, dano: 1.5, quantidade: 1.3 },
};
/**
* O escritório, em células de 1 m. `#` parede, `M` mesa (não dá para andar, o tiro passa),
* `J` onde o jogador começa, `N` onde os zumbis nascem, `.` chão.
*/
export const ESCRITORIO = [
"############################",
"#N.........#......#.......N#",
"#..MM..MM..#......#..MM....#",
"#..MM..MM.........#..MM....#",
"#..........#...............#",
"#..MM..MM..#......#..MM....#",
"#..MM..MM..###..###........#",
"#..........................#",
"#............J.............#",
"#..........................#",
"#..MM..MM..###..###..MM....#",
"#..MM..MM..#......#..MM....#",
"#..........#......#........#",
"#..MM..MM.........#..MM....#",
"#..MM..MM..#...............#",
"#N.........#......#.......N#",
"############################",
] as const;
/** Degraus de qualidade da tela, do melhor para o mais leve. Desce na ordem: resolução, sombras, zumbis à vista. */
export const NIVEIS = [
{ pixelRatio: 2, sombras: true, teto: 16 },
{ pixelRatio: 1.5, sombras: true, teto: 16 },
{ pixelRatio: 1, sombras: true, teto: 16 },
{ pixelRatio: 1, sombras: false, teto: 16 },
{ pixelRatio: 1, sombras: false, teto: 12 },
{ pixelRatio: 1, sombras: false, teto: 8 },
] as const;
/** Tempos em milissegundos. */
export const REGULADOR = {
/** Tamanho da janela em que o p95 do intervalo entre quadros e o do trabalho são medidos. */
janela: 2000,
/** p95 do intervalo acima disto na janela: desce um degrau. */
limite: 20,
/** Janela sem descida e com p95 do trabalho de JS abaixo disto conta como folga. */
folgaDeTrabalho: 6,
/** Tempo seguido de folga para subir um degrau. */
subida: 10000,
/** Quadro mais longo que isto é pausa da aba, não lentidão: não entra na conta. */
ignorar: 250,
/** Se descer de novo antes disto depois de subir, não sobe mais. */
trava: 20000,
/** Fração mínima em que o p95 do intervalo cai na janela seguinte a uma descida para ela contar como ganho. */
ganho: 0.1,
/** Descidas seguidas sem ganho que fazem o regulador voltar esses degraus e travar. */
descidasSemGanho: 2,
} as const;
/**
* Raio máximo usado para andar e desviar de parede. O chefão é mais largo que meia célula (0,6 m): com o raio inteiro
* ele nasce encostado na parede e não sai do lugar. Para levar tiro, vale o raio do tipo.
*/
export const RAIO_DE_PASSAGEM = 0.45;