/* Autor: Leandro Bernsmuller
Cria uma janela de aplicao (janela principal), carrega e inicia dados.
Cria o objeto que tem a funcionalidade do jogo.
Arquivos complementares: exibe.cpp, partida.cpp */



#include <windows.h>
#include <windowsx.h>
#include <ddraw.h>
#include <d3drmwin.h>
#include <mmsystem.h>
#include <dsound.h>
#include "defs.h"
#include "..\extra\ddutil.h"
#include "..\extra\ddmm.h"
#include "..\extra\arqs.h"
#include "..\cenario\gr.h"
#include "..\cenario\cenario.h"
#include "..\cenario\cenfis.h"
#include "..\som\sons.h"
#include "..\ia\acoes\acao.h"
#include "..\ia\dados\dados.h"
#include "..\ia\agente.h"
#include "..\ia\agencia.h"
#include "..\interf\janela.h"
#include "..\interf\jancen.h"
#include "..\interf\dlgconpa.h"
#include "..\interf\dlgconf.h"
#include "..\interf\dlgmodo.h"
#include "..\interf\dlgsobre.h"
#include "..\interf\dlgesper.h"
#include "..\interf\dlgconve.h"
#include "..\comunic\sockcomu.h"
#define IDIRECTPLAY2_OR_GREATER
#include <dplay.h>
#include "..\comunic\dplayinf.h"
#include "..\comunic\dpcomu.h"
#include "apl.h"



/* Cria aplicacao (inicia dados)
return TRUE - certo / FALSE - erro
**********************************************************/
BOOL CApl::mCria ( HINSTANCE hInstance, int nCmdShow )
{
   m_hInstancia = hInstance;
   m_dwVeloc = VELOCDEFAULT;
   m_dwNumInteracoes = 0;
   m_nPorcentagemUsoJanela = PORMEDIA;
   m_dwQuemJogador1 = ID_PERS_MAE_NATUREZA;
   m_dwQuemJogador2 = ID_PERS_PESCADOR; 
   m_szNomeArqFaseDefault [ 0 ] = 0;
   m_szNomeArqFase [ 0 ] = 0;
   m_nBotaoPressionado = -1;
   m_nNdxObjetoMensagem = -1;
   
   // quantidade de ferramentas que personagens terao
   mDefineNumFerramentas ( m_dwQuemJogador1, m_adwNumFerramentas1 );   
   mDefineNumFerramentas ( m_dwQuemJogador2, m_adwNumFerramentas2 );   


   #ifdef COMP_PERGUNTAR_REDE_DP

   // verifica se deve jogar com/sem colega em rede (com DP)
   int
      nResp = MessageBox ( NULL, STR_JOGAR_EM_REDE, STR_NOMEPEQ, MB_YESNOCANCEL | MB_ICONQUESTION | MB_DEFBUTTON2 );
   // analisa resposta
   if ( nResp == IDCANCEL )                   // sair CANCELAR
      return FALSE;
   // usar rede?
   if ( nResp == IDYES ) {
      TentaConectar ( m_hInstancia );
      if ( ! bUSANDO_REDEDP ) {                  // erro?
         MSGSTR ( STR_TERMINAR_SEM_CONECXAO );
         return FALSE;
      }
      // verifica se foi conectado como servidor, se sim espera por cliente
      if ( DPInfo.bIsHost )
         // espera conexao, se cancelar, o programa termina
         if ( ! FazDialogo_Espera ( m_hInstancia, STR_ESPERA_CLIENTE, &bCLIENTE_CONECTOU ) ) {
            MSGSTR ( STR_TERMINAR_SEM_CONECXAO );
            return FALSE;
         }
      // Se foi conectado como cliente, o sistema envia automaticamente
      // mensagem para servidor avisando que cliente estah disponivel.
   }
   
   #endif


   #ifdef COMP_PERGUNTAR_SOCKETS

   // verifica se deve jogar com/sem tutor
   int
      // caixa de mensagem simples para selecao
      nResp2 = MessageBox ( NULL, STR_JOGAR_COM_TUTOR, STR_NOMEPEQ, MB_YESNOCANCEL | MB_ICONQUESTION | MB_DEFBUTTON2 );
   // analisa resposta
   if ( nResp2 == IDCANCEL )                   // sair CANCELAR
      return FALSE;
   // usar tutor?
   if ( nResp2 == IDYES ) {
      TentaConectarSockets ( m_hInstancia );
      if ( ! bUSANDO_SOCKETS ) {                  // erro?
         MSGSTR ( STR_TERMINAR_SEM_CONECXAO );
         return FALSE;
      }
      // Se foi conectado como cliente, o sistema envia automaticamente
      // mensagem para servidor avisando que cliente estah disponivel.
   }

   #endif


   // le arquivo de configuracao
   ::CarregaConfiguracao ( m_dwVeloc, m_nPorcentagemUsoJanela, m_szNomeArqFaseDefault );

   // define nome do arquivo de fase
   strcpy ( m_szNomeArqFase, m_szNomeArqFaseDefault );

   // define tamanho da janela (se em rede o tamanho eh fixo)
   if ( bUSANDO_REDEDP || bUSANDO_SOCKETS )
      m_nPorcentagemUsoJanela = PORMEDIA;

   // define qual menu e titulo usar
   DWORD
      dwMenu = IDR_MENU1;   // menu se a aplicacao estah rodando como servidor (ou sem rede)
   char
      szTitulo [ 300 ] = STR_NOMEAPL;  // rodando sem rede
   // cliente
   if ( bUSANDO_REDEDP && ! DPInfo.bIsHost ) {
      dwMenu = IDR_MENU2;
      strcat ( szTitulo, STR_TITCLIENTE );
   }
   // servidor
   if ( bUSANDO_REDEDP && DPInfo.bIsHost )
      strcat ( szTitulo, STR_TITSERVIDOR );
   // sem rede
   if ( ! bUSANDO_REDEDP )
      dwMenu = IDR_MENU3;

   // tenta iniciar janela principal
   if ( ! m_oJanPrincipal.mCria ( dwMenu, szTitulo, hInstance ) )
      return FALSE;

   // cria o objeto que gerencia bitmaps
   if ( ! m_oBmps.mCria ( m_oJanPrincipal.m_hWnd ) )
      return FALSE;

   // inclui objeto que gerencia bmps na janela principal
   m_oJanPrincipal.mIncluiBmps ( m_oBmps );

   // inclui bitmaps
   
   // do inicio e fundo da barra de ferramentas
   m_oBmps.mIncluiBmp ( "dp\\ABERTURA.bmp"    , 0.0, 0.0, 1.0, 1.0 );
   m_oBmps.mIncluiBmp ( "dp\\FUNDOJAN.bmp"    , 0.0, 1.0 - PROPMARGEMINFERIOR, 1.0, 1.0 );

   // moldura do personagem
   m_oBmps.mIncluiBmp ( "dp\\moldura.bmp"     , 0.27, 0.76, 0.27 + 0.104375, 0.78 + 0.1479166666667 );

   // personagens
   // sem moldura se nao joga em rede
   if ( bUSANDO_REDEDP )
      m_oBmps.mIncluiBmp ( "dp\\MAE.bmp"         , 0.28, 0.77, 0.28 + 0.084375, 0.77 + 0.1479166666667 );
   else
      m_oBmps.mIncluiBmp ( "dp\\MAE.bmp"         , 0.28, 0.78, 0.28 + 0.084375, 0.78 + 0.1479166666667 );
   m_oBmps.mIncluiBmp ( "dp\\PESCADOR.bmp"    , 0.66, 0.78, 0.66 + 0.084375, 0.78 + 0.1479166666667 );

   // o ecometro eh um pouco achatado
   m_oBmps.mIncluiBmp ( "dp\\ECOMETRO.bmp"    , 0.01, 0.755, 0.01 + 0.1078125, 0.755 + 0.2216216216214 );
   m_oBmps.mIncluiBmp ( "dp\\ebarverd.bmp"    , 0.01 + 0.01875, 0.755 + 0.025, 0.01 + 0.01875 + 0.0640625, 0.755 + 0.025 + 0.193 );
   m_oBmps.mIncluiBmp ( "dp\\ebaramar.bmp"    , 0.01 + 0.01875, 0.755 + 0.025, 0.01 + 0.01875 + 0.0640625, 0.755 + 0.025 + 0.193 );
   m_oBmps.mIncluiBmp ( "dp\\ebarverm.bmp"    , 0.01 + 0.01875, 0.755 + 0.025, 0.01 + 0.01875 + 0.0640625, 0.755 + 0.025 + 0.193 );

   // botoes laterais
   m_oBmps.mIncluiBmp ( "dp\\MENTAL.bmp"      , 0.90, 0.78, 0.90 + 0.084375, 0.78 + 0.10625 );
   m_oBmps.mIncluiBmp ( "dp\\AJUDA.bmp"       , 0.90, 0.89, 0.90 + 0.084375, 0.89 + 0.10625 );

   // bitmaps dos botoes das ferramentas
   // esquerda
   m_oBmps.mIncluiBmp ( "dp\\INTENS16.bmp"    , 0.16, 0.93, 0.16 + 0.0828125, 0.93 + 0.06041666666667 );
   m_oBmps.mIncluiBmp ( "dp\\PLANTA16.bmp"    , 0.24, 0.93, 0.24 + 0.0828125, 0.93 + 0.06041666666667 );
   m_oBmps.mIncluiBmp ( "dp\\FUNDO16.bmp"     , 0.32, 0.93, 0.32 + 0.0828125, 0.93 + 0.06041666666667 );
   m_oBmps.mIncluiBmp ( "dp\\DEGRAD16.bmp"    , 0.40, 0.93, 0.40 + 0.0828125, 0.93 + 0.06041666666667 );
   // direita
   m_oBmps.mIncluiBmp ( "dp\\EQUIP16.bmp"     , 0.54, 0.93, 0.54 + 0.0828125, 0.93 + 0.06041666666667 );
   m_oBmps.mIncluiBmp ( "dp\\RELIXO16.bmp"    , 0.62, 0.93, 0.62 + 0.0828125, 0.93 + 0.06041666666667 );
   m_oBmps.mIncluiBmp ( "dp\\DEVPEI16.bmp"    , 0.70, 0.93, 0.70 + 0.0828125, 0.93 + 0.06041666666667 );
   m_oBmps.mIncluiBmp ( "dp\\PESCA16.bmp"     , 0.78, 0.93, 0.78 + 0.0828125, 0.93 + 0.06041666666667 );

   // bitmaps dos botoes pressionados
   // botoes laterais
   m_oBmps.mIncluiBmp ( "dp\\bmentaap.bmp"    , 0.90, 0.78, 0.90 + 0.084375, 0.78 + 0.10625 );
   m_oBmps.mIncluiBmp ( "dp\\bajudape.bmp"    , 0.90, 0.89, 0.90 + 0.084375, 0.89 + 0.10625 );

   // bitmaps dos botoes pressionados das ferramentas
   // esquerda
   m_oBmps.mIncluiBmp ( "dp\\bintenap.bmp"    , 0.16, 0.93, 0.16 + 0.0828125, 0.93 + 0.06041666666667 );
   m_oBmps.mIncluiBmp ( "dp\\bplanape.bmp"    , 0.24, 0.93, 0.24 + 0.0828125, 0.93 + 0.06041666666667 );
   m_oBmps.mIncluiBmp ( "dp\\bfundape.bmp"    , 0.32, 0.93, 0.32 + 0.0828125, 0.93 + 0.06041666666667 );
   m_oBmps.mIncluiBmp ( "dp\\bdeapert.bmp"    , 0.40, 0.93, 0.40 + 0.0828125, 0.93 + 0.06041666666667 );
   // direita
   m_oBmps.mIncluiBmp ( "dp\\bequiape.bmp"    , 0.54, 0.93, 0.54 + 0.0828125, 0.93 + 0.06041666666667 );
   m_oBmps.mIncluiBmp ( "dp\\brelixoa.bmp"    , 0.62, 0.93, 0.62 + 0.0828125, 0.93 + 0.06041666666667 );
   m_oBmps.mIncluiBmp ( "dp\\bdevaper.bmp"    , 0.70, 0.93, 0.70 + 0.0828125, 0.93 + 0.06041666666667 );
   m_oBmps.mIncluiBmp ( "dp\\bpescape.bmp"    , 0.78, 0.93, 0.78 + 0.0828125, 0.93 + 0.06041666666667 );
   
   // configura bmps para nao serem exibidos
   for ( int ncB = 0; ncB < MAX_BMPS; ncB ++ )
      m_oJanPrincipal.m_bExibir [ ncB ] = FALSE;

   // tenta iniciar cenario
   if ( ! m_oCen.mCria ( 0, 0, JANX, JANY, m_oJanPrincipal.m_hWnd, LIMSUP, LIMINF, LIMESQ, LIMDIR ) ) {
      MSGSTR ( STR_ERRO_D3D );
      return FALSE;
   }

   // define em quais grupos do cenario usar Z buffer
   if ( ! m_oCen.mDefineUsarZBuffer ( 0, FALSE ) || // subaguaticos
        ! m_oCen.mDefineUsarZBuffer ( 1, FALSE ) || // interv e msgs
        ! m_oCen.mDefineUsarZBuffer ( 2, FALSE ) || // luzes
        ! m_oCen.mDefineUsarZBuffer ( 3, FALSE ) || // outros objetos
        ! m_oCen.mDefineUsarZBuffer ( 4, FALSE ) )  // universo
      return FALSE;

   // tenta incluir bitmap do fundo da janela principal
   if ( ! m_oCen.mConfiguraImagemFundo ( "dp\\FUNDOCEN.bmp", 64, 204, 204 ) )
      return FALSE;

   // inclui cenario na janela
   m_oJanPrincipal.mIncluiCenario ( 0.0, 0.0, PROPMARGEMDIREITA, PROPMARGEMINFERIOR, m_oCen );

   // inicia som
   m_oSons.mCria ( m_oJanPrincipal.m_hWnd );

   // carrega sons
   m_oSons.mCarrega ( 0, ".\\dp\\abertura.wav" );
   m_oSons.mCarrega ( 1, ".\\dp\\iniciapa.wav" );
   m_oSons.mCarrega ( 2, ".\\dp\\fimpa.wav" );
   m_oSons.mCarrega ( 3, ".\\dp\\recebe.wav" );   // transmissao colega
   m_oSons.mCarrega ( 4, ".\\dp\\presssuc.wav" );
   m_oSons.mCarrega ( 5, ".\\dp\\presserr.wav" );
   m_oSons.mCarrega ( 6, ".\\dp\\sobre.wav" );
   m_oSons.mCarrega ( 7, ".\\dp\\interv.wav" );

   // define tamanho e posicao da janela
   if ( bUSANDO_REDEDP || bUSANDO_SOCKETS ) {
      // se usando rede serah no meio horizontalmente e em cima
      m_oJanPrincipal.mAlteraTamanhoPosicaoJanela ( 2, 0, 0, m_nPorcentagemUsoJanela, m_nPorcentagemUsoJanela );
      // abre janela de dialogo
      PostMessage ( m_oJanPrincipal.m_hWnd, WM_COMMAND, ID_MENSAGENS_ALUNO, 0 );
   }
   else
      // sem rede: no meio da tela
      m_oJanPrincipal.mAlteraTamanhoPosicaoJanela ( 1, 0, 0, m_nPorcentagemUsoJanela, m_nPorcentagemUsoJanela );

   // exibe janela
   m_oJanPrincipal.mExibe ( nCmdShow );     // | SW_MAXIMIZE

   // mostra a abertura
   mExibeAbertura ();
   m_oSons.mToca ( 0, 0 );

   // carrega os objetos do cenario
   if ( ! mCriaModelosELuzes () )
      return FALSE;

   // le arquivo de fase default
   CarregaFase ( m_szNomeArqFaseDefault, m_astEventosFase );

   return TRUE;
}



/* Termina aplicacao
**********************************************************/
void CApl::mDestroi ()
{
   m_oAgencia.mDestroi ();
   m_oCen.mDestroi ();
   m_oBmps.mDestroi ( TRUE );
   m_oSons.mDestroi ();

   ::PostQuitMessage ( 0 );
}



/* Trata mensagens do windows, se forem comandos do mouse, menu,
teclado a aplicacao deve tratar, outras mapeia para a devida janela.
Excessao sao as caixas de dialogo que tem um outro procedimento
como handler.
return TRUE - certo / FALSE - erro
**********************************************************/
BOOL CApl::mTrataMensagensWindows ( HWND& hWnd, UINT& uMsg,
                                    WPARAM& wParam, LPARAM& lParam )
{
   // classifica mensagens
   switch ( uMsg ) {

      case WM_TIMER:
         mExecEventosFase ( 2 );
         break;

      // comandos do mouse
      case WM_LBUTTONDOWN:
      //case WM_MOUSEMOVE:
         // se nao estah exibindo abertura
         if ( m_yEstadoExecucao != 0 )
            mTrataEventosMouse ( hWnd, wParam, LOWORD ( lParam ), HIWORD ( lParam ) );
         break;

      // solta botao
      case WM_LBUTTONUP:
         {
            // solta botao
            if ( m_nBotaoPressionado != -1 ) {

               m_oJanPrincipal.m_bExibir [ m_nBotaoPressionado + 10 ] = FALSE;
               // + 10 indica a partir de onde estao bitmaps dos pressionados
               // depende do numero de botoes.

               if ( m_nBotaoPressionado >= 0 )    // se pressionou algum bitmap valido
                   m_oBmps.mExibe ( m_nBotaoPressionado );
               m_nBotaoPressionado = -1;
            }
            else
               // se nao estah exibindo abertura
               if ( m_yEstadoExecucao != 0 )
                  // exibe controles
                  // (apaga tip, info sobre a energia do ser,...)
                  mExibeControles ();
         }
         break;

      // exibe tips ou informacoes sobre objetos
      case WM_RBUTTONDOWN:

         // se nao estah exibindo abertura
         if ( m_yEstadoExecucao != 0 )

            // tenta exibir informacao sobre objeto
            if ( mExibeInfoObjeto ( LOWORD ( lParam ), HIWORD ( lParam ) ) )
               // se conseguiu, termina execucao desta mensagem
               return TRUE;
            else
               // tenta exibir algum tip
               mExibeTips ( hWnd, LOWORD ( lParam ), HIWORD ( lParam ) );
         break;

      // apaga tips
      case WM_RBUTTONUP:
         // se nao estah exibindo abertura
         if ( m_yEstadoExecucao != 0 )
            mExibeControles ();
         break;

      // comandos do menu
      case WM_COMMAND: 

         switch ( LOWORD ( wParam ) ) {

            case ID_ARQUIVO_SAIR:       
               PostMessage ( hWnd, WM_CLOSE, 0, 0 );
               break;

            case ID_ARQUIVO_ESCOLHERPERSONAGEM: // foi colocado no inicio da partida
               break;

            case ID_ARQUIVO_CONFIGURARPARTIDA:
               // agora configura parametros gerais do programa
               {
                  // nao altera parametro da janela em uso
                  int
                     nPocent = m_nPorcentagemUsoJanela;
                  // altera e grava dados
                  FazDialogo_Configura ( m_oJanPrincipal.m_hWnd, m_szNomeArqFaseDefault, nPocent );
                  SalvaConfiguracao ( m_dwVeloc, nPocent, m_szNomeArqFaseDefault );
               }
               break;

            case ID_ARQUIVO_INICIARPARTIDA:                   
               // tenta iniciar partida
               if ( ! mIniciaPartida () )
                  return FALSE;
               break;

            case ID_ARQUIVO_TERMINARPARTIDA:                   
               // tenta terminar partida
               if ( ! mTerminaPartida () )
                  return FALSE;
               break;

            case ID_ARQUIVO_PAUSA:
               // suspende temporariamente a partida
               mSuspendePartida ();
               break;

            case ID_MENSAGENS_ALUNO:
               // abre dialogo para troca de mensagens entre alunos
               FazDialogo_Conversar ( m_hInstancia );
               break;

            case ID__SOBRE:
               m_oSons.mToca ( 6, 0 );
               FazDialogo_Sobre  ( m_oJanPrincipal.m_hWnd );
               break;

            case ID__AJUDA:
               // verifica se a ajuda nao foi aberta (se sim, nao abre novamente)
               if ( ! ProcessoRodando ( m_stAjuda ) )
                  // exibe a ajuda
                  ExecutaProcesso ( STR_ABRE_AJUDA, m_stAjuda );
               break;

            case ID_JOGO_CONECTARREDE:
               break;

            case ID_JOGO_DESCONECTARREDE:
               break;

            case ID_JOGO_CONFIGURAOAVANADA:
               // verifica se o editor nao foi aberto (se sim, nao abre novamente)
               if ( ! ProcessoRodando ( m_stConfigAv ) )
                  // exibe a ajuda
                  ExecutaProcesso ( STR_ABRE_CONFIGURACAO_AVANCADA, m_stConfigAv );
               break;

            case ID_JOGO_EDITAR:
               // verifica se o programa nao foi aberto (se sim, nao abre novamente)
               if ( ! ProcessoRodando ( m_stEditor ) )
                  // exibe a ajuda
                  ExecutaProcesso ( STR_ABRE_EDITOR, m_stEditor );
               break;
         } 
         break;

      // comandos do teclado
      case WM_KEYDOWN:

         switch ( wParam ) {

            case VK_F12:
               PostMessage ( hWnd, WM_CLOSE, 0, 0 );
               break;

            case VK_F1:
               PostMessage ( hWnd, WM_COMMAND, ID__AJUDA, 0 );
               break;

            case VK_F2:
               if ( ! mIniciaPartida () )
                  return FALSE;
               break;

            case VK_F3:
               mSuspendePartida ();
               break;

            // teclas especiais

            #ifdef COMP_TESTES
            case VK_F7:
               EnviaMensagemSockets ( "TESTE MCOE" );
            break;
            case VK_F8:   // provoca GPF de proposito, para testes
               m_oCen.mMudaDirecaoDeslocamentoObjeto ( 0, 300, 0.0, -1, 0.0 );
            case VK_F11:
               m_oCen.mMudaDirecaoDeslocamentoObjeto ( 0, 3, 0.0, 0.0, 0.0 );
               break;
            case VK_F9:
               {
                  DWORD
                     adwDrag [] = CONFIG_AGENTE_DRAGA;

                  // coordenadas limitrofes
                  float
                     fSup,
                     fInf,
                     fDir,
                     fEsq;
                  m_oCen.mRetLimiteJanVis ( fSup, fInf, fDir, fEsq ); 

                  // coordenadas do agente no cenario (x,y,z)
                  float
                     afCoord [ 3 ];
                  afCoord [ 2 ] = 0;      // z eh sempre 0

                  // cria draga
                  afCoord [ 0 ] = fEsq - fEsq * LIMESQ;
                  afCoord [ 1 ] = fSup - ( fSup * LIMSUP * 0.92 );
                  m_oAgencia.m_aoAgentes [ MAX_AGENTES - MAX_AGENTES_INTERVENTORES - 3 ].mTrataEvento ( NDX_EVENTO_NASCE, (PTRVAL) adwDrag, (PTRVAL) afCoord );
               }
               break;
            case VK_DOWN:
               m_oCen.mMudaDirecaoDeslocamentoObjeto ( 0, 3, 0.0, -1, 0.0 );
               break;
            case VK_UP:
               m_oCen.mMudaDirecaoDeslocamentoObjeto ( 0, 3, 0.0, +1, 0.0 );
               break;
            case VK_LEFT:
               m_oCen.mMudaDirecaoDeslocamentoObjeto ( 0, 3, -1, 0.0, 0.0 );
               break;
            case VK_RIGHT:
               m_oCen.mMudaDirecaoDeslocamentoObjeto ( 0, 3, +1, 0.0, 0.0 );
               break;

            #endif

          }
         break;

      // envia mensagem para janelas (nao caixas de dialogo)
      default:
         {
            // fechando janela
            if ( uMsg == WM_CLOSE )
               // se em rede - avisa colega
               if ( bUSANDO_REDEDP )
                  SendGeneralMessage ( APPMSG_TERMINEI_EXECUCAO, 0, NULL );

            // transmite mensagem para janela
            // principal
            if ( hWnd == m_oJanPrincipal.m_hWnd ) {

               return m_oJanPrincipal.mTrataMensagensWindows ( hWnd, uMsg, wParam, lParam );
            }

            break;
         }
   }

   return TRUE;
}



/* Executa acoes referentes aos eventos do mouse
**********************************************************/
void CApl::mTrataEventosMouse ( HWND& hWnd, DWORD dwBotoes, DWORD dwX, DWORD dwY )
{
   // testa se clicou sobre um objeto do cenario
   
   if ( mExibeInfoObjeto ( dwX, dwY ) )
      return;

   // testa botoes

   // normaliza coordenadas do mouse conforme janela (ver defs.h)
   float
      fX = (float) dwX,
      fY = (float) dwY;
   TRANSJAN_NORM ( fX, fY, m_nPorcentagemUsoJanela, m_nPorcentagemUsoJanela );
  
   // para cada botao (cada botao tem um bitmap)
   for ( int ncB = 9; ncB < 19; ncB ++ )
      
      // testa se mouse estah sobre botao
      if ( m_oBmps.mTestaPontoSobreBmp ( ncB, fX, fY ) ) {

         // se pressionou botao de ferramenta sem estar em jogo
         if ( m_yEstadoExecucao != 1 && ncB >= 11 && ncB <= 14 ) {
            m_oSons.mToca ( 5, 0 );
            return;
         }

         // se nao estah usando sockets (tutor remoto)
         if ( ! bUSANDO_SOCKETS && ncB == 9 ) {  // botao do tutor
            m_oSons.mToca ( 5, 0 );
            return;
         }

         // pressiona botao
         m_nBotaoPressionado = ncB;
         m_oJanPrincipal.m_bExibir [ m_nBotaoPressionado ] = FALSE;
         // + 10 indica a partir de onde estao bitmaps dos pressionados
         // depende do numero de botoes.
         m_oJanPrincipal.m_bExibir [ m_nBotaoPressionado + 10 ] = TRUE;
         m_oBmps.mExibe ( m_nBotaoPressionado + 10 );

         // verifica se deve mandar um sinal para o colega, se em rede
         if ( bUSANDO_REDEDP && ( ncB >= 11 && ncB <= 14 ) ) { // botoes de ferramenta
            // manda botao para colega

            // prepara dados para transferencia

            // aloca
            void
               *pvMsg;
            DWORD
               dwTamanho = sizeof ( DWORD );
            pvMsg = GlobalAllocPtr ( GHND, dwTamanho );

            // botao
            * ( (DWORD*) pvMsg ) = ncB;

            // manda
            SendGeneralMessage ( APPMSG_COLEGA_COMANDOU, dwTamanho, pvMsg );
   
            // libera
            GlobalFreePtr ( pvMsg );
         }

         // executa acao referente ao controle
         mExecutaAcaoBotao ( ncB, m_dwQuemJogador1, m_adwNumFerramentas1 );

         // se nao estah em rede e foi pressionado um botao do colega: usa
         if ( ! bUSANDO_REDEDP && ncB >= 15 && ncB <= 18 )
            mExecutaAcaoBotao ( ncB - 4, m_dwQuemJogador2, m_adwNumFerramentas2 );

         // tratou de um botao: termina busca
         return;

      } // fim IF testa mouse sobre botao

   // clicou em lugar algum
   m_oSons.mToca ( 5, 0 );
}



/* Executa uma acao que eh associada a um certo botao
dwPers - ID personagem
**********************************************************/
void CApl::mExecutaAcaoBotao ( DWORD dwBotao, DWORD dwPers, DWORD* padwNumFerramentas )
{
   //  executa acao especifica conforme botao
   switch ( dwBotao ) {

      case 10:           // ajuda
         {
            // verifica se a ajuda foi aberta (se sim, nao abre novamente)
            if ( ProcessoRodando ( m_stAjuda ) ) {
               m_oSons.mToca ( 5, 0 );
               break;
            }

            // executa a ajuda
            m_oSons.mToca ( 4, 0 );
            ExecutaProcesso ( STR_ABRE_AJUDA, m_stAjuda );
         }
         break;

      case 11:            // 1o. botao da esquerda
         {
            // verifica numero de recursos jah usados
            if ( padwNumFerramentas [ 0 ] <= 0 ) {
               m_oSons.mToca ( 5, 0 );
               break;
            }
            padwNumFerramentas [ 0 ] --;
            m_oSons.mToca ( 4, 0 );

            switch ( dwPers ) {

               case ID_PERS_MAE_NATUREZA:
                  // aumenta intensidade solar
                  mAlteraEnergiaSeres ( afALTERA_FERR_0_MAE_NATUREZA );
   
                  // verifica se deve enviar dado para tutor
                  if ( bUSANDO_SOCKETS )
                     mTutorEnviarAcaoUsuario ( "e1" );
                  break;

               case ID_PERS_PESCADOR:
                  // pescar em area protegida
                  mAlteraEnergiaSeres ( afALTERA_FERR_0_PESCADOR );
   
                  // verifica se deve enviar dado para tutor
                  if ( bUSANDO_SOCKETS )
                     mTutorEnviarAcaoUsuario ( "e5" );
                  break;

               case ID_PERS_PREFEITO:
                  // proibição poluição sonora
                  mAlteraEnergiaSeres ( afALTERA_FERR_0_PREFEITO );
                  break;

               case ID_PERS_TURISTA:
                  // nadar no lago
                  mAlteraEnergiaSeres ( afALTERA_FERR_0_TURISTA );
                  break;
            }
         }
         break;

      case 12:            // 2o. botao da esquerda
         {
            // verifica numero de recursos jah usados
            if ( ! padwNumFerramentas [ 1 ] ) {
               m_oSons.mToca ( 5, 0 );
               break;
            }
            m_oSons.mToca ( 4, 0 );
            padwNumFerramentas [ 1 ] --;

            switch ( m_dwQuemJogador1 ) {

               case ID_PERS_MAE_NATUREZA:
                  // colocar aguapes
                  mAlteraEnergiaSeres ( afALTERA_FERR_1_MAE_NATUREZA );
   
                  // verifica se deve enviar dado para tutor
                  if ( bUSANDO_SOCKETS )
                     mTutorEnviarAcaoUsuario ( "e2" );
                  break;

               case ID_PERS_PESCADOR:
                  // recolher lixo das margens
                  mAlteraEnergiaSeres ( afALTERA_FERR_1_PESCADOR );
   
                  // verifica se deve enviar dado para tutor
                  if ( bUSANDO_SOCKETS )
                     mTutorEnviarAcaoUsuario ( "e6" );
                  break;

               case ID_PERS_PREFEITO:
                  // multa (campanha conscientizacao)
                  mAlteraEnergiaSeres ( afALTERA_FERR_1_PREFEITO );
                  break;

               case ID_PERS_TURISTA:
                  // recolher lixo do chao
                  mAlteraEnergiaSeres ( afALTERA_FERR_1_TURISTA );
                  break;
            }
         }
         break;

      case 13:            // 3o. botao da esquerda
         {
            // verifica numero de recursos jah usados
            if ( ! padwNumFerramentas [ 2 ] ) {
               m_oSons.mToca ( 5, 0 );
               break;
            }
            m_oSons.mToca ( 4, 0 );
            padwNumFerramentas [ 2 ] --;

            switch ( dwPers ) {

               case ID_PERS_MAE_NATUREZA:
                  // trocar o fundo do lago
                  mAlteraEnergiaSeres ( afALTERA_FERR_2_MAE_NATUREZA );
   
                  // verifica se deve enviar dado para tutor
                  if ( bUSANDO_SOCKETS )
                     mTutorEnviarAcaoUsuario ( "e3" );
                  break;

               case ID_PERS_PESCADOR:
                  // pescar para se alimentar
                  mAlteraEnergiaSeres ( afALTERA_FERR_2_PESCADOR );
   
                  // verifica se deve enviar dado para tutor
                  if ( bUSANDO_SOCKETS )
                     mTutorEnviarAcaoUsuario ( "e7" );
                  break;

               case ID_PERS_PREFEITO:
                  // Colocar Lixeiras
                  mAlteraEnergiaSeres ( afALTERA_FERR_2_PREFEITO );
                  break;

               case ID_PERS_TURISTA:
                  // nao levar lembranca do lago
                  mAlteraEnergiaSeres ( afALTERA_FERR_2_TURISTA );
                  break;
            }
         }
         break;

      case 14:            // 4o. botao da esquerda
         {
            // verifica numero de recursos jah usados
            if ( ! padwNumFerramentas [ 3 ] ) {
               m_oSons.mToca ( 5, 0 );
               break;
            }
            m_oSons.mToca ( 4, 0 );
            padwNumFerramentas [ 3 ] --;

            switch ( dwPers ) {

               case ID_PERS_MAE_NATUREZA:
                  // acelerar degradacao
                  mAlteraEnergiaSeres ( afALTERA_FERR_3_MAE_NATUREZA );
   
                  // verifica se deve enviar dado para tutor
                  if ( bUSANDO_SOCKETS )
                     mTutorEnviarAcaoUsuario ( "e4" );
                  break;

               case ID_PERS_PESCADOR:
                  // pescar em época permitida
                  mAlteraEnergiaSeres ( afALTERA_FERR_3_PESCADOR );
   
                  // verifica se deve enviar dado para tutor
                  if ( bUSANDO_SOCKETS )
                     mTutorEnviarAcaoUsuario ( "e8" );
                  break;

               case ID_PERS_PREFEITO:
                  // licença (Filtro na Fábrica)
                  mAlteraEnergiaSeres ( afALTERA_FERR_3_PREFEITO );
                  break;

               case ID_PERS_TURISTA:
                  // foto
                  mAlteraEnergiaSeres ( afALTERA_FERR_3_TURISTA );
                  break;
            }
         }
         break;

      default:

         m_oSons.mToca ( 5, 0 );
         break;
   }
}



/* Altera a energia de varios seres
pafQuanto - array com quantos %, da sua energia inicial, cada ser
            deve ganhar
**********************************************************/
void CApl::mAlteraEnergiaSeres ( float* pafQuanto )
{
   float
      fValIni = TX_INICIAL_FOME - TX_MORRE_FOME;
   m_oAgencia.mAlteraEnergia ( NDX_MODELO_PEIXE_GORDO, fValIni * pafQuanto [ 0 ] );
   m_oAgencia.mAlteraEnergia ( NDX_MODELO_PEIXE_AZUL, fValIni * pafQuanto [ 1 ] );
   m_oAgencia.mAlteraEnergia ( NDX_MODELO_PEIXE_LISTRADO, fValIni * pafQuanto [ 2 ] );
   m_oAgencia.mAlteraEnergia ( NDX_MODELO_ALGA_VERDE, fValIni * pafQuanto [ 3 ] );
   m_oAgencia.mAlteraEnergia ( NDX_MODELO_MICROORGANISMO, fValIni * pafQuanto [ 4 ] );
   m_oAgencia.mAlteraEnergia ( NDX_MODELO_FUNDO_LAGO_INVISIVEL, fValIni * pafQuanto [ 5 ] );
   m_oAgencia.mAlteraEnergia ( NDX_MODELO_AGUA_INVISIVEL, fValIni * pafQuanto [ 6 ] );
}
