mirror of
https://github.com/MartinKral/Slash-The-Hordes
synced 2024-12-26 03:38:58 +00:00
enemy projectile
This commit is contained in:
parent
9158085b58
commit
b8c40c4053
@ -135,6 +135,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"enemyManager": {
|
"enemyManager": {
|
||||||
|
"projectileLauncher1": {
|
||||||
|
"enemyIds": [
|
||||||
|
"BasicEnemy"
|
||||||
|
],
|
||||||
|
"projectileLifetime": 10,
|
||||||
|
"projectileSpeed": 150,
|
||||||
|
"projectileDamage": 1,
|
||||||
|
"cooldown": 10
|
||||||
|
},
|
||||||
"enemies": [
|
"enemies": [
|
||||||
{
|
{
|
||||||
"id": "BasicEnemy",
|
"id": "BasicEnemy",
|
||||||
|
197
assets/Media/Prefabs/Game/Projectiles/EnemyProjectile.prefab
Normal file
197
assets/Media/Prefabs/Game/Projectiles/EnemyProjectile.prefab
Normal file
@ -0,0 +1,197 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"__type__": "cc.Prefab",
|
||||||
|
"_name": "EnemyProjectile",
|
||||||
|
"_objFlags": 0,
|
||||||
|
"_native": "",
|
||||||
|
"data": {
|
||||||
|
"__id__": 1
|
||||||
|
},
|
||||||
|
"optimizationPolicy": 0,
|
||||||
|
"persistent": false,
|
||||||
|
"asyncLoadAssets": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.Node",
|
||||||
|
"_name": "EnemyProjectile",
|
||||||
|
"_objFlags": 0,
|
||||||
|
"__editorExtras__": {},
|
||||||
|
"_parent": null,
|
||||||
|
"_children": [],
|
||||||
|
"_active": true,
|
||||||
|
"_components": [
|
||||||
|
{
|
||||||
|
"__id__": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__id__": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__id__": 6
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__id__": 8
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"_prefab": {
|
||||||
|
"__id__": 10
|
||||||
|
},
|
||||||
|
"_lpos": {
|
||||||
|
"__type__": "cc.Vec3",
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"_lrot": {
|
||||||
|
"__type__": "cc.Quat",
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"z": 0,
|
||||||
|
"w": 1
|
||||||
|
},
|
||||||
|
"_lscale": {
|
||||||
|
"__type__": "cc.Vec3",
|
||||||
|
"x": 2,
|
||||||
|
"y": 2,
|
||||||
|
"z": 1
|
||||||
|
},
|
||||||
|
"_layer": 33554432,
|
||||||
|
"_euler": {
|
||||||
|
"__type__": "cc.Vec3",
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"_id": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.UITransform",
|
||||||
|
"_name": "",
|
||||||
|
"_objFlags": 0,
|
||||||
|
"node": {
|
||||||
|
"__id__": 1
|
||||||
|
},
|
||||||
|
"_enabled": true,
|
||||||
|
"__prefab": {
|
||||||
|
"__id__": 3
|
||||||
|
},
|
||||||
|
"_contentSize": {
|
||||||
|
"__type__": "cc.Size",
|
||||||
|
"width": 26,
|
||||||
|
"height": 8
|
||||||
|
},
|
||||||
|
"_anchorPoint": {
|
||||||
|
"__type__": "cc.Vec2",
|
||||||
|
"x": 0.5,
|
||||||
|
"y": 0.5
|
||||||
|
},
|
||||||
|
"_id": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.CompPrefabInfo",
|
||||||
|
"fileId": "baF+RbIRdMqqYdGWVAqM48"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.Sprite",
|
||||||
|
"_name": "",
|
||||||
|
"_objFlags": 0,
|
||||||
|
"node": {
|
||||||
|
"__id__": 1
|
||||||
|
},
|
||||||
|
"_enabled": true,
|
||||||
|
"__prefab": {
|
||||||
|
"__id__": 5
|
||||||
|
},
|
||||||
|
"_customMaterial": null,
|
||||||
|
"_srcBlendFactor": 2,
|
||||||
|
"_dstBlendFactor": 4,
|
||||||
|
"_color": {
|
||||||
|
"__type__": "cc.Color",
|
||||||
|
"r": 255,
|
||||||
|
"g": 0,
|
||||||
|
"b": 0,
|
||||||
|
"a": 255
|
||||||
|
},
|
||||||
|
"_spriteFrame": {
|
||||||
|
"__uuid__": "6826a961-a189-448f-adf7-d3795b2439b2@f9941",
|
||||||
|
"__expectedType__": "cc.SpriteFrame"
|
||||||
|
},
|
||||||
|
"_type": 0,
|
||||||
|
"_fillType": 0,
|
||||||
|
"_sizeMode": 1,
|
||||||
|
"_fillCenter": {
|
||||||
|
"__type__": "cc.Vec2",
|
||||||
|
"x": 0,
|
||||||
|
"y": 0
|
||||||
|
},
|
||||||
|
"_fillStart": 0,
|
||||||
|
"_fillRange": 0,
|
||||||
|
"_isTrimmedMode": true,
|
||||||
|
"_useGrayscale": false,
|
||||||
|
"_atlas": null,
|
||||||
|
"_id": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.CompPrefabInfo",
|
||||||
|
"fileId": "46qOXlbU5GmbOpfjiX4jGV"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.CircleCollider2D",
|
||||||
|
"_name": "",
|
||||||
|
"_objFlags": 0,
|
||||||
|
"node": {
|
||||||
|
"__id__": 1
|
||||||
|
},
|
||||||
|
"_enabled": true,
|
||||||
|
"__prefab": {
|
||||||
|
"__id__": 7
|
||||||
|
},
|
||||||
|
"tag": 0,
|
||||||
|
"_group": 64,
|
||||||
|
"_density": 1,
|
||||||
|
"_sensor": false,
|
||||||
|
"_friction": 0.2,
|
||||||
|
"_restitution": 0,
|
||||||
|
"_offset": {
|
||||||
|
"__type__": "cc.Vec2",
|
||||||
|
"x": 0,
|
||||||
|
"y": 0
|
||||||
|
},
|
||||||
|
"_radius": 13,
|
||||||
|
"_id": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.CompPrefabInfo",
|
||||||
|
"fileId": "7cR5oa68RG/oqkiwJ9HQ3X"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__type__": "6a24eYAhmtMDZo5Wb8iLC5Q",
|
||||||
|
"_name": "",
|
||||||
|
"_objFlags": 0,
|
||||||
|
"node": {
|
||||||
|
"__id__": 1
|
||||||
|
},
|
||||||
|
"_enabled": true,
|
||||||
|
"__prefab": {
|
||||||
|
"__id__": 9
|
||||||
|
},
|
||||||
|
"collider": {
|
||||||
|
"__id__": 6
|
||||||
|
},
|
||||||
|
"_id": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.CompPrefabInfo",
|
||||||
|
"fileId": "a81ki8NjhA4KniWAiobzy2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.PrefabInfo",
|
||||||
|
"root": {
|
||||||
|
"__id__": 1
|
||||||
|
},
|
||||||
|
"asset": {
|
||||||
|
"__id__": 0
|
||||||
|
},
|
||||||
|
"fileId": "26opAI9A5IGabbGPZh6QDI"
|
||||||
|
}
|
||||||
|
]
|
@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"ver": "1.1.40",
|
||||||
|
"importer": "prefab",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "01948a38-ee6f-4cd8-8a55-9b518e72c5f3",
|
||||||
|
"files": [
|
||||||
|
".json"
|
||||||
|
],
|
||||||
|
"subMetas": {},
|
||||||
|
"userData": {
|
||||||
|
"syncNodeName": "EnemyProjectile"
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
@ -7,6 +7,7 @@ import { Gold } from "../Items/Gold/Gold";
|
|||||||
import { HealthPotion } from "../Items/HealthPotion/HealthPotion";
|
import { HealthPotion } from "../Items/HealthPotion/HealthPotion";
|
||||||
import { ItemManager } from "../Items/ItemManager";
|
import { ItemManager } from "../Items/ItemManager";
|
||||||
import { XP } from "../Items/XP/XP";
|
import { XP } from "../Items/XP/XP";
|
||||||
|
import { Projectile } from "../Projectile/Projectile";
|
||||||
import { Enemy } from "../Unit/Enemy/Enemy";
|
import { Enemy } from "../Unit/Enemy/Enemy";
|
||||||
import { Player } from "../Unit/Player/Player";
|
import { Player } from "../Unit/Player/Player";
|
||||||
|
|
||||||
@ -27,6 +28,7 @@ export class PlayerCollisionSystem {
|
|||||||
this.collisionTimer = new GameTimer(collisionDelay);
|
this.collisionTimer = new GameTimer(collisionDelay);
|
||||||
|
|
||||||
this.groupToResolver.set(GroupType.ENEMY, this.resolveEnemyContact.bind(this));
|
this.groupToResolver.set(GroupType.ENEMY, this.resolveEnemyContact.bind(this));
|
||||||
|
this.groupToResolver.set(GroupType.ENEMY_PROJECTILE, this.resolveEnemyProjectileContact.bind(this));
|
||||||
this.groupToResolver.set(GroupType.XP, this.resolveXpContact.bind(this));
|
this.groupToResolver.set(GroupType.XP, this.resolveXpContact.bind(this));
|
||||||
this.groupToResolver.set(GroupType.GOLD, this.resolveGoldContact.bind(this));
|
this.groupToResolver.set(GroupType.GOLD, this.resolveGoldContact.bind(this));
|
||||||
this.groupToResolver.set(GroupType.HEALTH_POTION, this.resolveHealthPotionContact.bind(this));
|
this.groupToResolver.set(GroupType.HEALTH_POTION, this.resolveHealthPotionContact.bind(this));
|
||||||
@ -75,6 +77,15 @@ export class PlayerCollisionSystem {
|
|||||||
this.player.Health.damage(damage);
|
this.player.Health.damage(damage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private resolveEnemyProjectileContact(enemyCollider: Collider2D): void {
|
||||||
|
const projectile = enemyCollider.node.getComponent(Projectile);
|
||||||
|
const damage: number = projectile.Damage;
|
||||||
|
projectile.pierce();
|
||||||
|
console.log("Collided with enemy projectile: Damage: " + damage);
|
||||||
|
|
||||||
|
this.player.Health.damage(damage);
|
||||||
|
}
|
||||||
|
|
||||||
private resolveXpContact(xpCollider: Collider2D): void {
|
private resolveXpContact(xpCollider: Collider2D): void {
|
||||||
console.log("Collided with XP");
|
console.log("Collided with XP");
|
||||||
this.itemManager.pickupXP(xpCollider.node.getComponent(XP));
|
this.itemManager.pickupXP(xpCollider.node.getComponent(XP));
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import { EnemyProjectileLauncher } from "../Unit/Enemy/ProjectileLauncher.cs/EnemyProjectileLauncher";
|
||||||
|
|
||||||
export class GameSettings {
|
export class GameSettings {
|
||||||
public player: PlayerSettings = new PlayerSettings();
|
public player: PlayerSettings = new PlayerSettings();
|
||||||
public upgrades: UpgradeSettings = new UpgradeSettings();
|
public upgrades: UpgradeSettings = new UpgradeSettings();
|
||||||
@ -34,6 +36,14 @@ export class HaloLauncherSettings {
|
|||||||
public launcher = new ProjectileLauncherSettings();
|
public launcher = new ProjectileLauncherSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class EnemyLauncherSettings {
|
||||||
|
public enemyIds: string[] = [];
|
||||||
|
public projectileLifetime = 0;
|
||||||
|
public projectileSpeed = 0;
|
||||||
|
public projectileDamage = 0;
|
||||||
|
public cooldown = 0;
|
||||||
|
}
|
||||||
|
|
||||||
export class ProjectileLauncherSettings {
|
export class ProjectileLauncherSettings {
|
||||||
public projectileLifetime = 0;
|
public projectileLifetime = 0;
|
||||||
public projectileSpeed = 0;
|
public projectileSpeed = 0;
|
||||||
@ -66,6 +76,7 @@ export class MetaUpgradeSettings {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class EnemyManagerSettings {
|
export class EnemyManagerSettings {
|
||||||
|
public projectileLauncher1 = new EnemyLauncherSettings();
|
||||||
public enemies: EnemySettings[] = [new EnemySettings()];
|
public enemies: EnemySettings[] = [new EnemySettings()];
|
||||||
public periodicFollowMovers: PeriodicFollowMoverSettings[] = [new PeriodicFollowMoverSettings()];
|
public periodicFollowMovers: PeriodicFollowMoverSettings[] = [new PeriodicFollowMoverSettings()];
|
||||||
public individualEnemySpawners: IndividualEnemySpawnerSettings[] = [new IndividualEnemySpawnerSettings()];
|
public individualEnemySpawners: IndividualEnemySpawnerSettings[] = [new IndividualEnemySpawnerSettings()];
|
||||||
|
@ -26,6 +26,7 @@ import { ProjectileData } from "./Unit/Player/ProjectileLauncher/ProjectileData"
|
|||||||
import { WaveProjectileLauncher } from "./Unit/Player/ProjectileLauncher/WaveProjectileLauncher";
|
import { WaveProjectileLauncher } from "./Unit/Player/ProjectileLauncher/WaveProjectileLauncher";
|
||||||
import { Upgrader } from "./Upgrades/Upgrader";
|
import { Upgrader } from "./Upgrades/Upgrader";
|
||||||
import { MetaUpgradeType } from "./Upgrades/UpgradeType";
|
import { MetaUpgradeType } from "./Upgrades/UpgradeType";
|
||||||
|
import { EnemyProjectileLauncher } from "./Unit/Enemy/ProjectileLauncher.cs/EnemyProjectileLauncher";
|
||||||
|
|
||||||
const { ccclass, property } = _decorator;
|
const { ccclass, property } = _decorator;
|
||||||
|
|
||||||
@ -36,6 +37,7 @@ export class Game extends Component {
|
|||||||
@property(ProjectileLauncher) private haloProjectileLauncherComponent: ProjectileLauncher;
|
@property(ProjectileLauncher) private haloProjectileLauncherComponent: ProjectileLauncher;
|
||||||
@property(ProjectileLauncher) private horizontalProjectileLauncherComponent: ProjectileLauncher;
|
@property(ProjectileLauncher) private horizontalProjectileLauncherComponent: ProjectileLauncher;
|
||||||
@property(ProjectileLauncher) private diagonalProjectileLauncherComponent: ProjectileLauncher;
|
@property(ProjectileLauncher) private diagonalProjectileLauncherComponent: ProjectileLauncher;
|
||||||
|
@property(ProjectileLauncher) private enemyProjectileLauncherComponent: ProjectileLauncher;
|
||||||
@property(EnemyManager) private enemyManager: EnemyManager;
|
@property(EnemyManager) private enemyManager: EnemyManager;
|
||||||
@property(ItemManager) private itemManager: ItemManager;
|
@property(ItemManager) private itemManager: ItemManager;
|
||||||
@property(Camera) private camera: Camera;
|
@property(Camera) private camera: Camera;
|
||||||
@ -49,6 +51,8 @@ export class Game extends Component {
|
|||||||
private horizontalProjectileLauncher: WaveProjectileLauncher;
|
private horizontalProjectileLauncher: WaveProjectileLauncher;
|
||||||
private diagonalProjectileLauncher: WaveProjectileLauncher;
|
private diagonalProjectileLauncher: WaveProjectileLauncher;
|
||||||
|
|
||||||
|
private enemyProjectileLauncher: EnemyProjectileLauncher;
|
||||||
|
|
||||||
private gamePauser: Pauser = new Pauser();
|
private gamePauser: Pauser = new Pauser();
|
||||||
|
|
||||||
private static instance: Game;
|
private static instance: Game;
|
||||||
@ -112,6 +116,13 @@ export class Game extends Component {
|
|||||||
projectileData
|
projectileData
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this.enemyProjectileLauncher = new EnemyProjectileLauncher(
|
||||||
|
this.enemyProjectileLauncherComponent,
|
||||||
|
this.player.node,
|
||||||
|
this.enemyManager,
|
||||||
|
settings.enemyManager.projectileLauncher1
|
||||||
|
);
|
||||||
|
|
||||||
new PlayerProjectileCollisionSystem([this.haloProjectileLauncher, this.horizontalProjectileLauncher, this.diagonalProjectileLauncher]);
|
new PlayerProjectileCollisionSystem([this.haloProjectileLauncher, this.horizontalProjectileLauncher, this.diagonalProjectileLauncher]);
|
||||||
|
|
||||||
const upgrader = new Upgrader(
|
const upgrader = new Upgrader(
|
||||||
@ -150,6 +161,7 @@ export class Game extends Component {
|
|||||||
this.haloProjectileLauncher.gameTick(deltaTime);
|
this.haloProjectileLauncher.gameTick(deltaTime);
|
||||||
this.horizontalProjectileLauncher.gameTick(deltaTime);
|
this.horizontalProjectileLauncher.gameTick(deltaTime);
|
||||||
this.diagonalProjectileLauncher.gameTick(deltaTime);
|
this.diagonalProjectileLauncher.gameTick(deltaTime);
|
||||||
|
this.enemyProjectileLauncher.gameTick(deltaTime);
|
||||||
this.background.gameTick();
|
this.background.gameTick();
|
||||||
|
|
||||||
this.timeAlive += deltaTime;
|
this.timeAlive += deltaTime;
|
||||||
|
@ -1,30 +1,54 @@
|
|||||||
import { Vec3, Node, Vec2 } from "cc";
|
import { Vec3, Node, Vec2 } from "cc";
|
||||||
import { GameTimer } from "../../../../Services/GameTimer";
|
import { GameTimer } from "../../../../Services/GameTimer";
|
||||||
|
import { EnemyLauncherSettings } from "../../../Data/GameSettings";
|
||||||
import { ProjectileLauncher } from "../../Player/ProjectileLauncher/ProjectileLauncher";
|
import { ProjectileLauncher } from "../../Player/ProjectileLauncher/ProjectileLauncher";
|
||||||
import { Enemy } from "../Enemy";
|
import { Enemy } from "../Enemy";
|
||||||
import { EnemyManager } from "../EnemyManager";
|
import { EnemyManager } from "../EnemyManager";
|
||||||
|
|
||||||
export class EnemyProjectileLauncher {
|
export class EnemyProjectileLauncher {
|
||||||
private enemies: Enemy[] = [];
|
private enemyToTimer = new Map<Enemy, GameTimer>();
|
||||||
private shootTimer: GameTimer = new GameTimer(3);
|
private cooldown: number;
|
||||||
|
private enemyIds: string[];
|
||||||
|
|
||||||
public constructor(private playerNode: Node, private projectileLauncher: ProjectileLauncher, enemyManager: EnemyManager) {
|
public constructor(
|
||||||
|
private projectileLauncher: ProjectileLauncher,
|
||||||
|
private playerNode: Node,
|
||||||
|
enemyManager: EnemyManager,
|
||||||
|
settings: EnemyLauncherSettings
|
||||||
|
) {
|
||||||
enemyManager.EnemyAddedEvent.on(this.tryAddEnemy, this);
|
enemyManager.EnemyAddedEvent.on(this.tryAddEnemy, this);
|
||||||
enemyManager.EnemyRemovedEvent.on(this.tryRemoveEnemy, this);
|
enemyManager.EnemyRemovedEvent.on(this.tryRemoveEnemy, this);
|
||||||
|
|
||||||
|
this.cooldown = settings.cooldown;
|
||||||
|
this.enemyIds = settings.enemyIds;
|
||||||
|
projectileLauncher.init(settings.projectileLifetime, settings.projectileSpeed, settings.projectileDamage, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private tryAddEnemy(enemy: Enemy): void {
|
private tryAddEnemy(enemy: Enemy): void {
|
||||||
if (enemy.Id == "BasicEnemy") {
|
if (this.enemyIds.includes(enemy.Id)) {
|
||||||
this.enemies.push();
|
this.enemyToTimer.set(enemy, new GameTimer(this.cooldown));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private tryRemoveEnemy(enemy: Enemy): void {
|
private tryRemoveEnemy(enemy: Enemy): void {
|
||||||
if (enemy.Id == "BasicEnemy") {
|
if (!this.enemyToTimer.has(enemy)) return;
|
||||||
const index = this.enemies.indexOf(enemy);
|
|
||||||
this.enemies.splice(index, 1);
|
this.enemyToTimer.delete(enemy);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public gameTick(deltaTime: number): void {}
|
public gameTick(deltaTime: number): void {
|
||||||
|
this.projectileLauncher.gameTick(deltaTime);
|
||||||
|
|
||||||
|
for (const enemyAndTimerPair of this.enemyToTimer) {
|
||||||
|
const enemyWorldPosition: Vec3 = enemyAndTimerPair[0].node.worldPosition;
|
||||||
|
const shootTimer: GameTimer = enemyAndTimerPair[1];
|
||||||
|
|
||||||
|
shootTimer.gameTick(deltaTime);
|
||||||
|
if (shootTimer.tryFinishPeriod()) {
|
||||||
|
let direction: Vec3 = new Vec3();
|
||||||
|
direction = Vec3.subtract(direction, this.playerNode.worldPosition, enemyWorldPosition);
|
||||||
|
this.projectileLauncher.fireProjectiles(enemyWorldPosition, [new Vec2(direction.x, direction.y)]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,6 +51,7 @@ export class ProjectileLauncher extends Component implements IProjectileCollisio
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fireProjectile(startPosition: Vec3, direction: Vec2): void {
|
private fireProjectile(startPosition: Vec3, direction: Vec2): void {
|
||||||
|
direction = direction.normalize();
|
||||||
const projectile: Projectile = this.projectilePool.borrow();
|
const projectile: Projectile = this.projectilePool.borrow();
|
||||||
projectile.init(this.projectileDamage, this.projectilePierces, getDegreeAngleFromDirection(direction.x, direction.y));
|
projectile.init(this.projectileDamage, this.projectilePierces, getDegreeAngleFromDirection(direction.x, direction.y));
|
||||||
projectile.node.setWorldPosition(startPosition);
|
projectile.node.setWorldPosition(startPosition);
|
||||||
|
Loading…
Reference in New Issue
Block a user