Tetris

Répondre
Partager Rechercher
Bestmomo, j'ai voulu regarder ton PDF mais le lien vers celui-ci est mort. ???

Cliquez ce bouton ou survolez le contenu pour afficher le spoiler
Faut dire qu'il pointe vers localhost
Citation :
Publié par Bonnie
Faut dire qu'il pointe vers localhost
C'est pour ça que ça marchait bien chez moi .

Bon c'est réparé maintenant, il est téléchargeable .
J'ai testé ton Tetris au café JOL.

Il fonctionne super bien, pas de lag, très fluide et difficile (Nondidjou)

Par contre, d'accord avec Yongho, le repérage vertical est parfois un peu difficile. Tu pourrais peut-être prévoir un fond légèrement marqué.

Mais bon... expérience super
Red face
Euh faite excuse mais je comprends pas comment il marche , j'ai crée un prim , mis le script , il dit ... tetris: Web Tetris 1.00 ... mais je vois rien du tout , il faut mettre des autres prims ou un seul prim , j'ai tout le topic mais rien ne me dit comment cela marche ...
Pour le premier script du thread, tu mets le script dans une prim .
Il s affichera sur la face numéro 4 .
Si ta prim a moins de faces , change le numéro de face dans le script .

Comme il utilise les médias , tu devras activer tes médias . ( par exemple , en cliquant sur le bouton "plus >>" en haut a droite dans ton viewer près du volume , et en sélectionnant "Javascript Tetris" dans la liste , puis en cliquant sur la loupe avec le + )

Dernière modification par redpurple ; 04/07/2014 à 09h06.
ahh cool merci pour la réouverture de ce thread, je ne savais pas que bestmomo avait sortie ce tetris !

je me suis éclater et maintenant ma femme squatte mon terrain pour jouer

je vais le placer sur Paris pendant quelque temps histoire de s'amuser un peu.

merci a toi bestmomo.
__________________
Paris 1900
http://www.paris1900.net
Talking
Ce soir j'ai réussi à le mettre , merci , il marche super bien ...

Par contre les autres ne voient que le script sur la face 4 , ou ai je fait une erreur ....

Dernière modification par Mitsuki Eclipse ; 13/07/2014 à 01h16.
Essaye avec cette version :

Code PHP:

//----------------------------------------------------------------------------------
//                                 Tetris web V1.0.1
//   modif 1.0.1 : conversion html -> xhtml
//----------------------------------------------------------------------------------
//    Source du Javascript : https://github.com/jakesgordon/javascript-tetris
//----------------------------------------------------------------------------------

//----------------------------------------------
//                  PARAMETRES
//----------------------------------------------
integer FACE 4;
string VERSION "1.01";

//----------------------------------------------
//                  VARIABLES
//----------------------------------------------
string myURL;

//----------------------------------------------
//                  FIN
//----------------------------------------------

browse(integer facestring url) {
    
llClearLinkMedia(LINK_THISface);
    
llSetLinkMedia(LINK_THISface, [
        
PRIM_MEDIA_CONTROLSPRIM_MEDIA_CONTROLS_MINI,
        
PRIM_MEDIA_AUTO_PLAYTRUE,
        
PRIM_MEDIA_AUTO_LOOPTRUE,
        
PRIM_MEDIA_AUTO_SCALETRUE,
        
PRIM_MEDIA_CURRENT_URLurl,
        
PRIM_MEDIA_HOME_URLurl,
        
PRIM_MEDIA_HEIGHT_PIXELS512,
        
PRIM_MEDIA_WIDTH_PIXELS512]);
}

string getPage() {
    return 
"<html xmlns='http://www.w3.org/1999/xhtml'>
<head>
  <title>Javascript Tetris</title>
  <style type='text/css'>
    body { font-family: Helvetica, sans-serif; }
    #tetris { margin: 1em auto; padding: 1em; border: 4px solid black; border-radius: 10px; background-color: #F8F8F8; }
    #canvas { display: inline-block; vertical-align: top; background: url(http://www.scriptol.fr/design/paint/images/nuage-bleu.png); box-shadow: 10px 10px 10px #999; border: 2px solid #333; }
    #menu { display: inline-block; vertical-align: top; position: relative; }
    #menu p { margin: 0.5em 0; text-align: center; }
    #menu p a { text-decoration: none; color: black; }
    #upcoming { display: block; margin: 0 auto; background-color: #E0E0E0; }
    #score { color: red; font-weight: bold; }
    #rows { color: blue; font-weight: bold; }
    @media screen and (min-width: 0px) and (min-height: 0px) { #tetris { font-size: 0.75em; width: 250px; } #menu { width: 100px; height: 200px; } #upcoming { width: 50px; height: 50px; } #canvas { width: 100px; height: 200px; } } /* 10px chunks */
    @media screen and (min-width: 400px) and (min-height: 400px) { #tetris { font-size: 1.00em; width: 350px; } #menu { width: 150px; height: 300px; } #upcoming { width: 75px; height: 75px; } #canvas { width: 150px; height: 300px; } } /* 15px chunks */
    @media screen and (min-width: 500px) and (min-height: 500px) { #tetris { font-size: 1.25em; width: 450px; } #menu { width: 200px; height: 400px; } #upcoming { width: 100px; height: 100px; } #canvas { width: 200px; height: 400px; } } /* 20px chunks */
    @media screen and (min-width: 600px) and (min-height: 600px) { #tetris { font-size: 1.50em; width: 550px; } #menu { width: 250px; height: 500px; } #upcoming { width: 125px; height: 125px; } #canvas { width: 250px; height: 500px; } } /* 25px chunks */
    @media screen and (min-width: 700px) and (min-height: 700px) { #tetris { font-size: 1.75em; width: 650px; } #menu { width: 300px; height: 600px; } #upcoming { width: 150px; height: 150px; } #canvas { width: 300px; height: 600px; } } /* 30px chunks */
    @media screen and (min-width: 800px) and (min-height: 800px) { #tetris { font-size: 2.00em; width: 750px; } #menu { width: 350px; height: 700px; } #upcoming { width: 175px; height: 175px; } #canvas { width: 350px; height: 700px; } } /* 35px chunks */
    @media screen and (min-width: 900px) and (min-height: 900px) { #tetris { font-size: 2.25em; width: 850px; } #menu { width: 400px; height: 800px; } #upcoming { width: 200px; height: 200px; } #canvas { width: 400px; height: 800px; } } /* 40px chunks */
  </style>
</head>

<body>

  <div id='tetris'>
    <div id='menu'>
      <p id='start'><a href='javascript:play();'>Espace pour jouer</a></p>
      <p><canvas id='upcoming'></canvas></p>
      <p>Score <span id='score'>00000</span></p>
      <p>Lignes <span id='rows'>0</span></p>
    </div>
    <canvas id='canvas'>
      Sorry, this example cannot be run because your browser does not support the &lt;canvas&gt; element
    </canvas>
  </div>

<script type='text/javascript'>
<![CDATA[
     //-------------------------------------------------------------------------
    // base helper methods
    //-------------------------------------------------------------------------

    function get(id) { return document.getElementById(id); };
    function hide(id) { get(id).style.visibility = 'hidden'; };
    function show(id) { get(id).style.visibility = null; };
    function html(id, html) { get(id).innerHTML = html; };

    function timestamp() { return new Date().getTime(); };
    function random(min, max) { return (min + (Math.random() * (max - min))); };
    function randomChoice(choices) { return choices[Math.round(random(0, choices.length-1))]; };

    if (!window.requestAnimationFrame) { // http://paulirish.com/2011/requestanimationframe-for-smart-animating/
      window.requestAnimationFrame = window.webkitRequestAnimationFrame ||
                                     window.mozRequestAnimationFrame ||
                                     window.oRequestAnimationFrame ||
                                     window.msRequestAnimationFrame ||
                                     function(callback, element) {
                                       window.setTimeout(callback, 1000 / 60);
                                     }
    }

    //-------------------------------------------------------------------------
    // game constants
    //-------------------------------------------------------------------------

    var KEY = { ESC: 27, SPACE: 32, LEFT: 37, UP: 38, RIGHT: 39, DOWN: 40 },
        DIR = { UP: 0, RIGHT: 1, DOWN: 2, LEFT: 3, MIN: 0, MAX: 3 },
        canvas = get('canvas'),
        ctx = canvas.getContext('2d'),
        ucanvas = get('upcoming'),
        uctx = ucanvas.getContext('2d'),
        speed = { start: 0.6, decrement: 0.005, min: 0.1 }, // how long before piece drops by 1 row (seconds)
        nx = 10, // width of tetris court (in blocks)
        ny = 20, // height of tetris court (in blocks)
        nu = 5; // width/height of upcoming preview (in blocks)

    //-------------------------------------------------------------------------
    // game variables (initialized during reset)
    //-------------------------------------------------------------------------

    var dx, dy, // pixel size of a single tetris block
        blocks, // 2 dimensional array (nx*ny) representing tetris court - either empty block or occupied by a 'piece'
        actions, // queue of user actions (inputs)
        playing, // true|false - game is in progress
        dt, // time since starting this game
        current, // the current piece
        next, // the next piece
        score, // the current score
        vscore, // the currently displayed score (it catches up to score in small chunks - like a spinning slot machine)
        rows, // number of completed rows in the current game
        step; // how long before current piece drops by 1 row

    //-------------------------------------------------------------------------
    // tetris pieces
    //
    // blocks: each element represents a rotation of the piece (0, 90, 180, 270)
    // each element is a 16 bit integer where the 16 bits represent
    // a 4x4 set of blocks, e.g. j.blocks[0] = 0x44C0
    //
    // 0100 = 0x4 << 3 = 0x4000
    // 0100 = 0x4 << 2 = 0x0400
    // 1100 = 0xC << 1 = 0x00C0
    // 0000 = 0x0 << 0 = 0x0000
    // ------
    // 0x44C0
    //
    //-------------------------------------------------------------------------

    var i = { id: 'i', size: 4, blocks: [0x0F00, 0x2222, 0x00F0, 0x4444], color: 'cyan' };
    var j = { id: 'j', size: 3, blocks: [0x44C0, 0x8E00, 0x6440, 0x0E20], color: 'blue' };
    var l = { id: 'l', size: 3, blocks: [0x4460, 0x0E80, 0xC440, 0x2E00], color: 'orange' };
    var o = { id: 'o', size: 2, blocks: [0xCC00, 0xCC00, 0xCC00, 0xCC00], color: 'yellow' };
    var s = { id: 's', size: 3, blocks: [0x06C0, 0x8C40, 0x6C00, 0x4620], color: 'green' };
    var t = { id: 't', size: 3, blocks: [0x0E40, 0x4C40, 0x4E00, 0x4640], color: 'purple' };
    var z = { id: 'z', size: 3, blocks: [0x0C60, 0x4C80, 0xC600, 0x2640], color: 'red' };

    //------------------------------------------------
    // do the bit manipulation and iterate through each
    // occupied block (x,y) for a given piece
    //------------------------------------------------
    function eachblock(type, x, y, dir, fn) {
      var bit, result, row = 0, col = 0, blocks = type.blocks[dir];
      for(bit = 0x8000 ; bit > 0 ; bit = bit >> 1) {
        if (blocks & bit) {
          fn(x + col, y + row);
        }
        if (++col === 4) {
          col = 0;
          ++row;
        }
      }
    };

    //-----------------------------------------------------
    // check if a piece can fit into a position in the grid
    //-----------------------------------------------------
    function occupied(type, x, y, dir) {
      var result = false
      eachblock(type, x, y, dir, function(x, y) {
        if ((x < 0) || (x >= nx) || (y < 0) || (y >= ny) || getBlock(x,y))
          result = true;
      });
      return result;
    };

    function unoccupied(type, x, y, dir) {
      return !occupied(type, x, y, dir);
    };

    //-----------------------------------------
    // start with 4 instances of each piece and
    // pick randomly until the 'bag is empty'
    //-----------------------------------------
    var pieces = [];
    function randomPiece() {
      if (pieces.length == 0)
        pieces = [i,i,i,i,j,j,j,j,l,l,l,l,o,o,o,o,s,s,s,s,t,t,t,t,z,z,z,z];
      var type = pieces.splice(random(0, pieces.length-1), 1)[0];
      return { type: type, dir: DIR.UP, x: Math.round(random(0, nx - type.size)), y: 0 };
    };


    //-------------------------------------------------------------------------
    // GAME LOOP
    //-------------------------------------------------------------------------

    function run() {

      addEvents(); // attach keydown and resize events

      var last = now = timestamp();
      function frame() {
        now = timestamp();
        update(Math.min(1, (now - last) / 1000.0)); // using requestAnimationFrame have to be able to handle large delta's caused when it 'hibernates' in a background or non-visible tab
        draw();
        last = now;
        requestAnimationFrame(frame, canvas);
      }

      resize(); // setup all our sizing information
      reset(); // reset the per-game variables
      frame(); // start the first frame

    };

    function addEvents() {
      document.addEventListener('keydown', keydown, false);
      window.addEventListener('resize', resize, false);
    };

    function resize(event) {
      canvas.width = canvas.clientWidth; // set canvas logical size equal to its physical size
      canvas.height = canvas.clientHeight; // (ditto)
      ucanvas.width = ucanvas.clientWidth;
      ucanvas.height = ucanvas.clientHeight;
      dx = canvas.width / nx; // pixel size of a single tetris block
      dy = canvas.height / ny; // (ditto)
      invalidate();
      invalidateNext();
    };

    function keydown(ev) {
      var handled = false;
      if (playing) {
        switch(ev.keyCode) {
          case KEY.LEFT: actions.push(DIR.LEFT); handled = true; break;
          case KEY.RIGHT: actions.push(DIR.RIGHT); handled = true; break;
          case KEY.UP: actions.push(DIR.UP); handled = true; break;
          case KEY.DOWN: actions.push(DIR.DOWN); handled = true; break;
          case KEY.ESC: lose(); handled = true; break;
        }
      }
      else if (ev.keyCode == KEY.SPACE) {
        play();
        handled = true;
      }
      if (handled)
        ev.preventDefault(); // prevent arrow keys from scrolling the page (supported in IE9+ and all other browsers)
    };

    //-------------------------------------------------------------------------
    // GAME LOGIC
    //-------------------------------------------------------------------------

    function play() { hide('start'); reset(); playing = true; };
    function lose() { show('start'); setVisualScore(); playing = false; };

    function setVisualScore(n) { vscore = n || score; invalidateScore(); };
    function setScore(n) { score = n; setVisualScore(n); };
    function addScore(n) { score = score + n; };
    function clearScore() { setScore(0); };
    function clearRows() { setRows(0); };
    function setRows(n) { rows = n; step = Math.max(speed.min, speed.start - (speed.decrement*rows)); invalidateRows(); };
    function addRows(n) { setRows(rows + n); };
    function getBlock(x,y) { return (blocks && blocks[x] ? blocks[x][y] : null); };
    function setBlock(x,y,type) { blocks[x] = blocks[x] || []; blocks[x][y] = type; invalidate(); };
    function clearBlocks() { blocks = []; invalidate(); }
    function clearActions() { actions = []; };
    function setCurrentPiece(piece) { current = piece || randomPiece(); invalidate(); };
    function setNextPiece(piece) { next = piece || randomPiece(); invalidateNext(); };

    function reset() {
      dt = 0;
      clearActions();
      clearBlocks();
      clearRows();
      clearScore();
      setCurrentPiece(next);
      setNextPiece();
    };

    function update(idt) {
      if (playing) {
        if (vscore < score)
          setVisualScore(vscore + 1);
        handle(actions.shift());
        dt = dt + idt;
        if (dt > step) {
          dt = dt - step;
          drop();
        }
      }
    };

    function handle(action) {
      switch(action) {
        case DIR.LEFT: move(DIR.LEFT); break;
        case DIR.RIGHT: move(DIR.RIGHT); break;
        case DIR.UP: rotate(); break;
        case DIR.DOWN: drop(); break;
      }
    };

    function move(dir) {
      var x = current.x, y = current.y;
      switch(dir) {
        case DIR.RIGHT: x = x + 1; break;
        case DIR.LEFT: x = x - 1; break;
        case DIR.DOWN: y = y + 1; break;
      }
      if (unoccupied(current.type, x, y, current.dir)) {
        current.x = x;
        current.y = y;
        invalidate();
        return true;
      }
      else {
        return false;
      }
    };

    function rotate(dir) {
      var newdir = (current.dir == DIR.MAX ? DIR.MIN : current.dir + 1);
      if (unoccupied(current.type, current.x, current.y, newdir)) {
        current.dir = newdir;
        invalidate();
      }
    };

    function drop() {
      if (!move(DIR.DOWN)) {
        addScore(10);
        dropPiece();
        removeLines();
        setCurrentPiece(next);
        setNextPiece(randomPiece());
        clearActions();
        if (occupied(current.type, current.x, current.y, current.dir)) {
          lose();
        }
      }
    };

    function dropPiece() {
      eachblock(current.type, current.x, current.y, current.dir, function(x, y) {
        setBlock(x, y, current.type);
      });
    };

    function removeLines() {
      var x, y, complete, n = 0;
      for(y = ny ; y > 0 ; --y) {
        complete = true;
        for(x = 0 ; x < nx ; ++x) {
          if (!getBlock(x, y))
            complete = false;
        }
        if (complete) {
          removeLine(y);
          y = y + 1; // recheck same line
          n++;
        }
      }
      if (n > 0) {
        addRows(n);
        addScore(100*Math.pow(2,n-1)); // 1: 100, 2: 200, 3: 400, 4: 800
      }
    };

    function removeLine(n) {
      var x, y;
      for(y = n ; y >= 0 ; --y) {
        for(x = 0 ; x < nx ; ++x)
          setBlock(x, y, (y == 0) ? null : getBlock(x, y-1));
      }
    };

    //-------------------------------------------------------------------------
    // RENDERING
    //-------------------------------------------------------------------------

    var invalid = {};

    function invalidate() { invalid.court = true; }
    function invalidateNext() { invalid.next = true; }
    function invalidateScore() { invalid.score = true; }
    function invalidateRows() { invalid.rows = true; }

    function draw() {
      ctx.save();
      ctx.lineWidth = 1;
      ctx.translate(0.5, 0.5); // for crisp 1px black lines
      drawCourt();
      drawNext();
      drawScore();
      drawRows();
      ctx.restore();
    };

    function drawCourt() {
      if (invalid.court) {
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        if (playing)
          drawPiece(ctx, current.type, current.x, current.y, current.dir);
        var x, y, block;
        for(y = 0 ; y < ny ; y++) {
          for (x = 0 ; x < nx ; x++) {
            if (block = getBlock(x,y))
              drawBlock(ctx, x, y, block.color);
          }
        }
        ctx.strokeRect(0, 0, nx*dx - 1, ny*dy - 1); // court boundary
        invalid.court = false;
      }
    };

    function drawNext() {
      if (invalid.next) {
        var padding = (nu - next.type.size) / 2; // half-arsed attempt at centering next piece display
        uctx.save();
        uctx.translate(0.5, 0.5);
        uctx.clearRect(0, 0, nu*dx, nu*dy);
        drawPiece(uctx, next.type, padding, padding, next.dir);
        uctx.strokeStyle = 'black';
        uctx.strokeRect(0, 0, nu*dx - 1, nu*dy - 1);
        uctx.restore();
        invalid.next = false;
      }
    };

    function drawScore() {
      if (invalid.score) {
        html('score', ('00000' + Math.floor(vscore)).slice(-5));
        invalid.score = false;
      }
    };

    function drawRows() {
      if (invalid.rows) {
        html('rows', rows);
        invalid.rows = false;
      }
    };

    function drawPiece(ctx, type, x, y, dir) {
      eachblock(type, x, y, dir, function(x, y) {
        drawBlock(ctx, x, y, type.color);
      });
    };

    function drawBlock(ctx, x, y, color) {
      ctx.fillStyle = color;
      ctx.fillRect(x*dx, y*dy, dx, dy);
      ctx.strokeRect(x*dx, y*dy, dx, dy)
    };

    //-------------------------------------------------------------------------
    // FINALLY, lets run the game
    //-------------------------------------------------------------------------

    run();
]]>
  </script>

</body>
</html>
"
;
}
 
default
{
    
changed(integer change) {
        if (
change & (CHANGED_REGION_START CHANGED_REGION CHANGED_TELEPORT))
            
llResetScript();
    }

    
state_entry() {
        
llOwnerSay("Web Tetris " VERSION);
        
llRequestURL();
    }

    
on_rez(integer start_param) {
        
llResetScript();
    }

    
http_request(key idstring methodstring body) {
        if (
method == URL_REQUEST_GRANTED) {
            
myURL body;
            
browse(FACEbody);
        }
        else if (
method == "GET") {
            
string path_info llGetHTTPHeader(id"x-path-info");
            
// Appel url de base
            
if (path_info == "") {
                
// Réponse
                
llSetContentType(idCONTENT_TYPE_XHTML);
                
llHTTPResponse(id200getPage());
            }
        }
    }


Dernière modification par redpurple ; 13/07/2014 à 02h35.
Bonjour,

Et désolée de relancer ce vieux sujet mais le créateur a-t-il fini par y arriver ??

Ce serait sympa de pouvoir y jouer tout en écoutant le DJ du soir.

Bixxx

Grace
Ah oui c'est un vieux sujet ça
Citation :
Publié par Worstbobo
Ça fera une 2e vente.

OK, je sors.


Du coup je suis allé voir ma page vendeur que je n'avais pas ouvert depuis longtemps et pour ce tetris je trouve :


  • consultations : 759
  • achat démo : 54
  • achat tetris : 37
Franchement je n'en attendais pas autant et le rapport démo/achat est intéressant . Mais il faut dire que je n'ai aucun concurrent parce qu'il faut quand même un gros brin de folie pour faire un truc pareil...



Worst a déjà sorti sa calculette .
Citation :
Publié par bestmomo


  • consultations : 759
  • achat démo : 54
  • achat tetris : 37

mais bon, la moyenne des notes pour la démo est moins brillante: 1 étoile, que s'est-il passé


Citation :
easy to cheat all you have to do is rotate the peace and it stops dropping so big flaw in this game

Dernière modification par Worstbobo ; 13/01/2018 à 19h00.
Citation :
easy to cheat all you have to do is rotate the peace and it stops dropping so big flaw in this game
Encore un qui a tout compris, avec toutes les pièces forcément non liées il voudrait qu'elles suivent quand il déplace le jeu en cours de partie. On voit qu'il a même pas scripté une ligne dans sa vie lui
Citation :
Publié par bestmomo
Encore un qui a tout compris, avec toutes les pièces forcément non liées il voudrait qu'elles suivent quand il déplace le jeu en cours de partie. On voit qu'il a même pas scripté une ligne dans sa vie lui
Moi, de ce qu'il reproche, je ne comprends pas ça: je comprends qu'on peut arrêter les pièces qui tombent pour les positionner comme on le souhaite et donc tricher. Après, je n'ai pas testé le jeu... Et personne n'oblige personne à tricher...
Citation :
Publié par Worstbobo
Moi, de ce qu'il reproche, je ne comprends pas ça: je comprends qu'on peut arrêter les pièces qui tombent pour les positionner comme on le souhaite et donc tricher. Après, je n'ai pas testé le jeu... Et personne n'oblige personne à tricher...
Ah oui j'avais pas compris ça, c'est encore pire .

C'est clair qu'on peut pas empêcher le proprio d'un objet de le bouger... Enfin si on peut mais bon... Comme tu dis si on a envie de tricher...

Pour mémoire j'ai écrit un article dans lequel on peut télécharger un PDF qui explique complètement le projet. Il est donc possible de se créer un Tetris sans avoir besoin de l'acheter.

Dernière modification par bestmomo ; 15/01/2018 à 22h22.
Citation :
Publié par bestmomo
Ah oui j'avais pas compris ça, c'est encore pire .

C'est clair qu'on peut pas empêcher le proprio d'un objet de le bouger... Enfin si on peut mais bon... Comme tu dis si on a envie de tricher...

Pour mémoire j'ai écrit un article dans lequel on peut télécharger un PDF qui explique complètement le projet. Il est donc possible de se créer un Tetris sans avoir besoin de l'acheter.
C'était un super projet en tout cas.

Du coup, je ne comprends pas comment il bloque les pièces qui tombent, puisqu'il y a une vitre.

Je ne suis hélas pas suffisamment fan de Tetris - jeu qui m'a toujours ennuyé au bout de 30 secondes - pour vouloir expérimenter ton tuto ni même acheter l'objet tout fait ou la démo. Ce n'est pas toi mais Tetris qui me bloque.

Bon, c'est quoi ton prochain projet dans SL?
Citation :
Publié par Worstbobo
Bon, c'est quoi ton prochain projet dans SL?
Je n'ai plus trop d'envie de ce genre depuis quelques temps mais ça reviendra peut-être...
Répondre

Connectés sur ce fil

 
1 connecté (0 membre et 1 invité) Afficher la liste détaillée des connectés