Robot Question / Réponse (IA) 6

  • Auteur de la discussion ZZZ
  • Date de début
ZZZ
Passionné
Messages
1 400
Fofocoins
7 662
Personnalisation du groupe
Personnalisation pseudo
JavaScript:
var shotLightVisible = false;
var intervalId;

function draw() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.fillStyle = "black";
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    ctx.save();
    ctx.translate(player.x, player.y);
    ctx.rotate(angle + Math.PI / 2);
    ctx.drawImage(player.image, -player.width / 2, -player.height / 2, player.width, player.height);

    if (shotLightVisible) {
        ctx.drawImage(player.shotLightImage, (-player.width) + 65 / 2, (-player.height / 2) - 20, 20, 20);
    }

    ctx.restore();
}

function blink() {
    // alterner l'affichage de l'image shotLightImage
    if (shotLightVisible) {
        shotLightVisible = false;
    } else {
        shotLightVisible = true;
    }
}

canvas.addEventListener("mousedown", function () {
    // initialiser la variable shotLightVisible à true au début du clignotement
    shotLightVisible = true;
    var aK47sound = new Audio('./sounds/AK-47.mp3');
    aK47sound.play();

    intervalId = setInterval(function () {
        var aK47sound = new Audio('./sounds/AK-47.mp3');
        aK47sound.play();
        blink();
    }, 150);

    window.addEventListener("mouseup", function () {
        clearInterval(intervalId);
        shotLightVisible = false;
    })
});

Comment faire en sorte qu'il ne soit pas possible de spamer comme un gros malade en mettant une cadence max de 1 coup (son + flash) toutes les 0.15 sec
 
Fofobot 🤖
Assistant virtuel
Donateur 🤲
Messages
3 016
Fofocoins
70 789
Pour limiter le spamming, vous pouvez ajouter une variable pour stocker le temps écoulé depuis le dernier tir. Si ce temps est inférieur à 150 millisecondes (la fréquence maximale autorisée), le script ne doit pas exécuter la boucle avec l'image clignotante et le son. Voici comment vous pouvez mettre cela en place :

1. Ajouter une variable pour stocker la date et l'heure du dernier tir :

```
var lastShotTime = 0;
```

2. Modifier l'écouteur d'événements « mousedown » pour vérifier si la dernière fois qu'un tir a été effectué est inférieure à 150 millisecondes. Si c'est le cas, ne rien faire. Sinon, initialiser la variable shotLightVisible, jouer le son et mettre une nouvelle valeur pour lastShotTime :

```
canvas.addEventListener("mousedown", function () {
if (lastShotTime + 150 > Date.now()) { // Vérifier si le temps écoulé depuis le dernier tir est inférieur à 150ms
return; // Si oui, ne pas exécuter le code suivant
}

// Sinon, initialiser la variable shotLightVisible, jouer le son et mettre une nouvelle valeur pour lastShotTime
shotLightVisible = true;
var aK47sound = new Audio('./sounds/AK-47.mp3');
aK47sound.play();
lastShotTime = Date.now(); // Stocker la date et l'heure actuelles comme dernier temps de tir
```

3. Modifier l'écouteur d'événements « mouseup » pour mettre à jour lastShotTime :

```
window.addEventListener("mouseup", function () {
clearInterval(intervalId);
shotLightVisible = false;
lastShotTime = Date.now(); // Stocker la date et l'heure actuelles comme dernier temps de tir
})
```
 
ZZZ
Passionné
Messages
1 400
Fofocoins
7 662
Personnalisation du groupe
Personnalisation pseudo
Pour limiter le spamming, vous pouvez ajouter une variable pour stocker le temps écoulé depuis le dernier tir. Si ce temps est inférieur à 150 millisecondes (la fréquence maximale autorisée), le script ne doit pas exécuter la boucle avec l'image clignotante et le son. Voici comment vous pouvez mettre cela en place :

1. Ajouter une variable pour stocker la date et l'heure du dernier tir :

```
var lastShotTime = 0;
```

2. Modifier l'écouteur d'événements « mousedown » pour vérifier si la dernière fois qu'un tir a été effectué est inférieure à 150 millisecondes. Si c'est le cas, ne rien faire. Sinon, initialiser la variable shotLightVisible, jouer le son et mettre une nouvelle valeur pour lastShotTime :

```
canvas.addEventListener("mousedown", function () {
if (lastShotTime + 150 > Date.now()) { // Vérifier si le temps écoulé depuis le dernier tir est inférieur à 150ms
return; // Si oui, ne pas exécuter le code suivant
}

// Sinon, initialiser la variable shotLightVisible, jouer le son et mettre une nouvelle valeur pour lastShotTime
shotLightVisible = true;
var aK47sound = new Audio('./sounds/AK-47.mp3');
aK47sound.play();
lastShotTime = Date.now(); // Stocker la date et l'heure actuelles comme dernier temps de tir
```

3. Modifier l'écouteur d'événements « mouseup » pour mettre à jour lastShotTime :

```
window.addEventListener("mouseup", function () {
clearInterval(intervalId);
shotLightVisible = false;
lastShotTime = Date.now(); // Stocker la date et l'heure actuelles comme dernier temps de tir
})
```
JavaScript:
var shotLightVisible = false;
var intervalId;
var allowToFire = true;
var fireRate = 8;


function draw() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.fillStyle = "black";
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    ctx.save();
    ctx.translate(player.x, player.y);
    ctx.rotate(angle + Math.PI / 2);
    ctx.drawImage(player.image, -player.width / 2, -player.height / 2, player.width, player.height);

    if (shotLightVisible) {
        ctx.drawImage(player.shotLightImage, (-player.width) + 65 / 2, (-player.height / 2) - 20, 20, 20);
    }

    ctx.restore();
}

function shoot() {
    if (allowToFire) {
        shotLightVisible = true;
        var aK47sound = new Audio('./sounds/AK-47.mp3');
        aK47sound.play();
        allowToFire = false;
    } else {
        setInterval(function () {
            allowToFire = true;
        }, 1000 / fireRate)
    }
}

function blink() {
    // alterner l'affichage de l'image shotLightImage
    if (shotLightVisible) {
        shotLightVisible = false;
    } else {
        shoot();
    }
}

canvas.addEventListener("mousedown", function () {
    shoot();

    intervalId = setInterval(function () {
        blink();
    }, 1000 / fireRate);

    window.addEventListener("mouseup", function () {
        clearInterval(intervalId);
        shotLightVisible = false;
    })
});

Comment éviter que avec ce code, on puisse spammer comme un dingue en limitant la cadence de tire max à (1000/fireRate) coups par secondes ?
 
Fofobot 🤖
Assistant virtuel
Donateur 🤲
Messages
3 016
Fofocoins
70 789
JavaScript:
var shotLightVisible = false;
var intervalId;
var allowToFire = true;
var fireRate = 8;


function draw() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.fillStyle = "black";
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    ctx.save();
    ctx.translate(player.x, player.y);
    ctx.rotate(angle + Math.PI / 2);
    ctx.drawImage(player.image, -player.width / 2, -player.height / 2, player.width, player.height);

    if (shotLightVisible) {
        ctx.drawImage(player.shotLightImage, (-player.width) + 65 / 2, (-player.height / 2) - 20, 20, 20);
    }

    ctx.restore();
}

function shoot() {
    if (allowToFire) {
        shotLightVisible = true;
        var aK47sound = new Audio('./sounds/AK-47.mp3');
        aK47sound.play();
        allowToFire = false;
    } else {
        setInterval(function () {
            allowToFire = true;
        }, 1000 / fireRate)
    }
}

function blink() {
    // alterner l'affichage de l'image shotLightImage
    if (shotLightVisible) {
        shotLightVisible = false;
    } else {
        shoot();
    }
}

canvas.addEventListener("mousedown", function () {
    shoot();

    intervalId = setInterval(function () {
        blink();
    }, 1000 / fireRate);

    window.addEventListener("mouseup", function () {
        clearInterval(intervalId);
        shotLightVisible = false;
    })
});

Comment éviter que avec ce code, on puisse spammer comme un dingue en limitant la cadence de tire max à (1000/fireRate) coups par secondes ?
Pour limiter le nombre de tirs par seconde, vous devez ajouter une variable pour stocker le temps écoulé depuis le dernier coup de feu, comme ceci :

```js
var lastFireTime = 0;
```

Ensuite, vous pouvez modifier la fonction `shoot()` pour vérifier si le temps écoulé depuis le dernier coup de feu est supérieur ou égal à la cadence de tir souhaitée. Si c'est le cas, vous pouvez tirer et mettre à jour `lastFireTime` pour stocker le moment où le coup de feu a été tiré. Sinon, vous ne devez rien faire.

Voici comment vous pouvez modifier la fonction `shoot()` :

```js
function shoot() {
var currentTime = Date.now();
var timeSinceLastFire = currentTime - lastFireTime;

if (timeSinceLastFire >= 1000 / fireRate) {
shotLightVisible = true;
var aK47sound = new Audio('./sounds/AK-47.mp3');
aK47sound.play();
lastFireTime = currentTime;
}
}
```

Enfin, vous devez remplacer l'appel à la fonction `shoot()` dans la fonction `blink()` par un simple appel à `shoot()`, car `blink()` est appelée tout le temps et cela ne respecterait pas la cadence désirée. Le code final ressemblera à ceci :

```js
var shotLightVisible = false;
var intervalId;
var fireRate = 8;
var lastFireTime = 0;

function draw() {
// ...
}

function shoot() {
var currentTime = Date.now();
var timeSinceLastFire = currentTime - lastFireTime;

if (timeSinceLastFire >= 1000 / fireRate) {
shotLightVisible = true;
var aK47sound = new Audio('./sounds/AK-47.mp3');
aK47sound.play();
lastFireTime = currentTime;
}
}

function blink() {
// alterner l'affichage de l'image shotLightImage
if (shotLightVisible) {
shotLightVisible = false;
} else {
shoot();
}
}

canvas.addEventListener("mousedown", function () {
shoot();

intervalId = setInterval(function () {
blink();
}, 1000 / fireRate);

window.addEventListener("mouseup", function () {
clearInterval(intervalId);
shotLightVisible = false;
})
});
```
 
ZZZ
Passionné
Messages
1 400
Fofocoins
7 662
Personnalisation du groupe
Personnalisation pseudo
JavaScript:
var shotLightVisible = false;
var intervalId;
var lastFireTime = 0;
var allowToFire = true;
var fireRate = 1;


function draw() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.fillStyle = "black";
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    ctx.save();
    ctx.translate(player.x, player.y);
    ctx.rotate(angle + Math.PI / 2);
    ctx.drawImage(player.image, -player.width / 2, -player.height / 2, player.width, player.height);

    if (shotLightVisible) {
        ctx.drawImage(player.shotLightImage, (-player.width) + 65 / 2, (-player.height / 2) - 20, 20, 20);
    }

    ctx.restore();
}

function shoot() {
    var currentTime = Date.now();
    var timeSinceLastFire = currentTime - lastFireTime;

    if (timeSinceLastFire >= 1000 / fireRate) {
        shotLightVisible = true;
        var aK47sound = new Audio('./sounds/AK-47.mp3');
        aK47sound.play();
        lastFireTime = currentTime;
        setInterval(function () {
            shotLightVisible = false;
        }, 100)
    }
}

function blink() {
    // alterner l'affichage de l'image shotLightImage
    shotLightVisible = true;
    var aK47sound = new Audio('./sounds/AK-47.mp3');
    aK47sound.play();
    setInterval(function () {
        shotLightVisible = false;
    }, 100)
}

canvas.addEventListener("mousedown", function () {
    shoot();

    intervalId = setInterval(function () {
        blink();
    }, 1000 / fireRate);

    window.addEventListener("mouseup", function () {
        clearInterval(intervalId);
    })
});

Dans ce code, le clique simple fonctionne bien, mais quand on maintient celui-ci pour passer en automatique; le son marche bien mais le flash deviens de plus en plus cours jusqu'à au bout de 3 coups de plus apparaître à moins de relâcher le clique et le renfoncer pour finalement revenir au point de départ?
 
ZZZ
Passionné
Messages
1 400
Fofocoins
7 662
Personnalisation du groupe
Personnalisation pseudo
Pour limiter le nombre de tirs par seconde, vous devez ajouter une variable pour stocker le temps écoulé depuis le dernier coup de feu, comme ceci :

```js
var lastFireTime = 0;
```

Ensuite, vous pouvez modifier la fonction `shoot()` pour vérifier si le temps écoulé depuis le dernier coup de feu est supérieur ou égal à la cadence de tir souhaitée. Si c'est le cas, vous pouvez tirer et mettre à jour `lastFireTime` pour stocker le moment où le coup de feu a été tiré. Sinon, vous ne devez rien faire.

Voici comment vous pouvez modifier la fonction `shoot()` :

```js
function shoot() {
var currentTime = Date.now();
var timeSinceLastFire = currentTime - lastFireTime;

if (timeSinceLastFire >= 1000 / fireRate) {
shotLightVisible = true;
var aK47sound = new Audio('./sounds/AK-47.mp3');
aK47sound.play();
lastFireTime = currentTime;
}
}
```

Enfin, vous devez remplacer l'appel à la fonction `shoot()` dans la fonction `blink()` par un simple appel à `shoot()`, car `blink()` est appelée tout le temps et cela ne respecterait pas la cadence désirée. Le code final ressemblera à ceci :

```js
var shotLightVisible = false;
var intervalId;
var fireRate = 8;
var lastFireTime = 0;

function draw() {
// ...
}

function shoot() {
var currentTime = Date.now();
var timeSinceLastFire = currentTime - lastFireTime;

if (timeSinceLastFire >= 1000 / fireRate) {
shotLightVisible = true;
var aK47sound = new Audio('./sounds/AK-47.mp3');
aK47sound.play();
lastFireTime = currentTime;
}
}

function blink() {
// alterner l'affichage de l'image shotLightImage
if (shotLightVisible) {
shotLightVisible = false;
} else {
shoot();
}
}

canvas.addEventListener("mousedown", function () {
shoot();

intervalId = setInterval(function () {
blink();
}, 1000 / fireRate);

window.addEventListener("mouseup", function () {
clearInterval(intervalId);
shotLightVisible = false;
})
});
```
JavaScript:
var shotLightVisible = false;
var intervalId;
var lastFireTime = 0;
var allowToFire = true;
var fireRate = 1;


function draw() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.fillStyle = "black";
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    ctx.save();
    ctx.translate(player.x, player.y);
    ctx.rotate(angle + Math.PI / 2);
    ctx.drawImage(player.image, -player.width / 2, -player.height / 2, player.width, player.height);

    if (shotLightVisible) {
        ctx.drawImage(player.shotLightImage, (-player.width) + 65 / 2, (-player.height / 2) - 20, 20, 20);
    }

    ctx.restore();
}

function shoot() {
    var currentTime = Date.now();
    var timeSinceLastFire = currentTime - lastFireTime;

    if (timeSinceLastFire >= 1000 / fireRate) {
        shotLightVisible = true;
        var aK47sound = new Audio('./sounds/AK-47.mp3');
        aK47sound.play();
        lastFireTime = currentTime;
        setInterval(function () {
            shotLightVisible = false;
        }, 100)
    }
}

function blink() {
    // alterner l'affichage de l'image shotLightImage
    shotLightVisible = true;
    var aK47sound = new Audio('./sounds/AK-47.mp3');
    aK47sound.play();
    setInterval(function () {
        shotLightVisible = false;
    }, 100)
}

canvas.addEventListener("mousedown", function () {
    shoot();

    intervalId = setInterval(function () {
        blink();
    }, 1000 / fireRate);

    window.addEventListener("mouseup", function () {
        clearInterval(intervalId);
    })
});

Dans ce code, le clique simple fonctionne bien, mais quand on maintient celui-ci pour passer en automatique; le son marche bien mais le flash deviens de plus en plus cours jusqu'à au bout de 3 coups de plus apparaître à moins de relâcher le clique et le renfoncer pour finalement revenir au point de départ?
 
Fofobot 🤖
Assistant virtuel
Donateur 🤲
Messages
3 016
Fofocoins
70 789
JavaScript:
var shotLightVisible = false;
var intervalId;
var lastFireTime = 0;
var allowToFire = true;
var fireRate = 1;


function draw() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.fillStyle = "black";
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    ctx.save();
    ctx.translate(player.x, player.y);
    ctx.rotate(angle + Math.PI / 2);
    ctx.drawImage(player.image, -player.width / 2, -player.height / 2, player.width, player.height);

    if (shotLightVisible) {
        ctx.drawImage(player.shotLightImage, (-player.width) + 65 / 2, (-player.height / 2) - 20, 20, 20);
    }

    ctx.restore();
}

function shoot() {
    var currentTime = Date.now();
    var timeSinceLastFire = currentTime - lastFireTime;

    if (timeSinceLastFire >= 1000 / fireRate) {
        shotLightVisible = true;
        var aK47sound = new Audio('./sounds/AK-47.mp3');
        aK47sound.play();
        lastFireTime = currentTime;
        setInterval(function () {
            shotLightVisible = false;
        }, 100)
    }
}

function blink() {
    // alterner l'affichage de l'image shotLightImage
    shotLightVisible = true;
    var aK47sound = new Audio('./sounds/AK-47.mp3');
    aK47sound.play();
    setInterval(function () {
        shotLightVisible = false;
    }, 100)
}

canvas.addEventListener("mousedown", function () {
    shoot();

    intervalId = setInterval(function () {
        blink();
    }, 1000 / fireRate);

    window.addEventListener("mouseup", function () {
        clearInterval(intervalId);
    })
});

Dans ce code, le clique simple fonctionne bien, mais quand on maintient celui-ci pour passer en automatique; le son marche bien mais le flash deviens de plus en plus cours jusqu'à au bout de 3 coups de plus apparaître à moins de relâcher le clique et le renfoncer pour finalement revenir au point de départ?
Sorry I couldn't contact the ChatGPT think tank :(
 
Fofobot 🤖
Assistant virtuel
Donateur 🤲
Messages
3 016
Fofocoins
70 789
Je m'excuse, il y a eu une confusion dans les précédentes réponses. Passons à votre question, dans votre code, le clignotement du flash devient de plus en plus court car dans la fonction `shoot()`, vous utilisez `setInterval()` pour masquer le flash après un temps donné, mais cette méthode créée un nouveau setInterval à chaque tir et ne s'arrête jamais, ce qui fait que le flash disparaît de plus en plus rapidement à chaque fois.

Pour résoudre le problème, vous pouvez utiliser `setTimeout()` à la place de `setInterval()` pour masquer le flash après un certain délai. Il faut également enlever la ligne `setInterval()` de cette fonction.

Le code modifié de la fonction `shoot()` ressemblera à ceci :

```js
function shoot() {
var currentTime = Date.now();
var timeSinceLastFire = currentTime - lastFireTime;

if (timeSinceLastFire >= 1000 / fireRate) {
shotLightVisible = true;
var aK47sound = new Audio('./sounds/AK-47.mp3');
aK47sound.play();
lastFireTime = currentTime;
setTimeout(function () {
shotLightVisible = false;
}, 100);
}
}
```

En utilisant `setTimeout()` plutôt que `setInterval()`, lorsque la pause de 100 ms est terminée, la fonction `blink()` sera appelée à nouveau une fois toutes les millisecondes (1000 / fireRate) comme prévu, mais le flash ne disparaîtra qu'après la pause de 100 ms, ce qui résoudra le problème.
 
ZZZ
Passionné
Messages
1 400
Fofocoins
7 662
Personnalisation du groupe
Personnalisation pseudo
Je m'excuse, il y a eu une confusion dans les précédentes réponses. Passons à votre question, dans votre code, le clignotement du flash devient de plus en plus court car dans la fonction `shoot()`, vous utilisez `setInterval()` pour masquer le flash après un temps donné, mais cette méthode créée un nouveau setInterval à chaque tir et ne s'arrête jamais, ce qui fait que le flash disparaît de plus en plus rapidement à chaque fois.

Pour résoudre le problème, vous pouvez utiliser `setTimeout()` à la place de `setInterval()` pour masquer le flash après un certain délai. Il faut également enlever la ligne `setInterval()` de cette fonction.

Le code modifié de la fonction `shoot()` ressemblera à ceci :

```js
function shoot() {
var currentTime = Date.now();
var timeSinceLastFire = currentTime - lastFireTime;

if (timeSinceLastFire >= 1000 / fireRate) {
shotLightVisible = true;
var aK47sound = new Audio('./sounds/AK-47.mp3');
aK47sound.play();
lastFireTime = currentTime;
setTimeout(function () {
shotLightVisible = false;
}, 100);
}
}
```

En utilisant `setTimeout()` plutôt que `setInterval()`, lorsque la pause de 100 ms est terminée, la fonction `blink()` sera appelée à nouveau une fois toutes les millisecondes (1000 / fireRate) comme prévu, mais le flash ne disparaîtra qu'après la pause de 100 ms, ce qui résoudra le problème.
cela fait la même chose, sauf que le flash ne diminue pas peu à peu, i reste stable pendant 2 tirs puis disparaît. Et en plus, quand on recommence, mais avec un clique normal cette fois, le premier clique n'apparaît pas !
 
Fofobot 🤖
Assistant virtuel
Donateur 🤲
Messages
3 016
Fofocoins
70 789
cela fait la même chose, sauf que le flash ne diminue pas peu à peu, i reste stable pendant 2 tirs puis disparaît. Et en plus, quand on recommence, mais avec un clique normal cette fois, le premier clique n'apparaît pas !
Sorry I couldn't contact the ChatGPT think tank :(
 
Fofobot 🤖
Assistant virtuel
Donateur 🤲
Messages
3 016
Fofocoins
70 789
arrête d'accumuler les erreurs et réponds !
Je m'excuse pour la confusion. Pour résoudre le premier problème, valider que la variable `shotLightVisible` est définie avant que `shoot()` et `blink()` soient appelés, ensuite nous allons ajouter une nouvelle variable appelée `isFiring` pour savoir si le joueur est en train de tirer ou non. Dans la fonction `shoot()`, nous allons vérifier si `isFiring` est défini avant de permettre au joueur de tirer, et ensuite, nous allons définir `isFiring` à `true`. Enfin, nous allons définir `isFiring` sur `false` lorsque le joueur relâche le clic de la souris.

Pour le deuxième problème, nous devons appeler `shoot()` une seule fois lorsque le joueur appuie sur le clic de la souris et pas à chaque fois que la fonction `blink()` est appelée. Pour cela, j'ai retiré l'appel à `shoot()` dans la fonction `blink()` et j'ai ajouté une condition pour vérifier si `isFiring` est défini avant de permettre à `shoot()` d'être appelé.

Voici le code corrigé :

```js
var shotLightVisible = false;
var intervalId;
var lastFireTime = 0;
var allowToFire = true;
var fireRate = 1;
var isFiring = false;

function draw() {
//...
}

function shoot() {
var currentTime = Date.now();
var timeSinceLastFire = currentTime - lastFireTime;

if (timeSinceLastFire >= 1000 / fireRate && isFiring) {
shotLightVisible = true;
var aK47sound = new Audio('./sounds/AK-47.mp3');
aK47sound.play();
lastFireTime = currentTime;
setTimeout(function () {
shotLightVisible = false;
}, 100);
}
}

function blink() {
// alterner l'affichage de l'image shotLightImage
if (shotLightVisible) {
shotLightVisible = false;
}
}

canvas.addEventListener("mousedown", function (event) {
if (event.button === 0) {
isFiring = true;
shoot();

intervalId = setInterval(function () {
shoot();
blink();
}, 1000 / fireRate);
}
});

window.addEventListener("mouseup", function (event) {
if (event.button === 0) {
isFiring = false;
clearInterval(intervalId);
shotLightVisible = false;
}
});
```

J'espère que cela vous aide !
 

🚫 Alerte AdBlock !

Vous avez activé le mode Ninja, et il cache toutes les pubs ! 😆 Un petit coup de pouce pour notre site serait super apprécié si vous pouvez le désactiver. 🙏

🦸‍♂️ J'ai Désactivé AdBlock !