Skip to content

Procedimentos

Procedimentos (ou Procedures) armazenados são blocos de código SQL pré-compilados que podem ser executados repetidamente no banco de dados. Eles permitem encapsular lógica complexa, melhorar o desempenho ao reduzir a sobrecarga de comunicação entre a aplicação e o banco de dados e garantir a reutilização do código.

No nosso projeto, utilizamos procedimentos armazenados para otimizar e automatizar diversas operações essenciais, como:

  • Manipulação do combate, garantindo que as regras de vitória, derrota e status dos personagens sejam aplicadas corretamente.
  • Gerenciamento do inventário, permitindo a adição e remoção de itens enquanto se respeita a capacidade máxima. Criação e especialização de NPCs, assegurando que cada NPC seja criado com as características apropriadas de acordo com sua função no jogo.
  • Controle de respawn de inimigos, garantindo que os adversários retornem ao mundo do jogo seguindo as regras definidas.
  • Validação de personagens, evitando que informações inconsistentes sejam inseridas ou modificadas no banco de dados. A adoção de procedimentos armazenados melhora a performance do sistema, reduzindo a carga da aplicação e garantindo a integridade dos dados do jogo de maneira eficiente e organizada.

Procedimentos Armazenados

Procedimento: mover_pc

CREATE OR REPLACE PROCEDURE mover_pc(
    p_id_pc INT,
    p_id_sala_destino INT
)
LANGUAGE plpgsql
AS $$
DECLARE
    v_id_sala_atual INT;
    v_conexao_existe BOOLEAN;
BEGIN
    -- Obtém a sala atual do PC
    SELECT id_sala INTO v_id_sala_atual
    FROM PC
    WHERE id_personagem = p_id_pc;

    -- Verifica se a sala de destino está conectada à sala atual
    SELECT EXISTS(
        SELECT 1 FROM SalaConexoes
        WHERE (id_sala_origem = v_id_sala_atual AND id_sala_destino = p_id_sala_destino)
           OR (id_sala_origem = p_id_sala_destino AND id_sala_destino = v_id_sala_atual)
    ) INTO v_conexao_existe;

    IF NOT v_conexao_existe THEN
        RAISE EXCEPTION 'Movimento inválido: a sala de destino não está conectada à sala atual.';
    END IF;

    -- Atualiza a sala do PC
    UPDATE PC
    SET id_sala = p_id_sala_destino
    WHERE id_personagem = p_id_pc;

    RAISE NOTICE 'PC movido para a sala %.', p_id_sala_destino;
END;
$$;

Procedimento: concluir_missao

CREATE OR REPLACE PROCEDURE concluir_missao(
    p_id_missao INT,
    p_id_pc INT
)
LANGUAGE plpgsql
AS $$
DECLARE
    v_xp_recompensa INT;
BEGIN
    -- Obtém a recompensa de XP da missão
    SELECT qnt_xp INTO v_xp_recompensa
    FROM Missao
    WHERE id_missao = p_id_missao;

    -- Marca a missão como concluída
    INSERT INTO MissoesRealizadas (id_missao, id_pc)
    VALUES (p_id_missao, p_id_pc);

    -- Concede a recompensa de XP ao PC
    UPDATE PC
    SET xp = xp + v_xp_recompensa
    WHERE id_personagem = p_id_pc;

    RAISE NOTICE 'Missão concluída! % XP concedido ao PC.', v_xp_recompensa;
END;
$$;

Procedimento: comprar_item

CREATE OR REPLACE PROCEDURE comprar_item(
    p_id_pc INT,
    p_id_mercador INT,
    p_id_instancia_item INT,
    p_valor INT
)
LANGUAGE plpgsql
AS $$
DECLARE
    v_coins_pc INT;
BEGIN
    -- Verifica se o PC tem coins suficientes
    SELECT coins INTO v_coins_pc
    FROM PC
    WHERE id_personagem = p_id_pc;

    IF v_coins_pc < p_valor THEN
        RAISE EXCEPTION 'Coins insuficientes para realizar a compra.';
    END IF;

    -- Realiza a transação
    INSERT INTO Transacao (id_mercador, id_pc, valor, tipo)
    VALUES (p_id_mercador, p_id_pc, p_valor, 'compra');

    -- Adiciona o item ao inventário do PC
    INSERT INTO Inventario (id_pc, id_instancia_item)
    VALUES (p_id_pc, p_id_instancia_item);

    -- Deduz o valor da compra dos coins do PC
    UPDATE PC
    SET coins = coins - p_valor
    WHERE id_personagem = p_id_pc;

    RAISE NOTICE 'Compra realizada com sucesso!';
END;
$$;

Funções Relacionadas

Função: respawn_inimigo

CREATE OR REPLACE FUNCTION respawn_inimigo()
RETURNS TRIGGER AS $$
DECLARE
    nova_sala INT;
BEGIN
    SELECT id_sala INTO nova_sala
    FROM Sala
    WHERE id_sala <> OLD.id_sala  
    ORDER BY RANDOM()
    LIMIT 1;

    INSERT INTO InstanciaInimigo (id_inimigo, id_sala, vida_atual, absorcao, atk, habilidade, combat_status)
    VALUES (OLD.id_inimigo, nova_sala, 100, OLD.absorcao, OLD.atk, OLD.habilidade, 'Normal');

    RETURN OLD;
END;
$$ LANGUAGE plpgsql;

Função: validar_personagem

CREATE OR REPLACE FUNCTION validar_personagem() RETURNS TRIGGER AS $$
BEGIN
    IF NEW.tipo = 'PC' THEN
        IF NOT EXISTS (SELECT 1 FROM PC WHERE id_personagem = NEW.id_personagem) THEN
            RAISE EXCEPTION 'Todo Personagem do tipo PC deve ter um registro correspondente na tabela PC';
        END IF;
    ELSIF NEW.tipo = 'NPC' THEN
        IF NOT EXISTS (SELECT 1 FROM NPC WHERE id_personagem = NEW.id_personagem) THEN
            RAISE EXCEPTION 'Todo Personagem do tipo NPC deve ter um registro correspondente na tabela NPC';
        END IF;
    END IF;

    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

Função: validar_especializacao_personagem

CREATE OR REPLACE FUNCTION validar_especializacao_personagem() RETURNS TRIGGER AS $$
BEGIN
    IF TG_TABLE_NAME = 'pc' THEN
        IF NOT EXISTS (SELECT 1 FROM Personagem WHERE id_personagem = NEW.id_personagem AND tipo = 'PC') THEN
            RAISE EXCEPTION 'Não é possível inserir um PC sem um registro correspondente na tabela Personagem';
        END IF;

    ELSIF TG_TABLE_NAME = 'npc' THEN
        IF NOT EXISTS (SELECT 1 FROM Personagem WHERE id_personagem = NEW.id_personagem AND tipo = 'NPC') THEN
            RAISE EXCEPTION 'Não é possível inserir um NPC sem um registro correspondente na tabela Personagem';
        END IF;
    END IF;

    RETURN NEW;
END;
$$ LANGUAGE plpgsql;