;; ////////////////////////////////////////////////////////////////////////////
;; Includes For extension libraries
XIncludeFile #PB_Compiler_Home + "Includes\IrrlichtWrapper_Include.pbi"


  #WIN_WIDTH  = 800
  #WIN_HEIGHT = 600

#USE_IRRKLANG = #True
#Window_0 = 0


  ;Game-States
  Enumeration
    #ARK_STATE_NOTHING
    #ARK_STATE_MENU
    #ARK_STATE_GAME
  EndEnumeration  


  ;simple 3 Procedures for each State 
  Structure sGameState
    id.l
    *init
    *main
    *cleanup    
  EndStructure 


Structure sCrate
  *node
  type.l
  visibility.l
  

EndStructure


;; ////////////////////////////////////////////////////////////////////////////
;; Variables

Global g_ScreenSize_X.l,g_ScreenSize_Y.l

g_ScreenSize_X = #WIN_WIDTH
g_ScreenSize_Y = #WIN_HEIGHT


Global ChangeDir = #True

Global g_GameQuit.l = #False;

Global *_Game_ER      ;Game-Event-Receiver
Global *_Menu_ER      ;Menu-Event-Receiver

Global _EscapeDown.l = #False


Global *batter, *ball, *anim, *anim2
Global *butt1,*butt2, *cam , *statusText
Global speedX.l,speedZ.l

Global batterpos.l, ballsleft.l, cratesleft.l , level, lastFPS


Global NewList states.sGameState()
*_actual_state.sGameState = #Null

Global Dim crates.sCrate(30)

;; ////////////////////////////////////////////////////////////////////////////
;; Declares

  Declare SwitchState(newstate.l)
  
  Declare _Game_Init()
  Declare _Game_Cleanup()
  Declare _Game_Main()

  Declare _Menu_Init()
  Declare _Menu_Cleanup()
  Declare _Menu_Main()



Procedure P_StdColl(x1,y1,a1,b1,x2,y2,a2,b2)
  Coll = #False
  
  If x1 < x2
    dx = x2 - (x1 + a1)
  Else
    dx = x1 - (x2 + a2)
  EndIf
  If y1 < y2
    dy = y2 - (y1 + b1)
  Else
    dy = y1 - (y2 + b2)
  EndIf
  
  If dx < 0 And dy < 0
    Coll = #True
  EndIf
  
  ProcedureReturn Coll
  
EndProcedure



Procedure InitLevel(num)
  *ldata = ?Level1
  Select num
    Case 1:
      *ldata = ?Level1
    Case 2:
      *ldata = ?Level2
    Case 3:
      *ldata = ?Level3
    Default:
      *ldata = ?Level3
  EndSelect
  
  cratesleft = 0

  For n = 0 To 26
      crates(n)\visibility = #True
      t.l = PeekL(*ldata+(n*4))
      If t > 0 And t < 5 : cratesleft+1: crates(n)\type = t : EndIf
      If t = 1
        IrrSetNodeMaterialTexture( crates(n)\node, IrrGetTexture("./media/crate.jpg"), 0 )
      ElseIf t = 2
        IrrSetNodeMaterialTexture( crates(n)\node, IrrGetTexture("./media/streifen.jpg"), 0 )
      ElseIf t = 3
        IrrSetNodeMaterialTexture( crates(n)\node, IrrGetTexture("./media/crate.jpg"), 0 )
      ElseIf t = 4
        IrrSetNodeMaterialTexture( crates(n)\node, IrrGetTexture("./media/crate.jpg"), 0 )
      ElseIf t = 5
        IrrSetNodeMaterialTexture( crates(n)\node, IrrGetTexture("./media/metall.jpg"), 0 )
        crates(n)\type = t
      Else
      crates(n)\visibility = #False
      EndIf
    IrrSetNodeVisibility( crates(n)\node , crates(n)\visibility)
    Next


  Debug("Crateleft="+Str(cratesleft))
  ;set Ball to Startposition
;  IrrSetNodePosition(*ball,0,-8.5,-45);
   IrrSetNodePosition(*ball, 0,-9,-45)
  
EndProcedure

Procedure _Game_Init()
   IrrHideMouse()  

   IrrSetEventReceiver(*_Game_ER)
   IrrGuiSetVisible(*butt1,#False)
   IrrGuiSetVisible(*butt2,#False)
   
   
   IrrRemoveAnimator(*cam,*anim2)
   IrrSetCameraTarget(*cam,0,-20,0)
   IrrSetNodePosition(*cam,10,50,-90)
   
   ballsleft = 3
   level=1
   
   InitLevel(1)
   IrrSetNodePosition(*ball, 0,-9,-45)
   changedir = #True
   SpeedZ=200: SpeedX=20
   
   
EndProcedure
Procedure _Game_Cleanup()
      IrrRemoveAnimator(*ball, *anim)      
EndProcedure



Procedure moveBall(menu.l=#False)
  IrrGetNodeAbsolutePosition(*ball, @bposX.f, @bposY.f, @bposZ.f)
  
  ;Check boundaries
  If bPosX >  50 : speedX = -Abs(speedX) : bposX= 50 : changedir=#True : EndIf
  If bPosX <- 50 : speedX =  Abs(speedX) : bposX=-50 : changedir=#True : EndIf
  If bPosZ >  50 : speedZ =  -200        : bposZ= 50 : changedir=#True
  ElseIf bposZ <= -60
    ;Ball behind the Batter
    bposZ = -49
    changedir = #True
    If menu
      speedZ = 200;
    Else
      
      ballsleft -1
      
      ;Ball at Start-Position
      IrrSetNodePosition(*ball, 0,-9,-45)
      bposZ = -45: bposX = 0
      SpeedZ=200 : SpeedX=20
      Debug("loos Ball, now"+Str(ballsleft))
      If ballsleft < 1
        SwitchState(#ARK_STATE_MENU)
      EndIf
    EndIf
    
  EndIf

    

    If bPosZ > -3 Or bposZ < 33
      IrrGetNodePosition(*ball,@bX.f,@bY.f,@bZ.f)
    
      For n = 0 To 26
      
        If crates(n)\visibility
          IrrGetNodePosition(crates(n)\node,@cX.f,@cY.f,@cZ.f)
          If p_stdColl(bX,bZ,3,3,cX,cZ,6,6)
            ;;move into new direction */
             speedz = (-1*speedz);           
             speedx = (-1*speedz) + (1 + ( Random(5) )); // random change
              changedir=#True;
              If crates(n)\type < 5
                crates(n)\visibility = #False
                cratesleft-1
                
                If cratesleft <=0
                  level+1
                  InitLevel(level)
                EndIf
                
                
              EndIf
            EndIf
          EndIf
          IrrSEtNodeVisibility(crates(n)\node,crates(n)\visibility)
        Next              
      EndIf
      
              
      ;; is the ball hitting the batter?
      
      If bposZ <= -50 And bposZ >=-54
        bvector.l = bposX-batterpos
        If bvector <=8 And bVector >=-8
          speedZ=200
          speedx = (bvector * 30)
          bposZ = -49
          changedir = #True
        EndIf
      EndIf
      
              
    If changedir
      IrrRemoveAnimator(*ball, *anim)      
      IrrSetNodePosition(*ball,bposX,-9,bposZ)
      *anim = IrrAddFlyStraightAnimator(*ball,bposX,-9,bposZ,(bposX+speedx),-9.0,(bposZ+speedz),2500,#True)
      changedir = #False
;             SoundFx();
    EndIf
EndProcedure



Procedure _Game_Main()
  Shared *ball

;   IrrHideMouse()  
   
  moveBall(#False)  
  IrrGuiSetText(*statusText,"Level: "+Str(level+1) + " Balls: "+Str(ballsleft))
;  ShowCursor_(0)   
          
EndProcedure

Procedure _Menu_Init()
   IrrSetEventReceiver(*_Menu_ER)
   IrrGuiSetVisible(*butt1,#True)
   IrrGuiSetVisible(*butt2,#True)
   
  *anim2 = IrrAddFlyCircleAnimator(*cam, 0,30,-100,30)
  IrrSetCameraTarget(*cam,0,0,0)
  IrrShowMouse()   
  InitLevel(1)
      IrrSetNodePosition(*ball, 0,-9,-45)
   SpeedZ=200: SpeedX=20
   changedir = #True   
  
EndProcedure
Procedure _Menu_Cleanup()
      IrrRemoveAnimator(*ball, *anim)      
EndProcedure
Procedure _Menu_Main()
  
  fps.l = IrrGetFPS();
  If lastFPS <> fps
    IrrGuiSetText(*statusText, "FPS "+Str(fps))
    lastFPS=fps
  EndIf
  moveball(#True)
  
EndProcedure


ProcedureC _Menu_Events(*event.SEvent)
  Shared player  
;   If *event\EventType = #IRR_EET_MOUSE_INPUT_EVENT
;     _mouse_X = *event\MouseEvent\x
;     _mouse_Y = *event\MouseEvent\y
;     _mouse_LMB = #False
;     If *event\MouseEvent\event = #IRR_EMIE_LMOUSE_PRESSED_DOWN
;       _mouse_LMB = #True
;     EndIf
; 
;   EndIf 


  If *event\EventType = #IRR_EET_GUI_EVENT
 	    If  *event\GuiEvent\EventType = #IRR_EGET_BUTTON_CLICKED 	     	    
 	        id.l = IrrGuiGetId(*event\GuiEvent\Caller)
 	        Debug("id="+Str(id))
			  	If id = 101  ; Quit
			  	  g_GameQuit = #True
			  	EndIf 
			  	If id = 102  ; Start
			  	  SwitchState(#ARK_STATE_GAME)			  	  
			  	EndIf 
			 EndIf
      
  EndIf
  


  
  If *event\EventType = #IRR_EET_KEY_INPUT_EVENT         
    ;         ; arbitrate based on the key that was pressed
    key.l = *event\KeyEvent\key
    Select key
      Case #IRR_KEY_ESCAPE  ;Escape Quits
        If *event\KeyEvent\PressedDown
          If _EscapeDown = #False
            _EscapeDown = #True         
            g_GameQuit = #True;             
          EndIf
        Else
            _EscapeDown = #False
        EndIf        
        
      Case #IRR_KEY_SPACE
        *fader.l = IrrGuiAddInOutFader()
        IrrGuiFaderSetColor(*fader, 0,255,0,0)
        IrrGuiFaderFadeIn(*fader,4000)        
    EndSelect        
  EndIf     
 
  ProcedureReturn #False
EndProcedure

ProcedureC _Game_Events(*event.SEvent)
  
  If *event\EventType = #IRR_EET_MOUSE_INPUT_EVENT         
    IrrGetNodePosition(*batter, @vX.f,@vY.f,@vZ.f)
    vX = ((*event\MouseEvent\X- (g_ScreenSize_X/2))/(g_ScreenSize_X/100))
    If vX >42.5 : vX=42.5 : EndIf
    If vX <-42.5 : vX=-42.5 : EndIf
    IrrSetNodePosition(*batter,vX,vY,vZ)
    batterpos = Int(vX)
    ProcedureReturn #True
    
  EndIf
    
  If *event\EventType = #IRR_EET_KEY_INPUT_EVENT         
    ;         ; arbitrate based on the key that was pressed
    key.l = *event\KeyEvent\key
    Select key
      Case #IRR_KEY_ESCAPE
        If *event\KeyEvent\PressedDown
          If _EscapeDown = #False
            _EscapeDown = #True         
            SwitchState(#ARK_STATE_MENU)
          EndIf
        Else
            _EscapeDown = #False
        EndIf        
        
      Case #IRR_KEY_SPACE
        *fader.l = IrrGuiAddInOutFader()
        IrrGuiFaderSetColor(*fader, 0,255,0,0)
        IrrGuiFaderFadeIn(*fader,4000)        
    EndSelect        
  EndIf     
 
  ProcedureReturn #True
EndProcedure






Procedure _Init()
  
  ; -----------------------------------------------------------------------------
  ; start the irrlicht interface
  If InitSprite() = 0 Or InitKeyboard() = 0 Or InitMouse() = 0  
    MessageRequester("Error","Can't open DirectX",0)  
    End  
  EndIf  
;     
;   ; create window  
;   If OpenWindow(#Window_0, 0, 0, g_ScreenSize_X, g_ScreenSize_Y, "invisible", #PB_Window_BorderLess | #PB_Window_ScreenCentered)  
;   EndIf   
;   ; open screen  
;   If OpenWindowedScreen(WindowID(#Window_0),0,0,g_ScreenSize_X, g_ScreenSize_Y,0,0,0)  
    
;    If IrrStartEx(#IRR_EDT_DIRECT3D9,g_ScreenSize_X, g_ScreenSize_Y,#False, #False,#False, 16, #True, #False,#False,WindowID(#Window_0) )      
    If IrrStartEx(#IRR_EDT_DIRECT3D9,g_ScreenSize_X, g_ScreenSize_Y,#False, #False,#False, 16, #True, #False,#False,#Null)      
                              
      ; set the window caption
      IrrSetWindowCaption( "Advanced Example: Arkanoid" )


      ;disable mouse cursor
;      IrrShowMouse()
            
      ;Create our own Event-Receiver
      *_Game_ER.l = IrrCreateEventReceiver(@_Game_Events())
      *_Menu_ER.l = IrrCreateEventReceiver(@_Menu_Events())


      ;puton States
      AddElement(states())
      states()\id = #ARK_STATE_NOTHING
      states()\init = #Null
      states()\main = #Null
      states()\cleanup = #Null

      ;puton States
      AddElement(states())
      states()\id = #ARK_STATE_MENU
      states()\init = @_Menu_Init()
      states()\main = @_Menu_Main()
      states()\cleanup = @_Menu_Cleanup()


      ;puton States
      AddElement(states())
      states()\id = #ARK_STATE_GAME
      states()\init = @_Game_Init()
      states()\main = @_Game_Main()
      states()\cleanup = @_Game_Cleanup()
      

      Dim *textures.irr_texture(6)
      *textures(0) = IrrGetTexture("./media/ba-top.jpg")
      *textures(1) = IrrGetTexture("./media/ba-bottom.jpg")
      *textures(2) = IrrGetTexture("./media/ba-left.jpg")
      *textures(3) = IrrGetTexture("./media/ba-right.jpg")
      *textures(4) = IrrGetTexture("./media/ba-front.jpg")
      *textures(5) = IrrGetTexture("./media/ba-back.jpg")
      
      *SkyBox = IrrAddSkyBoxToScene( *textures(0),*textures(1),*textures(2),*textures(3),*textures(4),*textures(5))


	
  	  ;;Bottom
  
      *bottom = IrrAddCubeSceneNode(1)
      IrrSetNodePosition(*bottom,0,-12,0)
      IrrSetNodeScale(*bottom,110,5,110)
      *bottomTex = IrrGetTexture("./media/boden.jpg")  
      IrrSetNodeMaterialTexture( *bottom, *bottomTex, 0 )
      IrrSetNodeMaterialFlag( *bottom, #IRR_EMF_LIGHTING, #True)
  
      
      ;;Sides 
      *sideTex = IrrGetTexture("./media/wall.jpg")  
  
      *side = IrrAddCubeSceneNode(1)
      IrrSetNodePosition(*side,-52.5,-7,0)
      IrrSetNodeScale(*side,5,5,110)
      IrrSetNodeMaterialTexture( *side, *sideTex, 0 )
      IrrSetNodeMaterialFlag( *side, #IRR_EMF_LIGHTING, #True)
  
      *side = IrrAddCubeSceneNode(1)
      IrrSetNodePosition(*side,52.5,-7,0)
      IrrSetNodeScale(*side,5,5,110)
      IrrSetNodeMaterialTexture( *side, *sideTex, 0 )
      IrrSetNodeMaterialFlag( *side, #IRR_EMF_LIGHTING, #True)
  
      *side = IrrAddCubeSceneNode(1)
      IrrSetNodePosition(*side,0,-7,52.5)
      IrrSetNodeScale(*side,100,5,5)
      IrrSetNodeMaterialTexture( *side, *sideTex, 0 )
      IrrSetNodeMaterialFlag( *side, #IRR_EMF_LIGHTING, #True)


	
	    ;;Get ball
	    *bb = IrrGetMesh("./media/ball.x");
      *ball = IrrAddMeshToScene( *bb )    
      *ballTex = IrrGetTexture("./media/ball.jpg")  
      IrrSetNodeMaterialTexture( *ball, *ballTex, 0 )
      IrrSetNodeScale(*ball, 1,1,1)
      IrrSetNodeMaterialFlag( *side, #IRR_EMF_LIGHTING, #False)
	    
      ;;Add Shadow
      IrrAddNodeShadow(*ball)
      IrrSetShadowColor(60,0,0,0)
      
      ;; rotate the ball
      IrrAddRotationAnimator(*ball, 2.0,0.3,1.0)


      ;; add 2 lights
      
	  *bottom = IrrAddLight( 20,30,40, 0.5 , 0.7 , 1.0 , 100.0);
    *bottom = IrrAddLight(20,20,-80, 0.8 , 0.2 , 1.0 , 200.0);

	  ;; 	add the batter 	
	  *batter = IrrAddCubeSceneNode(10)
    IrrSetNodePosition(*batter,0,-7,-52.5)
    IrrSetNodeScale(*batter,1.5,0.5,0.2)
    *batterTex = IrrGetTexture("./media/bronze.jpg")  
    IrrSetNodeMaterialTexture( *batter, *batterTex, 0 )
    IrrSetNodeMaterialFlag( *batter, #IRR_EMF_LIGHTING, #True)
	  

    count.l = 0
    For cz = 0 To 30 Step 15
      For cx = -40 To 40 Step 10
        crates(count)\node = IrrAddCubeSceneNode(6)
        IrrSetNodePosition( crates(count)\node, cx,-6, cz)
        IrrSetNodeMaterialFlag( crates(count)\node, #IRR_EMF_LIGHTING, #True)        
        count + 1
      Next
    Next
            

    *_Font = IrrGetFont ( ".\media\fontoffi.png" )
    IrrGuiSetSkinFont(*_Font)  
	
	  
	IrrGuiSetSkinDefaultColor(#IRR_EGDC_BUTTON_TEXT, 255,255,220,100 )
	
	*guiTex = IrrGetTexture("./media/woslogo.tga")
	*img = IrrGuiAddImageFromTexture(*guiTex, 5,5)
	
	
	;;Statustext 
	lwidth.l  = 450
	lheight.l = 50
	
  *statusText = 	IrrGuiAddStaticText("Irrlicht WOS 06 Demo",10, g_ScreenSize_Y-lheight-10,10+lwidth,g_ScreenSize_X-10)
  
	IrrGuiStaticSetOverrideColor(*statusText, 205,200,200)
	; 

  halbe.l = g_ScreenSize_X/2
  *butt1 = IrrGuiAddButton("New Game", halbe-100, 210, halbe+100, 250,0, 102)
  *butt2 = IrrGuiAddButton("Quit", halbe-100, 290, halbe+100, 330,0, 101)
  
  
   ;; Buttons	
; 	int lastFPS = -1;
;     InitLevel();

  *cam = IrrAddCamera(0,0,0, 0,0,0)
  
      SwitchState(#ARK_STATE_MENU)
  
  
  
    
    Else
      MessageRequester("Problem","Could not open the Screen...")
      End
    EndIf
;  EndIf
  
EndProcedure

Procedure _cleanup()

  ; -----------------------------------------------------------------------------
  ; Stop the irrlicht engine and release resources
  IrrStop()
  
EndProcedure

;; State-Switcher
Procedure SwitchState(ModeID.l)
  Shared states()
  Shared *_actual_state
  
  *newMode.sGameState = #Null

  ForEach states() 
    If states()\id = ModeID 
      *newMode = @states() 
      Break;
    EndIf
  Next

  If *newMode = #Null
    MessageRequester("Impossible Mode-Switch", "The Game wanted to switch to a unknown Mode ("+Str(ModeID) +"." + Chr(10) + "This is a critical failure, !" + Chr(10) + "" + Chr(10) + "Please contact the Programmer : mahjongg3dSupport@noxe.de", #MB_OK|#MB_ICONERROR)
    End
  EndIf
  
  If *_actual_state <> 0 
    If *_actual_state\cleanup <> 0
      CallFunctionFast(*_actual_state\cleanup)
    EndIf
  EndIf
  
  *_actual_state = *newMode     
    If *_actual_state\init <> 0
      CallFunctionFast(*_actual_state\init)
    EndIf  
   
EndProcedure




_init()

; -----------------------------------------------------------------------------
; while the irrlicht environment is still running
While IrrRunning() And  g_GameQuit = #False

;    WindowEvent()
        
    ; begin the scene, erasing the canvas with sky-blue before rendering    
    IrrBeginScene( 0,0,0 )
        
    IrrDrawScene()
              
    ; draw the GUI
    IrrDrawGUI()
    
;     ;Now View the State
     If *_actual_state <> #Null And *_actual_state\main <> #Null
       CallFunctionFast(*_actual_state\Main)
     EndIf

    ; end drawing the scene and render it
    IrrEndScene()
    
    Delay(2)
Wend

_cleanup()

End

DataSection
Level1:
  Data.l 0,0,0,1,1,1,0,0,0
  Data.l 0,1,1,1,5,1,1,1,0
  Data.l 0,0,0,1,1,1,0,0,0
Level2:  
  Data.l 0,0,1,5,1,5,1,0,0
  Data.l 0,5,1,1,1,1,1,5,0
  Data.l 0,0,2,0,5,0,2,0,0
Level3:
  Data.l 1,1,1,1,1,1,1,1,1
  Data.l 1,5,1,5,1,5,1,5,1
  Data.l 1,1,1,1,1,1,1,1,1  
EndDataSection


; IDE Options = PureBasic 4.10 Beta 3 (Windows - x86)
; CursorPosition = 287
; FirstLine = 262
; Folding = --9
; Executable = arkanoid.exe