/** 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;