; Simple Pacman-Example
;
; This is a small Example about how to write a game with the IrrlichtWrapper.
; I think it is one of the problems to get a good start with this.
; So maybe this helps to start off and make good games.  (i reallly want to see them !)
;
; This Example shows 


; Whats is missing in the example ?
; Menu  -> Is There now
; Font  -> Is There now....
; Scoring ->Basically
;
; PacMan eats Monsters
; Monsters kill PacMan


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


;; 



UsePNGImageDecoder()

;; ////////////////////////////////////////////////////////////////////////////
;; Constants

  #Window_0 = 0
  
  #WIN_WIDTH  = 800
  #WIN_HEIGHT = 600

  #POWERTIME = 6000


;; ////////////////////////////////////////////////////////////////////////////
;; Enumerations

  ;Game-States
  Enumeration
    #PAC_STATE_NOTHING
    #PAC_STATE_MENU
    #PAC_STATE_GAME
  EndEnumeration  

  ;Object-Types
  Enumeration 
    #OBJ_TYPE_NOTHING
    #OBJ_TYPE_WALL
    #OBJ_TYPE_ENEMY 
    #OBJ_TYPE_DOT
    #OBJ_TYPE_POWERDOT
    #OBJ_TYPE_TRANSPORTER
  EndEnumeration

  ;Object States
  Enumeration 
    #OBJ_STATE_UNKNOWN
    #OBJ_STATE_DEAD
    #OBJ_STATE_WEAK 
  EndEnumeration

  ;Moving-Directions
  Enumeration
    #PACDIR_STAND
    #PACDIR_LEFT
    #PACDIR_RIGHT
    #PACDIR_UP
    #PACDIR_DOWN
    #PACDIR_DIE
    #PACDIR_NONE
  EndEnumeration



;; ////////////////////////////////////////////////////////////////////////////
;; Structures

  ;Structure for position in 3D
  Structure sPos
    x.l : y.l: z.l : width.l
  EndStructure

  ;Structure for Levels
  Structure sLevel
    width.l
    height.l
    *data
  EndStructure


  ;
  Structure sObject 
    *node
    pos.sPos
    width.l
    type.l            ;Type of the Object (Wall / Dot / Enemy ect.)
    state.l           ;State (Dead/Weak ect....)
    speed.l           ;Speed
    move_direction.l 
    wish_direction.l 
  EndStructure   

  
  Structure sPlayer Extends sObject
    lives.l    
    score.l
    powertime.l
    transportflag.l  
    *transporter
    faketimemove.l    ;Time to change the Wish
    *light            ;The light above our little Pacman    
  EndStructure


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


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

Global g_ScreenSize_X.l,g_ScreenSize_Y.l

g_ScreenSize_X = #WIN_WIDTH
g_ScreenSize_Y = #WIN_HEIGHT

Global *Game_PlaneNode

Global g_GameQuit.l = #False;

Global player.sPlayer


Global *font

Global *Game_ER  = #Null      ;Game-Event-Receiver
Global *Menu_ER  = #Null      ;Menu-Event-Receiver

  
Global *Game_LIVESYMBOL


*MonsterMesh = #Null
*PacmanMesh  = #Null
*CubeMesh    = #Null
*FloorMesh   = #Null
*TransporterMesh = #Null


*MonsterTexture  = #Null
*MonsterTexture2 = #Null
*MonsterTextureEyes = #Null
*PacmanTexture   = #Null
*CubeTexture     = #Null
*FloorTexture    = #Null


  
Global *Menu_Titlepic
Global *Menu_optionpic
  
Global NewList Objects.sObject()
Global NewList Monsters.l()

Global NewList states.sGameState()


Global _EscapeDown.l = #False

Global _mouse_X.l, _mouse_Y.l, _mouse_LMB.l 

*actual_state.sGameState = #Null


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

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

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

 
 
;; ////////////////////////////////////////////////////////////////////////////
;; Macros

; ***   Standard Collision, equal to SpriteCollision()
  Macro StdColl(x1,y1,a1,b1,x2,y2,a2,b2)
    (0 Or (0>=((0 Or (x1 < x2))*(x2 - (x1 + a1)))+((0 Or (x1 >= x2))*(x1 - (x2 + a2)))))And(0 Or (0>=((0 Or (y1 < y2))*(y2 - (y1 + b1)))+((0 Or (y1 >= y2))*(y1 - (y2 + b2)))))
  EndMacro

  Macro mcGetFakeFloat(_xx_)
    (_xx_ / 1000)
  EndMacro
  
  Macro mcSetFakeFloat(_xx_)
    (_xx_ * 1000)
  EndMacro



;; ////////////////////////////////////////////////////////////////////////////
;; Procedures

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



;; ////////////////////////////////////////////////////////////////////////////
;; Checks for possible colissions

Procedure.l isCollission(x.l,y.l,w.l) 
  
  *back.l = #Null
  ForEach Objects()    
    If Objects()\state <> #OBJ_STATE_DEAD
      If P_StdColl(Objects()\pos\x, Objects()\pos\y, Objects()\pos\width, Objects()\pos\width , x,y,w,w) 

        If Objects()\type = #OBJ_TYPE_WALL
          *back = @Objects()
        EndIf
        If *back = #Null And Objects()\type = #OBJ_TYPE_ENEMY
          *back = @Objects()
        EndIf
          
        If *back = #Null And Objects()\type = #OBJ_TYPE_POWERDOT
          *back = @Objects()
        EndIf
    
        If *back = #Null And Objects()\type = #OBJ_TYPE_DOT
          *back = @Objects()
        EndIf

        If Objects()\type = #OBJ_TYPE_TRANSPORTER
          *back = @Objects()
        EndIf
        
      EndIf
    EndIf
  Next
  ProcedureReturn *back; 
EndProcedure




;; ////////////////////////////////////////////////////////////////////////////
;; Make a Particle-Eefect when touching a PowerDot

Procedure _makeExplosion(x.f,y.f,z.f)
  Shared *ParticlesNode,*em,*ParticleTexture
  Define explosionEmitter.IRR_PARTICLE_EMITTER
  
  ; add a particle system to the irrlicht scene manager, a default emitter is not
  ; created as we will define out own. the particle system is blank at the moment
  *ParticlesNode = IrrAddParticleSystemToScene( #IRR_NO_EMITTER ) 
  ; when the particle system starts it creates objects similar to billboards,
  ; this command specifies how large each of those particles will be
  IrrSetParticleSize( *ParticlesNode, 5, 5 )
  
  With explosionEmitter
    \min_box_x = -2
    \min_box_y = 0
    \min_box_z = -2
    \max_box_x = 2
    \max_box_y = 1
    \max_box_z = 2
    \direction_x = 0.06
    \direction_y = 0.06
    \direction_z = 0.06
    \min_paritlcles_per_second = 80
    \max_paritlcles_per_second = 100
    \min_start_color_red = 255
    \min_start_color_green = 255
    \min_start_color_blue = 255
    \max_start_color_red = 255
    \max_start_color_green = 255
    \max_start_color_blue = 255
    \min_lifetime = 200
    \max_lifetime = 700
    \max_angle_degrees = 360
  EndWith
  
  ; finally we add this particle emitting object to the particle system
  *em.l = IrrAddParticleEmitter( *ParticlesNode, @explosionEmitter )
  
  ; an affector is a mechanism that alters the particles over time, the fade out
  ; affector gradually fades the particles out so they are invisible when they
  ; are deleted this lets them smoothly vanish instead of poping out of existence
  IrrAddFadeOutParticleAffector( *ParticlesNode )
  
  ; another affector is the gravity affector, this adds a small amount of velocity
  ; to the particles each frame, although its called a gravity affector it can
  ; be used to push the particles in any direction so you can have drifting smoke
  ; bubbling fountains, etc ...
  IrrAddGravityParticleAffector ( *ParticlesNode, 0.5, 0.5, 0.0 )
  
  IrrAddStopParticleAffector(*ParticlesNode,#POWERTIME);
  ; at the moment the particles are simple grey squares and before we apply a
  ; material to them we need to get the particle system as a scene node
  ;;ParticlesNode = SmokeParticles
  
  ; load a grey smoke like image for the particle
  *ParticleTexture = IrrGetTexture( ".\media\blast.jpg" )
  
  ; apply the texture to the particles system, this texture will now be drawn
  ; across each particles surface
  IrrSetNodeMaterialTexture( *ParticlesNode, *ParticleTexture, 0 )
  
  ; out particle system is not affected by lighting so we make it self
  ; illuminating
  IrrSetNodeMaterialFlag( *ParticlesNode, #IRR_EMF_LIGHTING, #IRR_OFF )
  
  ; as the particle texture has black borders, each overlapping particle would
  ; draw this blackness ontop of one another as a sharp egde they would look like
  ; a lot of solid squares instead of the transparent gas effect we are trying
  ; to created. so here we change the material type of the node - instead of
  ; drawing the node solidly onto the screen it is added onto the colour
  ; underneath itself so black doesnt change the color and white would build up
  ; top of the existing color until it completly saturates the pixel
  IrrSetNodeMaterialType ( *ParticlesNode, #IRR_EMT_TRANSPARENT_ADD_COLOR  )
  
  IrrSetNodeMaterialFlag(*ParticlesNode,#IRR_EMF_BACK_FACE_CULLING,#False);
  
  ; add a fixed position camera to the scene so we can view the particle system.  
  IrrSetNodePosition(*ParticlesNode,x,y,z); x+5,y,z-Board\center\z-5)
  
  
EndProcedure


;; ////////////////////////////////////////////////////////////////////////////
;; Create the Floor from a PlaneSceneNode

Procedure createFloor()
  Shared *FloorTexture


  ;make a simple Plane as Background
  *Game_PlaneNode = IrrAddPlaneSceneNode( "SimplePacManFloor", 5, 5, 10, 10, 8,8 )
    
  IrrSetNodeRotation(*Game_PlaneNode,90,00,0)

  IrrSetNodePosition(*Game_PlaneNode,20,20,0)
  
  IrrSetNodeScale(*Game_PlaneNode,20,1,20)

  IrrSetNodeMaterialTexture( *Game_PlaneNode, *FloorTexture, 0 )

;IrrSetNodeAllMaterialEmissiveColor(*Game_PlaneNode,255,255,255,255)
;IrrSetNodeAllMaterialSpecularColor(*Game_PlaneNode,255,255,255,255)
  IrrSetNodeMaterialFlag( *Game_PlaneNode, #IRR_EMF_LIGHTING, #True )            
; IrrSetNodeMaterialType( *Game_PlaneNode, #IRR_EMT_REFLECTION_2_LAYER)

EndProcedure

;; ////////////////////////////////////////////////////////////////////////////
;; Create a Box (Walls)

Procedure addBox(x.l,y.l,z.l)
  Shared *CubeMesh
  Shared *Cubetexture 
  
  *stone.l = IrrAddMeshToScene( *CubeMesh )    
  IrrSetNodeRotation(*stone,90,00,0)
  IrrSetNodeMaterialTexture( *stone, *CubeTexture, 0 )
  IrrSetNodePosition(*stone,x*2,y*2,z*2)
  IrrSetNodeMaterialFlag( *stone, #IRR_EMF_LIGHTING, #True)
    
  AddElement(Objects())
  Objects()\node = *stone
  Objects()\pos\x = mcSetFakeFloat( x*2.00 )
  Objects()\pos\y = mcSetFakeFloat(y*2.00)
  Objects()\pos\width = mcSetFakeFloat(2.00)
  Objects()\type = #OBJ_TYPE_WALL
  Objects()\state = #OBJ_STATE_UNKNOWN
     
EndProcedure

;; ////////////////////////////////////////////////////////////////////////////
;; Create a Dot

Procedure addDot(x.l,y.l,z.l)  
  *dot.l = IrrAddSphereSceneNode( 0.2, 8 )    
  IrrSetNodePosition(*dot,x*2,y*2,z*2)  
  IrrSetNodeAllMaterialEmissiveColor(*dot,128,200,0,110)
  IrrSetNodeMaterialFlag( *dot, #IRR_EMF_LIGHTING, #True)

  AddElement(Objects())
  
  Objects()\node = *dot
  Objects()\pos\x = mcSetFakeFloat( x*2.00 )
  Objects()\pos\y = mcSetFakeFloat(y*2.00)
  Objects()\pos\width = mcSetFakeFloat(2.00)
  Objects()\type = #OBJ_TYPE_DOT
  Objects()\state = #OBJ_STATE_UNKNOWN
  
EndProcedure


;; ////////////////////////////////////////////////////////////////////////////
;; Create a PowerDot

Procedure addPower(x.l,y.l,z.l)  
  *power.l = IrrAddSphereSceneNode( 0.5, 8 )    
  IrrSetNodePosition(*power,x*2,y*2,z*2)  
  IrrSetNodeAllMaterialEmissiveColor(*power,128,243, 204, 42)
  IrrSetNodeMaterialFlag( *power, #IRR_EMF_LIGHTING, #True)
  AddElement(Objects())
  Objects()\node = *power
  Objects()\pos\x = mcSetFakeFloat( x*2.00 )
  Objects()\pos\y = mcSetFakeFloat(y*2.00)
  Objects()\pos\width = mcSetFakeFloat(2.00)
  Objects()\type = #OBJ_TYPE_POWERDOT
  Objects()\state = #OBJ_STATE_UNKNOWN
EndProcedure


;; ////////////////////////////////////////////////////////////////////////////
;; Create a Transporter

Procedure addTransporter(x.l,y.l,z.l)    
  Shared *TransporterMesh
  *trans = IrrAddMeshToScene( *TransporterMesh )

  IrrSetNodePosition(*trans,x*2,y*2,z*2)  
  IrrSetNodeAllMaterialEmissiveColor(*trans,128,243, 204, 42)
  IrrSetNodeMaterialFlag( *trans, #IRR_EMF_LIGHTING, #True)
  IrrSetNodeScale(*trans,0.1,0.1,0.1)  
    
  ;Let rotate that thingy
  IrrAddRotationAnimator(*trans,0.7,0,0)    
    
  AddElement(Objects())
  Objects()\node = *trans
  Objects()\pos\x = mcSetFakeFloat(x *2.00 )
  Objects()\pos\y = mcSetFakeFloat(y * 2.00)
  Objects()\pos\width = mcSetFakeFloat(2.0)
  Objects()\type = #OBJ_TYPE_TRANSPORTER
  Objects()\state = #OBJ_STATE_UNKNOWN
   
  IrrSetNodeMaterialType ( *trans, #IRR_EMT_TRANSPARENT_ADD_COLOR  )

  
EndProcedure



;; ////////////////////////////////////////////////////////////////////////////
;; Create Pacman - our hero

Procedure addPacman(x.l,y.l,z.l)    
  Shared *OurCamera.l
  Shared player
  Shared *PacmanMesh
  Shared *PacmanTexture
  
  *pac = IrrAddMeshToScene( *PacmanMesh )
  IrrSetNodeMaterialTexture( *pac, *PacmanTexture, 0 )
  
  player\node = *pac
  player\pos\x = mcSetFakeFloat( x*2);
  player\pos\y =  mcSetFakeFloat( y*2);
  player\pos\z =  mcSetFakeFloat( z*2);
      
  IrrSetNodePosition(*pac,x*2,y*2,z*2)  
  IrrSetNodeRotation(*pac,90,00,0)
  IrrSetNodeAllMaterialEmissiveColor(*pac,128,243, 204, 42)
  IrrSetNodeMaterialFlag( *pac, #IRR_EMF_LIGHTING, #True)
  
  IrrSetCameraTarget(*OurCamera,x*2,y*2,z*2)
  
;  *pac_light = IrrAddLight(0,8,00,80, 240, 16,0.07)

  *pac_light = IrrAddLight(0,8,00,80, 160, 180, 0.07)

;  IrrSetLightAmbientColor(*pac_light,85,239, 240, 16)

  IrrAddChildToParent(*pac_light,*pac)
  player\light = *pac_light
  
  IrrAddNodeShadow(*pac,#True)
  
  
  
EndProcedure



;; ////////////////////////////////////////////////////////////////////////////
;; Create Pacman - this bloody bastards....

Procedure addMonster(x.l,y.l,z.l)  
  Shared *MonsterMesh
  Shared *MonsterTexture 

  *mons.l = IrrAddMeshToScene( *MonsterMesh )    
  IrrSetNodeMaterialTexture( *mons, *MonsterTexture, 0 )
  
  IrrSetNodePosition(*mons,x*2,y*2,z*2)  
  IrrSetNodeRotation(*mons,90,0,0)
   IrrSetNodeAllMaterialEmissiveColor(*mons,80,243, 04, 2)
;   IrrSetNodeAllMaterialSpecularColor(*mons,10,243, 204, 42)
  IrrSetNodeMaterialFlag( *mons, #IRR_EMF_LIGHTING, #True)
  AddElement(Objects())
  Objects()\node = *mons
  Objects()\pos\x = mcSetFakeFloat( x*2.00 )
  Objects()\pos\y = mcSetFakeFloat( y*2.00)
  Objects()\pos\z = mcSetFakeFloat( z*2.00)
  Objects()\pos\width = mcSetFakeFloat(2.00)
  Objects()\type = #OBJ_TYPE_ENEMY
  Objects()\state = #OBJ_STATE_UNKNOWN
  Objects()\move_direction = #PACDIR_STAND 
  Objects()\wish_direction = Random(3)+1 

  ;To avoid problems when going through linked list
  AddElement(Monsters())
  Monsters() = @Objects()

  ;This makes them look like Ghosts....  
  IrrSetNodeMaterialType ( *mons, #IRR_EMT_TRANSPARENT_ADD_COLOR  )
  
  
EndProcedure


;; ////////////////////////////////////////////////////////////////////////////
;; Build the Level....

Procedure buildLevel2(*lev.sLevel)
        
  For y.l = 0 To *lev\height-1
  
    t.s = PeekS(*lev + OffsetOf(sLevel\data) + (y*(*lev\width+1)))

;;    Debug(t)
    
    For x.l = 1 To *lev\width
      st.s = Mid(t,x,1)
      If st="X"
        addBox(x-1,y,1)
      EndIf
      If st="."
        addDot(x-1,y,1)
      EndIf
       If st="o"
         addPower(x-1,y,1)
       EndIf
       If st="p"
         addPacman(x-1,y,1)
       EndIf
       If st="m"
         addMonster(x-1,y,1)
       EndIf
       If st="t"
         addTransporter(x-1,y,1)
       EndIf
    Next
  Next
;;  Debug("Collected " +Str(CountList(Objects())))
EndProcedure


;; ////////////////////////////////////////////////////////////////////////////
;; Check if a move in the direction is valid...
;;
Procedure check(dir.l,xl.l, yl.l, zl) 
  Select dir
    Case #PACDIR_UP
        yl = yl +  100
    Case #PACDIR_DOWN
        yl = yl - 100
    Case #PACDIR_RIGHT
        xl = xl- 10   
    Case #PACDIR_LEFT
        xl = xl + 100
  EndSelect
  
  *touch.sObject = isCollission(xl,yl,zl)
  If *touch <> #Null 
    If *touch\type = #OBJ_TYPE_WALL
      ProcedureReturn #False
    EndIf
  EndIf
  ProcedureReturn #True

EndProcedure


;; ////////////////////////////////////////////////////////////////////////////
;; Moves our PacMan according the informations of his moves and wishes

Procedure movePacman(isFaked.l = #False)
  Shared *OurCamera.l
  Shared player  
  
  xl.l = player\pos\x
  yl.l = player\pos\y
  zl.l = player\pos\z

  If check(player\wish_direction,xl,yl,zl)
    player\move_direction = player\wish_direction
    If isFaked 
      If check(player\move_direction,xl,yl,zl) = #False
        player\wish_direction = 1+(Random(3))  
      Else
        If player\faketimemove < ElapsedMilliseconds()
          player\wish_direction = 1+(Random(3))  
          player\faketimemove = ElapsedMilliseconds()+1000
        EndIf
      EndIf
    EndIf
  EndIf 

  
  rot.f = 0
  Select player\move_direction
    Case #PACDIR_UP
        yl = yl +  200
        rot= 180
    Case #PACDIR_DOWN
        yl = yl - 200
        rot= 0
    Case #PACDIR_RIGHT
        xl = xl-  200     
        rot= 270
    Case #PACDIR_LEFT
        xl = xl + 200    
        rot= 90
    EndSelect
    
    *touch.sObject = isCollission(xl,yl,zl)
    
    ;If We touch a Object, we need to see what it is.....
    If *touch <> #Null 
      If *touch\type <> #OBJ_TYPE_TRANSPORTER
          player\transportflag = #False        
      EndIf      
      Select *touch\type
        Case #OBJ_TYPE_WALL
          player\move_direction = #PACDIR_STAND
      Case #OBJ_TYPE_ENEMY

            now.l = ElapsedMilliseconds()
            If player\powertime > 0 And player\powertime > now
              *touch\state = #OBJ_STATE_DEAD
            Else
              *fader.l = IrrGuiAddInOutFader()
              IrrGuiFaderSetColor(*fader, 0,255,0,0)
              IrrGuiFaderFadeIn(*fader,50)               
            EndIf

        Case #OBJ_TYPE_DOT
            *touch\state = #OBJ_STATE_DEAD
            IrrSetNodeVisibility(*touch\node,#False)
            player\score+1

        Case #OBJ_TYPE_TRANSPORTER
          If player\transportflag = #False
            ForEach objects() 
              If Objects()\type = #OBJ_TYPE_TRANSPORTER And Objects()\node <> *touch\node
                xl = Objects()\pos\x
                yl = Objects()\pos\y
                player\transportflag = #True
;                zl = Objects()\pos\z
              EndIf
            Next
          EndIf
          

        Case #OBJ_TYPE_POWERDOT
            xc.f = mcGetFakeFloat(xl): yc.f = mcGetFakeFloat(yl): zc.f = mcGetFakeFloat(zl);
            _makeExplosion(xc,yc,zc)
            player\powertime = ElapsedMilliseconds()+#POWERTIME
            IrrSetNodeVisibility(*touch\node,#False)
            *touch\state = #OBJ_STATE_DEAD
          
;          Debug("Bouncde against an Enemy...")
        Default:
          player\transportflag = #False        
      EndSelect
    EndIf
    
    
  If player\move_direction = #PACDIR_STAND
;    Debug("Standing Pac-at: "+StrD(xd)+","+StrD(yd)+","+StrD(zd) + " // "+Str(vx)+","+Str(vy))
  Else 
    player\pos\x = xl
    player\pos\y = yl
    player\pos\z = zl
    xc.f = mcGetFakeFloat(xl): yc.f = mcGetFakeFloat(yl): zc.f = mcGetFakeFloat(zl);
    IrrSetNodePosition(player\node,xc,yc,zc)
    IrrGetNodeRotation(player\node,@xr.f,@yr.f,@zr.f)
    IrrSetNodeRotation(player\node,xr,yr,rot)
    IrrSetNodePosition(player\node,xc,yc,zc)
    
    IrrGetNodePosition(*OurCamera,@cx.f,@cy.f,@cz.f)
    IrrSetNodePosition(*OurCamera,xc,0,20)    

    IrrSetNodePosition(*OurCamera,xc,yc-20,20)    

    IrrSetCameraTarget(*OurCamera,xc,yc,zc)
    
  EndIf
  
  
  

EndProcedure


;To set the correct Texture when Paccie is full of power....
Procedure modMonsters()
  Shared *MonsterTexture 
  Shared *MonsterTexture2
  Shared *MonsterTextureEyes
  
  *useTex = *MonsterTexture
  now.l = ElapsedMilliseconds()
  If player\powertime > 0 And player\powertime > now
    *useTex = *MonsterTexture2
  EndIf
  
  ForEach Monsters()
    *mon.sObject = Monsters()
    If *mon\state <> #OBJ_STATE_DEAD
      IrrSetNodeMaterialTexture( *mon\node, *useTex, 0 )       
    Else
      IrrSetNodeMaterialTexture( *mon\node, *MonsterTextureEyes, 0 )       
    EndIf
    
  Next
  
  
  
  
EndProcedure


Procedure moveMonsters()
  
  modMonsters()
  ForEach Monsters()

    *mon.sObject = Monsters();
    
    If check(*mon\wish_direction,*mon\pos\x,*mon\pos\y,*mon\pos\width)
      *mon\move_direction = *mon\wish_direction
      *mon\wish_direction = 1+(Random(3))  
    EndIf 
    
    
    yl.l = *mon\pos\y
    xl.l = *mon\pos\x
    zl.l = *mon\pos\width

    rot.f = 0

    Select *mon\move_direction
      Case #PACDIR_UP
        yl = yl +  100
        rot= 90
      Case #PACDIR_DOWN
        yl = yl - 100
        rot= 270
      Case #PACDIR_RIGHT
        xl = xl- 100     
        rot= 180
      Case #PACDIR_LEFT
        xl = xl + 100
        rot= 0
    EndSelect

    

    *touch.sObject = isCollission(xl,yl,zl)
    If *touch <> #Null 
      Select *touch\type
        Case #OBJ_TYPE_WALL, #OBJ_TYPE_TRANSPORTER
          ;set new dir per random....
          *mon\move_direction = #PACDIR_STAND
      EndSelect       
      
    EndIf
    
    If *mon\move_direction = #PACDIR_STAND 
      *mon\wish_direction = 1+(Random(3))  
;      Debug("new state="+Str(*mon\wish_direction))
    Else         
;      Debug("Set Position of Enemy x="+Str(xl)+", y="+Str(zl))
      *mon\pos\x = xl
      *mon\pos\y = yl
      xc.f = mcGetFakeFloat(xl): yc.f = mcGetFakeFloat(yl): zc.f = mcGetFakeFloat(zl);
      IrrSetNodePosition(*mon\node,xc,yc,zc)
      IrrGetNodeRotation(*mon\node,@xr.f,@yr.f,@zr.f)
      IrrSetNodeRotation(*mon\node,xr,yr,rot)
      IrrSetNodePosition(*mon\node,xc,yc,zc)
    EndIf
       
            
  Next
  

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_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)        
        
      Case #IRR_KEY_F9        
        IrrSaveScreenshot("./menu.bmp")
    EndSelect        
  EndIf     
 
  ProcedureReturn #True
EndProcedure

Procedure _Menu_Init()
  Shared *OurCamera.l, *menu_animator
   IrrSetEventReceiver(*Menu_ER)

   buildLevel2(?level_o)
   
   IrrSetNodeRotation(*OurCamera,0,90,0)
   
    xc.f = mcGetFakeFloat(player\pos\x): yc.f = mcGetFakeFloat(player\pos\y): zc.f = mcGetFakeFloat(player\pos\z);
    
;     IrrGetNodePosition(*OurCamera,@cx.f,@cy.f,@cz.f)
;     IrrSetNodePosition(*OurCamera,xc,0,20)    
    IrrSetCameraTarget(*OurCamera,xc,yc,zc)


;IrrAddFlyCircleAnimator(*irr_node.l,centre_x.f,centre_y.f,centre_z.f, radius.f, speed.f=0.0001, dirX.f=0.0, dirY.f=1.0, dirZ.f=0.0)
  ;*menu_animator = IrrAddFlyCircleAnimator(*OurCamera,xc,yc,30, 10,0.0001,0,0,0)

;    IrrSetCameraTarget(*OurCamera,xc,yc,3)
;   
;     *light = IrrAddLight(0,8,00,80, 240, 16,0.07)
;     IrrSetLightAmbientColor(*light,255,20,80,20)
  _Mouse_LMB = #False
EndProcedure

Procedure _Menu_Main()
  Shared *OurCamera.l
    ;Draw Title
    
    
  ; Simulate Paccie
  If player\move_direction = #PACDIR_STAND
    player\wish_direction = Random(3)+1
  EndIf
      
  title_xpos.l =  (g_ScreenSize_X/2) - (295/2)
  menu_xpos.l  =  (g_ScreenSize_X/2) - (178/2)
    
  IrrDraw2DImageElement(*Menu_Titlepic, title_xpos,20,  0,0, 295,129);

  ;DrawMenu

  If StdColl(menu_xpos,200,178,78,_mouse_x,_mouse_y,2,2)   
    IrrDraw2DImageElement(*Menu_Optionpic, menu_xpos,200,  192,20, 192+178,78 );
    If _mouse_LMB 
      SwitchState(#PAC_STATE_GAME)
    EndIf    
  Else
    IrrDraw2DImageElement(*Menu_Optionpic, menu_xpos,200,  14,20, 176,78 );    
  EndIf

  If StdColl(menu_xpos,300,178,78,_mouse_x,_mouse_y,2,2)   
    IrrDraw2DImageElement(*Menu_Optionpic, menu_xpos,300,  192,110, 192+178,110+78 );
    If _mouse_LMB 
      g_GameQuit = #True
    EndIf
  Else
    IrrDraw2DImageElement(*Menu_Optionpic, menu_xpos,300,  14,110, 176,110+78 );
  EndIf

  movePacman(#True)
  moveMonsters()

    
EndProcedure

Procedure _Menu_Cleanup()
  Shared *OurCamera.l,*menu_animator

;   *fader.l = IrrGuiAddInOutFader()
;   IrrGuiFaderSetColor(*fader, 0,0,0,0)
;   IrrGuiFaderFadeOut(*fader,1000)        


  ForEach Objects()
    IrrRemoveNode(Objects()\node)
    DeleteElement(Objects())
  Next
  
  IrrRemoveNode(player\light)
  IrrRemoveNode(player\node)
  
  
  ClearList(Monsters())
  ClearList(Objects())
  
  IrrRemoveAnimator(*OurCamera,*menu_animator)
    
EndProcedure


ProcedureC _Game_Events(*event.SEvent)
  Shared player  
  
  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(#PAC_STATE_MENU)
          EndIf
        Else
            _EscapeDown = #False
        EndIf        
      Case #IRR_KEY_ARROW_DOWN 
        
        player\wish_direction = #PACDIR_DOWN
      Case #IRR_KEY_ARROW_UP 
        player\wish_direction = #PACDIR_UP        
      Case #IRR_KEY_ARROW_LEFT
        player\wish_direction = #PACDIR_LEFT
      Case #IRR_KEY_ARROW_RIGHT 
        player\wish_direction = #PACDIR_RIGHT
        
      Case #IRR_KEY_SPACE
        *fader.l = IrrGuiAddInOutFader()
        IrrGuiFaderSetColor(*fader, 0,255,0,0)
        IrrGuiFaderFadeIn(*fader,4000)  
        
      Case #IRR_KEY_F9        
        IrrSaveScreenshot("./game.bmp")

    EndSelect        
  EndIf     
 
  ProcedureReturn #True
EndProcedure
  
  
  
  


Procedure _Game_Init()
  Shared *OurCamera.l

  
  *fader.l = IrrGuiAddInOutFader()
  IrrGuiFaderSetColor(*fader, 0,0,0,0)
  IrrGuiFaderFadeIn(*fader,4000)        

  IrrSetEventReceiver(*Game_ER)
  
  buildLevel2(?level_o)
  
  player\lives=3
  player\score=0
  player\move_direction = #PACDIR_STAND
  player\wish_direction = #PACDIR_STAND
  

player\transportflag = #False

    xc.f = mcGetFakeFloat(player\pos\x): yc.f = mcGetFakeFloat(player\pos\y): zc.f = mcGetFakeFloat(player\pos\z);
    
    IrrGetNodePosition(*OurCamera,@cx.f,@cy.f,@cz.f)
    IrrSetNodePosition(*OurCamera,xc,0,20)    
    IrrSetCameraTarget(*OurCamera,xc,yc,zc)
  
EndProcedure


Procedure _Game_Cleanup()
  ForEach Objects()
    IrrRemoveNode(Objects()\node)
    DeleteElement(Objects())
  Next
  
  IrrRemoveNode(player\light)
  IrrRemoveNode(player\node)
  
  
  ClearList(Monsters())
  ClearList(Objects())
  
  
EndProcedure

Procedure _Game_Main()

  movePacman()
  
  moveMonsters()


    ;Draw Lives....
    For i = 0 To player\lives    
      IrrDraw2DImageElement(*Game_LIVESYMBOL, 20+(i*40),20,  0,0, 40,37);
    Next

  Irr2DFontDraw ( *Font, "Score: "+RSet(Str(player\score),8,"0") , 320, 20, 550, 36 )      

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



Procedure _init()
  Shared *OurCamera.l;
  Shared *MonsterMesh
  Shared *MonsterTexture 
  Shared *MonsterTexture2
  Shared *MonsterTextureEyes
  Shared *CubeMesh
  Shared *CubeTexture
  Shared *FloorTexture
  Shared *PacmanMesh
  Shared *PacmanTexture
  Shared *TransporterMesh
  
  ; -----------------------------------------------------------------------------
  ; 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_OPENGL,g_ScreenSize_X, g_ScreenSize_Y,#False, #False,#False, 16, #True, #False,#False,WindowID(#Window_0) )      
                  
            
      ; set the window caption
;      IrrSetWindowCaption( "Advanced Example: SimplePacMan" )


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

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


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

      ;Load Textures ans Meshes
      *CubeMesh    = IrrGetMesh(".\media\cube.3ds")  
      *CubeTexture = IrrGetTexture("./media/cube1_au.bmp")  

;      *PacmanMesh    = IrrGetMesh(".\media\mypac.obj")  
      *PacmanMesh    = IrrGetMesh(".\media\mypac.md2")  
      ;not needed for OBJ
      *PacmanTexture = IrrGetTexture("./media/pacman.bmp.tga")  
      
;      *MonsterMesh = IrrGetMesh(".\media\Monster.obj")  
      *MonsterMesh = IrrGetMesh(".\media\Monster.md2")  
      
      *MonsterTexture  = IrrGetTexture(".\media\monster.tga")  
      *MonsterTexture2  = IrrGetTexture(".\media\monster_h.tga")  
      *MonsterTextureEyes  = IrrGetTexture(".\media\monster_eyes.png")  
;    *MonsterMesh = IrrGetMesh(".\media\Monster.ms3d")  
;    *MonsterTex  = IrrGetTexture(".\media\monster.tga")  
;;    ;  IrrSetNodeMaterialTexture( *mons, *MonsterTex, 0 )
      
      
      *FloorTexture = IrrGetTexture( ".\media\floor.jpg" )
      
      
      *TransporterMesh = IrrGetMesh(".\media\thorus.md2")  
                  
            
            
;      *light = IrrAddLight(215,160,80,128,128,128,0.8001)
      ;  IrrSetLightAmbientColor(*light,255,20,80,20)
      
      ; add camera
      *OurCamera = IrrAddCamera(00,20,30,20,20,-5)
      
      
      *Game_LIVESYMBOL = IrrGetTexture( ".\media\spm_lives.png" )
      *Menu_titlepic = IrrGetTexture( ".\media\simple_pacman_title.png" )
      *Menu_optionpic = IrrGetTexture( ".\media\menuoptions.png" )
      
      
;      *Font = IrrGetFont ( ".\media\font_pacman.bmp" )
      *Font = IrrGetFont ( ".\media\pacman_font2h.tga" )
  
            
      ;disable mouse cursor
      IrrShowMouse()
            
      ;Create our own Event-Receiver
      *Game_ER.l = IrrCreateEventReceiver(@_Game_Events())
      *Menu_ER.l = IrrCreateEventReceiver(@_Menu_Events())

      
      createFloor()
      
      ;Switch to the Game (directly)           
      SwitchState(#PAC_STATE_MENU)
    Else
      MessageRequester("Problem","Could not open the Screen...")
      End
    EndIf
  EndIf
  
  
  
EndProcedure

Procedure _cleanup()
  SwitchState(#PAC_STATE_NOTHING)
  ; -----------------------------------------------------------------------------
  ; Stop the irrlicht engine and release resources
  IrrStop()
  
EndProcedure

;--- Start

;; ////////////////////////////////////////////////////////////////////////////

_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(1)
Wend

_cleanup()



End

DataSection
Level_o:
Data.l 19,21
Data.s  "XXXXXXXXXXXXXXXXXXX"
Data.s  "X........X........X"
Data.s  "XoXX.XXX.X.XXX.XXoX"
Data.s  "X.XX.XXX.X.XXX.XX.X"
Data.s  "X.................X"
Data.s  "X.XX.X.XXXXX.X.XX.X"
Data.s  "X....X...X...X....X"
Data.s  "XXXX.XXX.X.XXX.XXXX"
Data.s  "   X.X.......X X   "
Data.s  "XXXX.X.XXmXX.X.XXXX"
Data.s  "t...p..XmmmX.X....t"
Data.s  "XXXX.X.XXXXX.X.XXXX"
Data.s  "   X.X.......X X   "
Data.s  "XXXX.XXX.X.XXX.XXXX"
Data.s  "X....X...X...X....X"
Data.s  "X.XX.X.XXXXX.X.XX.X"
Data.s  "X.................X"
Data.s  "X.XX.XXX.X.XXX.XX.X"
Data.s  "XoXX.XXX.X.XXX.XXoX"
Data.s  "X........X........X"
Data.s  "XXXXXXXXXXXXXXXXXXX"



Data.l    30,30
Data.s  "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
Data.s  "X............................X"
Data.s  "X.XXXXXXXX.XXXXXXXX.XXXXXXXX.X"
Data.s  "X.X........................X.X"
Data.s  "X.X.XX.XXXXXXXXXXXXXXXX.XX.X.X"
Data.s  "X.X.X....................X.X.X"
Data.s  "X.X.X.XXXXXXXXXXXXXXXXXX.X.X.X"
Data.s  "X.X...X................X...X.X"
Data.s  "X...XXX.XXX,XXXXXX.XXX.XXX...X"
Data.s  "X.X.X...X............X...X.X.X"
Data.s  "X.X.X.XXX.XXX.XX.XXX.XXX.X.X.X"
Data.s  "X.X.X.X................X.X.X.X"
Data.s  "X.X.X.X.XXXXXXXXXXXXXX.X.X.X.X"
Data.s  "X.X...X.X............X.X...X.X"
Data.s  "X.X.XXXXX                X"


EndDataSection


; IDE Options = PureBasic 4.10 Beta 3 (Windows - x86)
; ExecutableFormat = Console
; CursorPosition = 1189
; FirstLine = 1155
; Folding = -----
; Executable = release\simplePacman.exe