#include "fbgfx.bi"
#define STEINBREITE 50
#define ROHRBREITE 10
#define FELDX 16
#define FELDY 12
#define SCHIEBGESCHWINDIGKEIT 5

declare function spiel(level as integer = 1, byref punkte as integer = 0) as integer
declare sub wasserlauf(x as integer, y as integer, weit as integer, von as integer, nach as integer)
enum Richtungen
  oben = 1, links, rechts, unten
end enum

chdir exepath
screenres STEINBREITE*FELDX, STEINBREITE*FELDY, 32
randomize

dim shared as FB.IMAGE ptr grafik(8)
for i as integer = 0 to 7
  grafik(i) = imagecreate(STEINBREITE, STEINBREITE)
  bload "grafik/pipe" & i & ".bmp", grafik(i)
next
grafik(8) = imagecreate(STEINBREITE, STEINBREITE, 0)

' Spiel starten
dim as integer punkte, rueckgabe
for level as integer = 10 to 20
  rueckgabe = spiel(level, punkte)
  if rueckgabe < 0 then exit for
next

' aufraeumen
for i as integer = 0 to 8
  imagedestroy grafik(i)
next
if rueckgabe <> -2 then getkey

function spiel(level as integer = 1, byref punkte as integer = 0) as integer
  windowtitle "Kanalisation - Level " & level

  ' Feld initialisieren
  dim as integer feld(FELDX+1, FELDY+1), mx, my, mb, leerX, leerY, klickX, klickY, punktfaktor = 1
  dim as integer bewegung, bewegX, bewegY, bewegXplus, bewegYplus, bewegXlang, bewegYlang
  dim as integer wasserX, wasserY, wasserStand, wasserVonRichtung, wasserNachRichtung, wasserPause = 5, wasserPauseCount
  if level < 30 then wasserPause = 20 - level\2
  dim as FB.IMAGE ptr bewegGrafik
  dim as string taste
  feld(1, 1) = 2                                     ' Eingang
  wasserX = 1
  wasserY = 1
  wasserStand = 0
  wasserVonRichtung  = oben
  wasserNachRichtung = unten
  for x as integer = 1 to FELDX-1
    for y as integer = 2 to FELDY
      if y = 2 or sqr(rnd*level) < 2.5 then
        feld(x, y) = int(rnd*6) + 1                  ' zufaelliges Rohr
      elseif y < 4 or x > FELDX - 3 or sqr(rnd*level) <= 4 then
        feld(x, y) = 7                               ' leeres (verschiebbares) Feld
      end if
      ' und sonst ist das Feld blockiert
    next
  next
  feld(FELDX, int(rnd*(FELDY-1))+2) = 5              ' sicherer Ausgang
  for y as integer = 2 to FELDY
    if rnd*level < 2 then feld(FELDX, y) = 5         ' weiterer Ausgang
  next
  leerX = 1
  leerY = 2
  feld(leerX, leerY) = 8                             ' freies Feld
  for x as integer = 1 to FELDX
    for y as integer = 1 to FELDY
      put ((x-1)*STEINBREITE, (y-1)*STEINBREITE), grafik(feld(x, y)), pset
    next
  next
  sleep 1, 1

  ' Spielstart
  do
    sleep 10
    ' Punktestand ausgeben
    screenlock
    for i as integer = 3 to 6
      put (i*STEINBREITE, 0), grafik(0), pset
    next
    draw string (3*STEINBREITE, STEINBREITE\2 - 4), punkte & " Punkte"
    screenunlock
    getmouse mx, my,, mb
    taste = inkey
    if taste = chr(255, 107) then return -2
    if taste = " " then             ' Schnelllauf: doppelte Punkte, kein Verschieben
      wasserPause = 1
      punktfaktor = 2
    end if
    ' Wasserlauf
    wasserPauseCount += 1
    if wasserPauseCount >= wasserPause then
      wasserPauseCount = 0
      wasserLauf wasserX, wasserY, wasserStand, wasserVonRichtung, wasserNachRichtung
      punkte += punktfaktor
      wasserStand += 1
      if wasserStand = STEINBREITE then
        select case wasserNachRichtung
          case oben   : wasserY -= 1
          case unten  : wasserY += 1
          case links  : wasserX -= 1
          case rechts : wasserX += 1
        end select
        if wasserX > FELDX then sleep 1, 1 : return 1
        wasserVonRichtung = 5 - wasserNachRichtung
        select case feld(wasserX, wasserY)
          case 0, 7, 8
            return -1  ' Wasser ist ins Nichts geflossen
          case 1
            if wasserVonRichtung = links or wasserVonRichtung = unten then return -1
            if wasserVonRichtung = oben then wasserNachRichtung = rechts else wasserNachRichtung = oben
          case 2
            if wasserVonRichtung = links or wasserVonRichtung = rechts then return -1
            if wasserVonRichtung = oben then wasserNachRichtung = unten else wasserNachRichtung = oben
          case 3
            if wasserVonRichtung = rechts or wasserVonRichtung = unten then return -1
            if wasserVonRichtung = oben then wasserNachRichtung = links else wasserNachRichtung = oben
          case 4
            if wasserVonRichtung = links or wasserVonRichtung = oben then return -1
            if wasserVonRichtung = rechts then wasserNachRichtung = unten else wasserNachRichtung = rechts
          case 5
            if wasserVonRichtung = oben or wasserVonRichtung = unten then return -1
            if wasserVonRichtung = rechts then wasserNachRichtung = links else wasserNachRichtung = rechts
          case 6
            if wasserVonRichtung = oben or wasserVonRichtung = rechts then return -1
            if wasserVonRichtung = unten then wasserNachRichtung = links else wasserNachRichtung = unten
        end select
        wasserStand = 0
        feld(wasserX, wasserY) += 16     ' nicht mehr verschiebbar
      end if
    end if
    if punktfaktor = 2 then continue do  ' Schnelllauf wurde aktiviert

    ' Verschiebung noch im Gang
    if bewegung then
      bewegung -= SCHIEBGESCHWINDIGKEIT
      if bewegung < 0 then bewegung = 0
      screenlock
      put ((klickX-1)*STEINBREITE, (klickY-1)*STEINBREITE), grafik(8), pset
      put ((leerX-1)*STEINBREITE, (leerY-1)*STEINBREITE), grafik(8), pset
      put (bewegX-(bewegung-STEINBREITE)*bewegXplus, bewegY-(bewegung-STEINBREITE)*bewegYplus), bewegGrafik, pset
      screenunlock
      if bewegung = 0 then
        imagedestroy bewegGrafik
        if bewegXplus then
          for x as integer = leerX to klickX+bewegXplus step -bewegXplus
            feld(x, leerY) = feld(x-bewegXplus, leerY)
          next
        else
          for y as integer = leerY to klickY+bewegYplus step -bewegYplus
            feld(leerX, y) = feld(leerX, y-bewegYplus)
          next
        end if
        feld(klickX, klickY) = 8
        leerX = klickX
        leerY = klickY
      end if
    end if

    ' auf neue Verschiebung ueberpruefen
    if mb = 1 and bewegung = 0 then
      klickX = mx\STEINBREITE + 1
      klickY = my\STEINBREITE + 1
      if klickX >= FELDX or klickY < 2 then continue do
      bewegXplus = sgn(leerX - klickX)
      bewegYplus = sgn(leerY - klickY)
      if bewegXplus = 0 xor bewegYplus <> 0 then continue do
      if bewegXplus then
        for x as integer = klickX to leerX step bewegXplus
          if feld(x, leerY) = 0 or feld(x, leerY) > 15 then continue do
        next
        bewegX = iif(leerX < klickX, leerX*STEINBREITE, (klickX-1)*STEINBREITE)
        bewegY = (klickY-1)*STEINBREITE
        bewegXlang = abs(leerX - klickX)*STEINBREITE
        bewegYlang = STEINBREITE
      else
        for y as integer = klickY to leerY step bewegYplus
          if feld(leerX, y) = 0 or feld(leerX, y) > 15 then continue do
        next
        bewegX = (klickX-1)*STEINBREITE
        bewegY = iif(leerY < klickY, leerY*STEINBREITE, (klickY-1)*STEINBREITE)
        bewegXlang = STEINBREITE
        bewegYlang = abs(leerY - klickY)*STEINBREITE
      end if
      bewegung = STEINBREITE
      bewegGrafik = imagecreate(bewegXlang, bewegYlang)
      get (bewegX, bewegY)-step(bewegXlang-1, bewegYlang-1), bewegGrafik
      punkte -= 1
    end if
  loop
  return 0              ' Level geschafft
end function

sub wasserlauf(x as integer, y as integer, weit as integer, von as integer, nach as integer)
  if (weit < STEINBREITE\2 - 8) or (von + nach = 5) then
    select case von
      case oben
        line ((x-.5)*STEINBREITE-ROHRBREITE\2, (y-1)*STEINBREITE+weit)-step(ROHRBREITE, 0), 255
      case unten
        line ((x-.5)*STEINBREITE-ROHRBREITE\2, y*STEINBREITE-weit-1)-step(ROHRBREITE, 0), 255
      case links
        line ((x-1)*STEINBREITE+weit, (y-.5)*STEINBREITE-ROHRBREITE\2) -step(0, ROHRBREITE), 255
      case rechts
        line (x*STEINBREITE-weit-1, (y-.5)*STEINBREITE-ROHRBREITE\2)-step(0, ROHRBREITE), 255
    end select
  elseif weit >= STEINBREITE\2 + 8 then
    select case nach
      case oben
        line ((x-.5)*STEINBREITE-ROHRBREITE\2, y*STEINBREITE-weit-1)-step(ROHRBREITE, 0), 255
      case unten
        line ((x-.5)*STEINBREITE-ROHRBREITE\2, (y-1)*STEINBREITE+weit)-step(ROHRBREITE, 0), 255
      case links
        line (x*STEINBREITE-weit-1, (y-.5)*STEINBREITE-ROHRBREITE\2)-step(0, ROHRBREITE), 255
      case rechts
        line ((x-1)*STEINBREITE+weit, (y-.5)*STEINBREITE-ROHRBREITE\2) -step(0, ROHRBREITE), 255
    end select
  end if
end sub
