Pour une app dans ce genre, j'utiliserais plutot un tableau qu'une liste chainée car on connait le nombre de cases qui sont de tailles et d'espacement constants donc il est très simple de trouver la case sur laquelle est le crayon sans avoir à toute les tester.
J'utiliserais simplement WindowMouseX/Y() aussi plutot que MouseX/Y() ce qui faciliterai le passage screen <-> window
Je te fais un exemple en vitesse, mais c'est juste comment je verais la chose, libre à toi de programmer comme tu le veux  
Code : Tout sélectionner
;----------------
;- Window Constants
;
Enumeration
  #Fenetre
EndEnumeration
;- MenuBar Constants
;
Enumeration
  #MenuBar_0
EndEnumeration
Enumeration
  #MENU_OUVRIR
  #MENU_SAUVEGARDE
  #MENU_QUITTER
  #MENU_JEU
  #MENU_CONSTRUCTION
  #MENU_ABOUT
EndEnumeration
;- Gadget Constants
;
Enumeration
  #Text_Largeur
  #Spin_Largeur
  #Text_Mode
  #Text_Longueur
  #Spin_Longueur
  #Frame3D_0
EndEnumeration
;- StatusBar Constants
;
Enumeration
  #StatusBar_0
EndEnumeration
;- Sprites Constants
;
Enumeration
  #Fond
  #Grille
  #Indication_Horiz
  #Indication_Vert
  #Crayon
  #Cross
EndEnumeration
;- Autres Constants
#Max_Cross = 10 ; nombre maxi de cases
;----------------
;- Structures
;----------------
Structure Cross
  x.f ; stocke position en x
  y.f ; stocke position en y
  Sprite.b ; stocke le sprite
EndStructure
;- Declarations globales
;
Global Dim Cross.Cross(#Max_Cross, #Max_Cross) ; tableau des cases
Global MaxCrossX.l, MaxCrossY.l ; nombre maxi de cases en x/y de la partie en cour (ne pas confondre avec le nombre maxi de case d'une partie en général)
Global CrayonX.l, CrayonY.l ; stock la position du crayon
Global CrayonCrossX.l, CrayonCrossY.l ; Stock la cases sur laquelle est le crayon
Global SwitchCursor.b ; va nous permetre d'afficher / cacher le curseur seulement s'il y a besoin et non à chaque boucle
Declare.b Generer_Cross()
;- Initialistions
;
InitSprite()
InitSprite3D()
SwitchCursor = #True
MaxCrossX = 5 : MaxCrossY = 5 ; nombre de cases de la premieres partie à 5x5
; On génère le premier tableau
Generer_Cross()
;- Creation fenetre / gadgets / ecran
;
OpenWindow(#Fenetre, 0, 0, 622, 522, "Exemple cases", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  If CreateMenu(#MenuBar_0, WindowID(#Fenetre))
    MenuTitle("Fichier")
      MenuItem(#MENU_OUVRIR, "Ouvrir un Purecross")
      MenuItem(#MENU_SAUVEGARDE, "Sauvegarder un Purecross")
      MenuBar()
      MenuItem(#MENU_QUITTER, "Quitter")
    MenuTitle("Mode")
      MenuItem(#MENU_JEU, "Mode Jeu")
      MenuItem(#MENU_CONSTRUCTION, "Mode Construction")
    MenuTitle("Aide")
      MenuItem(#MENU_ABOUT, "A propos de PureCross ")
  EndIf
  
  If CreateStatusBar(#StatusBar_0, WindowID(#Fenetre))
    AddStatusBarField(180)
    StatusBarText(#StatusBar_0, 0, "Purecross par Hackotedelaplaque")
  EndIf
  
  If CreateGadgetList(WindowID(#Fenetre))
    TextGadget(#Text_Largeur, 430, 100, 130, 20, "Largeur du PureCross : ")
    SpinGadget(#Spin_Largeur, 570, 100, 40, 20, 5, 20,#PB_Spin_ReadOnly | #PB_Spin_Numeric)
      SetGadgetState(#Spin_Largeur, MaxCrossX)
    
    TextGadget(#Text_Mode, 0, 20, 630, 30, "Mode construction", #PB_Text_Center)
      SetGadgetFont(#Text_Mode, FontID1)
      SetGadgetColor(#TEXT_MODE,#PB_Gadget_FrontColor,RGB(0, 0, 255))
    
    TextGadget(#Text_Longueur, 430, 160, 120, 20, "Longueur du PureCross :")
    SpinGadget(#Spin_Longueur, 570, 160, 40, 20, 5, 20,#PB_Spin_ReadOnly | #PB_Spin_Numeric)
      SetGadgetState(#Spin_Longueur, MaxCrossY)
    
    Frame3DGadget(#Frame3D_0, 420, 50, 200, 420, "Paramètres du PureCross")
  EndIf
  
  OpenWindowedScreen(WindowID(#Fenetre), 5, 70, 400, 400, 0, 0, 0)
  
  ;- Chargement / creation sprites
  ; On peut très bien utiliser le même identifiant pour un sprite normal et un sprite3D
  
  UsePNGImageDecoder()
  TransparentSpriteColor(#PB_Default, RGB(255, 0, 255))
  LoadSprite(#Fond, "back.png")
  
  LoadSprite(#Grille, "case_vierge.png", #PB_Sprite_Texture)
  LoadSprite(#Cross, "cross.png", #PB_Sprite_Texture)
  LoadSprite(#Crayon, "crayon.png", #PB_Sprite_Texture)
  
  CreateSprite(#Indication_Horiz, 92, 12,#PB_Sprite_Texture)
  
  StartDrawing(SpriteOutput(#Indication_Horiz))
    Box(0, 0, 92, 12,RGB(157, 255, 98))
    Line(0, 0, 92, 0,RGB(91, 199, 107))
  StopDrawing()
  
  CreateSprite(#Indication_Vert, 12, 92, #PB_Sprite_Texture)
  
  StartDrawing(SpriteOutput(#Indication_Vert))
    Box(0, 0, 12, 92,RGB(0, 0, 255))
    Line(0, 0, 0, 92,RGB(2, 2, 153))
  StopDrawing()
  
  
  ;- Sprites3D
  
  CreateSprite3D(#Grille, #Grille)
  CreateSprite3D(#Cross, #Cross)
  CreateSprite3D(#Indication_Horiz, #Indication_Horiz)
  CreateSprite3D(#Indication_Vert, #Indication_Vert)
  CreateSprite3D(#Crayon, #Crayon)
  
  Repeat
  
    ; On recupère la position du crayon sur l'ecran (sur la fenetre on s'en fou un peut...)
    CrayonX = WindowMouseX(0) - 5
    CrayonY = WindowMouseY(0) - 70
    
    ; On verifi que les positions restent dans l'écran
    If CrayonX < 0    : CrayonX = 0   : EndIf
    If CrayonX > 400  : CrayonX = 400 : EndIf
    If CrayonY < 0    : CrayonY = 0   : EndIf
    If CrayonY > 400  : CrayonY = 400 : EndIf
    
    ; On calcul sur quelle case est le crayon
    CrayonCrossX = Round((CrayonX  - 200) / 12 + MaxCrossX / 2, 1) - 1
    CrayonCrossY = Round((CrayonY  - 200) / 12 + MaxCrossY / 2, 1)  - 1
    
    ; on verifi qu'il sagit bien d'une case du tableau sinon on met à -1 ce qui permetre de ne pas change une case qui "n'existe" pas
    If CrayonCrossX < 0 : CrayonCrossX = -1 : EndIf
    If CrayonCrossX > MaxCrossX -1 : CrayonCrossX = -1 : EndIf
    If CrayonCrossY < 0 : CrayonCrossY = -1 : EndIf
    If CrayonCrossY > MaxCrossY -1 : CrayonCrossY = -1 : EndIf
    
    ; Si le curseur est dans l'écran, on le cache
    CursorInScreen = WindowMouseX(0) >= 5 And WindowMouseX(0) <= 405 And WindowMouseY(0) >= 70 And WindowMouseY(0) <= 470
    If CursorInScreen And SwitchCursor = #True
      ShowCursor_(#False)
      SwitchCursor = #False
    ElseIf Not CursorInScreen And SwitchCursor = #False
      ShowCursor_(#True)
      SwitchCursor = #True
    EndIf
    
    ;- Evenements sur la fenetre
    ;
    wEvent = WindowEvent()
    If wEvent ; S'il y a un evenement 
      
      Repeat ; Il peut y en avoir donc un boucle pour ne pas en perdre
      
        Select wEvent
        
          Case #WM_CLOSE ; La croix a été clikée
            Quit = #True
            
          Case #PB_Event_Gadget
            Select EventGadget()
            
              Case #Spin_Largeur
                ; on verifi que le nombre de cases n'est pas supérieur à #Max_Cross
                If GetGadgetState(#Spin_Largeur) > #Max_Cross : SetGadgetState(#Spin_Largeur, #Max_Cross) : EndIf
                MaxCrossX = GetGadgetState(#Spin_Largeur)
                
                ; on recreer le tableau
                Generer_Cross()
              
              Case #Spin_Longueur
                ; on verifi que le nombre de cases n'est pas supérieur à #Max_Cross
                If GetGadgetState(#Spin_Longueur) > #Max_Cross : SetGadgetState(#Spin_Longueur, #Max_Cross) : EndIf
                MaxCrossY = GetGadgetState(#Spin_Longueur)
                
                ; on recreer le tableau
                Generer_Cross()
            
            EndSelect
            
          Case #WM_LBUTTONUP ; Si le bouton droit est relacher sur une case, on la change si ce n'est pas -1, -1
            If CrayonCrossX > -1 And CrayonCrossY > -1
              Cross(CrayonCrossX, CrayonCrossY)\Sprite = #Cross
            EndIf
        EndSelect
        
        wEvent = WindowEvent() ; On regarde s'il y a un autre evenement
        
      Until wEvent = #Null ; Sinon on sort
    
    EndIf
    
    ;- Dessin sur l'écran
    ;
    
    ; Affichage du fond
    DisplaySprite(#Fond, 0, 0)
    
    Start3D() ; Surtout appeler Start3D() avant les boucle quand on est sur d'afficher que des sprite3d, ça evite les appels inutiles
      
      ; Affichage du tableau
      For y = 0 To MaxCrossY - 1
        For x = 0 To MaxCrossX - 1
          
          ; affichage des cases
          DisplaySprite3D(Cross(x, y)\Sprite, Cross(x, y)\x, Cross(x, y)\y, 125)
          
        Next
      Next
      
      ; Affichage du crayon s'il est dans l'écran
      If CursorInScreen
        DisplaySprite3D(#Crayon,CrayonX, CrayonY, 220)
      EndIf
    Stop3D()
    
    FlipBuffers()
  
  Until Quit = #True
  
;- Procedures
;
Procedure.b Generer_Cross()
  For y = 0 To MaxCrossY - 1
    For x = 0 To MaxCrossX - 1
    
      Cross(x, y)\Sprite = #Grille
      
      ; on calcul la postion en x/y de la case
      Cross(x, y)\x = 200 + ((x - MaxCrossX / 2) * 12)
      Cross(x, y)\y = 200 + ((y - MaxCrossY / 2) * 12)
    
    Next
  Next
  
EndProcedure
J'ai essayé de commenté les points "délicats" mais si tu as des questions, n'hesites pas  
Et encor une foi, je ne dis pas qu'il faut faire comme ça absolument, je te montre juste comment je ferais