Django Wars [Parte 20]: Descansando o jogador

O Django Wars foi idealizado e desenvolvido no Django 1.4. Algumas funcionalidades aqui descritas podem não funcionar ou funcionar de forma diferente em outras versões do Django

Nosso jogador gasta pontos de energia para cometer crimes, gasta pontos de raiva para atacar outros jogadores e perde HP quando luta contra outro jogador.
Precisamos criar uma função que faça com que o jogador se recupere, de tempos em tempos.
Sempre que uma ação envolver o jogador, executa essa função.
Como fizemos com a função de level_up(), esta nova função será um método da classe Player.

O funcionamento é bem básico: no modelo do Player temos 3 campos: hp_update, energia_update e raiva_update.
Cada um desses campos é do tipo DateTimeField.
Ou seja, eles guardam uma data, com hora, minutos e segundos.
Sempre que um usuário cometer uma ação, como acessar uma view, por exemplo, executaremos a função da atualização.
Esta função irá ver se o usuário perdeu HP, energia e raiva.
Se sim, verifica quando foi a ultima vez que o usuário atualizou esses atributos (a hora está salva nos campos que acabei de falar).
Se o tempo minimo necessário passou, adiciona HP, energia ou raiva e atualiza o horário.
É mais fácil de entender tudo vendo o código.

import datetime

Antes de mais nada, no arquivo models.py da pasta player, preciso importar a biblioteca Python datetime.
Com essa biblioteca poderemos calcular a diferença de horários.
É sussa demais!!!

    #funcao que recupera o player
    def refresh(self):
        #pega a hora atual
        agora = datetime.datetime.now()
        
        
        #verifica se o usuario tem menos HP do que deveria
        if self.hp < self.vida * 10:
            #verifica quanto tempo passou desde a ultima atualizacao do hp
            tempo = agora - self.hp_update
            #o hp atualiza a cada dois minutos
            #verifica quantas vezes 2 minutos se passaram no intervalo de tempo
            updates = tempo.total_seconds() // 120
            
            #verifica se houve algum update
            if updates > 0:
                #adiciona a quantidade de updates no hp
                self.hp = self.hp + updates
                #verifica se ficamos com mais hp do que o maximo permitido
                if self.hp > self.vida * 10:
                    self.hp = self.vida * 10
                #agora que verificou o ultimo update de hp, atualiza a variavel hp_update
                self.hp_update = agora
        else:
            #se nao existe nenhum update para fazer, atualiza o hp_update
            self.hp_update = agora
        
        
        #verifica se o usuario tem menos energia do que deveria
        if self.energia_atual < self.energia:
            #verifica quanto tempo passou desde a ultima atualizacao do hp
            tempo = agora - self.energia_update
            #a energia atualiza a cada minuto
            #verifica quantos minutos se passaram no intervalo de tempo
            updates = tempo.total_seconds() // 60
            
            #verifica se houve algum update
            if updates > 0:
                #adiciona a quantidade de updates na energia
                self.energia_atual = self.energia_atual + updates
                #verifica se ficamos com mais energia do que o maximo permitido
                if self.energia_atual > self.energia:
                    self.energia_atual = self.energia
                #agora que verificou o ultimo update da energia, atualiza a variavel energia_update
                self.energia_update = agora
        else:
            #se nao existe nenhum update para fazer, atualiza o energia_update
            self.energia_update = agora
        
        
        #verifica se o usuario tem menos raiva do que deveria
        if self.raiva_atual < self.raiva:
            #verifica quanto tempo passou desde a ultima atualizacao da raiva
            tempo = agora - self.raiva_update
            #a raiva atualiza a cada 5 minutos
            #verifica quantos minutos se passaram no intervalo de tempo
            updates = tempo.total_seconds() // 300
            
            #verifica se houve algum update
            if updates > 0:
                #adiciona a quantidade de updates na raiva
                self.raiva_atual = self.raiva_atual + updates
                #verifica se ficamos com mais raiva do que o maximo permitido
                if self.raiva_atual > self.raiva:
                    self.raiva_atual = self.raiva
                #agora que verificou o ultimo update da raiva, atualiza a variavel raiva_update
                self.energia_update = agora
        else:
            #se nao existe nenhum update para fazer, atualiza o raiva_update
            self.energia_update = agora

Essa função ficou grande demais…
Mas para ficar de fácil leitura, foi necessário.
Vou explicar como funciona, a primeira parte deste método, e o resto é análogo.

Na linha 72, utilizo o método datetime.now() da biblioteca datetime, para pegar a hora atual.
A biblioteca datetime tem a classe datetime que tem o método now, por isso datetime.datetime.now().

Na linha 76 verifico se o usuário perdeu hp.
Se ele perdeu hp, executa o que está dentro do IF.
Se ele não perdeu hp, atualizamos a última vez que verificamos seu hp, colocando a hora atual na variável hp_update (executado nas linhas 92~95).

Dentro do if, fica ainda mais fácil.
A primeira coisa que fazemos é descobrir quanto tempo se passou desde a última atualização do hp, guardado na variável hp_update.
Na linha 78 fazemos o tempo de agora – o tempo do hp_update e descobrimos quanto tempo passou.
Isso é uma diferença entre dois objetos do tipo datetime.datetime, que nos retorna um objeto do tipo datetime.timedelta.

A regra da atualização do hp é a seguinte: recupera 1 de hp a cada 2 minutos passados.
2 minutos = 60 * 2 = 120 segundos.
Utilizamos o método timedelta.total_seconds() para saber quantos segundos tempos de diferença entre dois objetos do tipo datetime.datetime.
Portato, na linha 81 verificamos quantas vezes se passou 2 minutos.
O operador Python // é uma divisão que arredonda o resultado.
Assim, não corremos o perigo de ter de retorno um número com ponto flutuante (nosso jogador não recupera meio hp, apenas números inteiros).

Na linha 84 verificamos se houve atualização de hp.
Em caso positivo, adicionamos a quantidade de hp recuperado.
Vale ressaltar que o usuário pode ter passado um bom tempo sem atualizar, como 2 semans por exemplo.
Isso faria com que ele virasse o highlander do jogo, recebendo muito hp.
Por isso, na linha 88 verificamos se ele passou do máximo possível.
Se passou, seta a variável como o máximo.

Por fim, na linha 91 atualizamos o hp_update para informar ao jogo que acabamos de verificar o hp do jogador e pronto.

O mesmo algoritmo serve para a raiva e a energia, a diferença está na regra.
A energia recupera em 1 minuto e a raiva em 5.

Para finalizar, precisamos colocar nas views do usuário a chamada para o método, lembrando sempre de que precisamos do método save(), ou as mudanças não serão salvas.

Como exemplo, vou colocar o nosso novo método na view crimes, no arquivo views.py.

# pagina que lista os crimes
def crimes(request):
    if not request.user.is_authenticated():
        return redirect(logar)
    
    #da um refrash no hp, energia e raiva do player
    player = request.user.get_profile()
    player.refresh()
    player.save()
    
    return render_to_response("crimes.html", {"player": request.user.get_profile(),
                                              "vida": request.user.get_profile().vida * 10}) # para exibir o total de vida do usuario

Vale ressaltar que voc? não precisa colocar a chamada para o método player.refresh() em todas as views, apenas em views chave: a view crimes, a view loja e a view inventário.
Essas views são as que o usuário vai passar com uma certa frequência.
Colocar em todas as views torna o site mais pesado, além de ter muita redundância.

Como já está ficando chato de eu avisar em todo post, o código fonte encontra-se em:
https://github.com/frenetic/django-wars

One thought on “Django Wars [Parte 20]: Descansando o jogador

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *