/*
* Plik naglowkowy zawiera definicje i deklaracje funkcji stanowiacych rdzen
* samej gry.
*
*       autor: r.Q
*       licencja: GNU GPL
*
*/
#include <windef.h>
#include "koraliki.h"
#include "gracz.h"
#include "wektor.h"

#ifndef _GRA_H_
#define _GRA_H_

void UstawObszarGry(HWND, ushort_t&, ushort_t&);
void RysujNitke(HDC&, WEKTOR*, ushort_t, ushort_t);
// Ostatni argument ponizszych funkcji jest niezbedny do tego aby zamienic
// adres przypisany do wskaznika podanego wlasnie jako ten argument.
// Gdybysmy tego nie zrobili to funkcje dzialalyby na kopii wskaznika.
void AktualizujGracza(HWND, HDC&, GRACZ*, KORALIK*, WEKTOR*, ushort_t&, 
                      ushort_t&, KIERUNEK&, KIERUNEK&, KORALIK* &, int&, int&);
void PrzestawGracza(POINT*, GRACZ*, WEKTOR*, ushort_t, bool); // funkcja uzywana przez funkcje
                                                              // 'AktualizujGracza' wtedy, kiedy
                                                              // gracz przekroczy krawedz okna.
void SprawdzKolizje(HWND&, KORALIK*, GRACZ*, KORALIK* &, int&, int&);
bool PorownajPunkty(POINT*, POINT*);

//////////////////////////Implementacja/////////////////////////////////////////
void UstawObszarGry(HWND hwnd, ushort_t& xRoz, ushort_t& yRoz) {
     RECT rRect;
     GetClientRect(hwnd, &rRect);
     xRoz = rRect.right;
     yRoz = rRect.bottom;
     xRoz -= (xRoz % WIELKOSC_KROKU);
     yRoz -= (yRoz % WIELKOSC_KROKU);
}
void RysujNitke(HDC& hdc, WEKTOR* wektor, ushort_t xObszarGry, ushort_t yObszarGry) {
     int i, prevROP2, tmp;
     POINT ptTemp;

     prevROP2 = SetROP2(hdc, R2_BLACK);
     MoveToEx(hdc, PobierzPierwszy(wektor)->x, PobierzPierwszy(wektor)->y, NULL);
     for(i = 1; i < PobierzDlugosc(wektor); i++) {
           ptTemp = *PobierzElement(wektor, i);
           // koryguj wyswietlanie dla OX
           if((ptTemp.x < 0) || (ptTemp.x > xObszarGry)) {
                  tmp = (ptTemp.x < 0 ? xObszarGry : 0);
                  LineTo(hdc, ptTemp.x, ptTemp.y);
                  MoveToEx(hdc, tmp, ptTemp.y, NULL);
                  continue;
           }
           // koryguj wyswietlanie dla OY
           if((ptTemp.y < 0) || (ptTemp.y > yObszarGry)) {
                  tmp = (ptTemp.y < 0 ? yObszarGry : 0);

                  LineTo(hdc, ptTemp.x, ptTemp.y);
                  MoveToEx(hdc, ptTemp.x, tmp, NULL);
                  continue;
           }
           LineTo(hdc, ptTemp.x, ptTemp.y);
     }
     SetROP2(hdc, prevROP2);
}
/* Ponizsza funkcja aktualizuje pozycje gracza. Najpierw sprawdzane jest, czy
gracz zmienil kierunek, jesli tak, zachowujemy w wektorze stara pozycje i zerujemy
wskaznik 'pZnalezione" przechowujacy adres nawlekanego koralika.Nastepnie ustawia 
punkt poczatkowy dla fragmentu nici, a nastepnie zmienia pozycje gracza zgodnie 
z obranym kierunkiem. Gdy polozenie gracza ulegnie zmianie, rysujemy linie od 
poprzedniego polozenia do nowego.
Kolejnym zadaniem jest sprawdzenie kolizji gracza z ktoryms z koralikow. Jesli gracz
nie nawlokl jeszcze zadnego koralika, sprawdzanie kolizji nastepuje przed zmiana polozenia,
w przeciwnym razie po zmianie polozenia.*/
void AktualizujGracza(HWND hwnd, HDC& hdc, GRACZ* gracz, KORALIK* pKoraliki, WEKTOR* wektor,
                      ushort_t& xObszarGry, ushort_t& yObszarGry, KIERUNEK& kierPrev,
                      KIERUNEK& kierNowy, KORALIK* &pZnaleziony, int& iloscKoralikow, 
                      int& ileKoralikow) {
     POINT ptTemp;
     int prevROP2;
     bool rysuj;
     // w trakcie przetwarzania komunikatow klawiatury, zmienna 'kierNowy' moze
     // przyjmowac rozne wartosci. Nas jednak interesuje jej ostatnia wartosc przed
     // aktualizacja gracza
     gracz->kierunek = kierNowy;
     if(kierPrev != gracz->kierunek) {
                DodajElement(wektor, &ptTemp);
                if(pZnaleziony) pZnaleziony = NULL;
     }
     rysuj = true;
     ptTemp = gracz->polozenie;
     if(pZnaleziony == NULL)
          SprawdzKolizje(hwnd, pKoraliki, gracz, pZnaleziony, ileKoralikow, iloscKoralikow);
     switch(gracz->kierunek) {
          case GORA: {
               gracz->polozenie.y -= WIELKOSC_KROKU;
               if(gracz->polozenie.y < 0) {
                    // gdy gracz wychodzi poza krawedz okna, dodajemy nowy punkt toru,
                    // w starym zapisujac wartosc skrajne tj. nie mieszczace sie w
                    // przedziale <0; yObszar> lub <0; xObszar>
                    PrzestawGracza(&ptTemp, gracz, wektor, yObszarGry, false);
                    rysuj = false;
               }
               break;
          }
          case LEWO: {
               gracz->polozenie.x -= WIELKOSC_KROKU;
               if(gracz->polozenie.x < 0) {
                    PrzestawGracza(&ptTemp, gracz, wektor, xObszarGry, true);
                    rysuj = false;
               }
               break;
          }
          case DOL: {
               gracz->polozenie.y += WIELKOSC_KROKU;
               if(gracz->polozenie.y > yObszarGry) {
                    PrzestawGracza(&ptTemp, gracz, wektor, 0, false);
                    rysuj = false;
               }
               break;
          }
          case PRAWO: {
               gracz->polozenie.x += WIELKOSC_KROKU;
               if(gracz->polozenie.x > xObszarGry) {
                    PrzestawGracza(&ptTemp, gracz, wektor, 0, true);
                    rysuj = false;
               }
               break;
          }
     }
     if(pZnaleziony != NULL)
          SprawdzKolizje(hwnd, pKoraliki, gracz, pZnaleziony, ileKoralikow, iloscKoralikow);
     // jesli gracz przechodzi poza krawedz okna to NIE rysuj nici i
     // nie zmieniaj ostatniego elementu wektora (bo po co)
     if(rysuj) {
              // aktualizuje ostatnio dodany punkt do wektora
              *PobierzOstatni(wektor) = gracz->polozenie;
              prevROP2 = SetROP2(hdc, R2_BLACK);
              MoveToEx(hdc, ptTemp.x, ptTemp.y, NULL);
              LineTo(hdc, gracz->polozenie.x, gracz->polozenie.y);
              SetROP2(hdc, prevROP2);
     }
}
void PrzestawGracza(POINT* ptTemp, GRACZ* pGracz, WEKTOR* wektor, ushort_t gdzie, bool czyX) {
     LONG& wspPoint = (czyX ? ptTemp->x : ptTemp->y);
     LONG& wspGracz = (czyX ? pGracz->polozenie.x : pGracz->polozenie.y);
     wspPoint = wspGracz;
     *PobierzOstatni(wektor) = *ptTemp;
     wspGracz = gdzie;
     wspPoint = wspGracz;
     DodajElement(wektor, ptTemp);
}
void SprawdzKolizje(HWND& hwnd, KORALIK* pKoraliki, GRACZ* gracz, KORALIK* &pZnaleziony,
                    int& kor, int& iloscKoralikow) {
     int iIndex;
     POINT ptTemp;
     RECT rc;
     HINSTANCE hInstance;
     ptTemp = gracz->polozenie;

     switch(gracz->kierunek) {
         case GORA: {
              ptTemp.y += (pZnaleziony != NULL ? PROMIEN_KORALIKA : -PROMIEN_KORALIKA);
              break;
         }
         case DOL: {
              ptTemp.y += (pZnaleziony != NULL ? -PROMIEN_KORALIKA : PROMIEN_KORALIKA);
              break;
         }
         case LEWO: {
              ptTemp.x += (pZnaleziony != NULL ? PROMIEN_KORALIKA : -PROMIEN_KORALIKA);
              break;
         }
         case PRAWO: {
              ptTemp.x += (pZnaleziony != NULL ? -PROMIEN_KORALIKA : PROMIEN_KORALIKA);
              break;
         }
     }
     if(!pZnaleziony) {   
              iIndex = ZnajdzKoralik(pKoraliki, &ptTemp, gracz->kierunek, iloscKoralikow);
              if(iIndex >= 0)
                      pZnaleziony = &pKoraliki[iIndex];
     }
     else if(PorownajPunkty(&pZnaleziony->polozenie, &ptTemp)) {
               ZmienStan(pZnaleziony);
               SetRect(&rc, pZnaleziony->polozenie.x - PROMIEN_KORALIKA,
                       pZnaleziony->polozenie.y - PROMIEN_KORALIKA,
                       pZnaleziony->polozenie.x + PROMIEN_KORALIKA,
                       pZnaleziony->polozenie.y + PROMIEN_KORALIKA);
               kor--;
               InvalidateRect(hwnd, &rc, TRUE);
               hInstance = (HINSTANCE) GetWindowLong(hwnd, GWL_HINSTANCE);
               PlaySound(TEXT("NAWLECZONE_SND"), hInstance, SND_RESOURCE | SND_ASYNC);
               pZnaleziony = NULL;
     }
}
bool PorownajPunkty(POINT* ptPierwszy, POINT* ptDrugi) {
     if((ptPierwszy->x == ptDrugi->x) &&
        (ptPierwszy->y == ptDrugi->y))
                       return true;
     return false;
}

#endif  /* _GRA_H_ */
