Make it so you cant shoot yourself
This commit is contained in:
@@ -16,7 +16,7 @@ export class TargetingSystem {
|
|||||||
private active: boolean = false;
|
private active: boolean = false;
|
||||||
private targetingItemId: string | null = null;
|
private targetingItemId: string | null = null;
|
||||||
private cursor: Vec2 | null = null;
|
private cursor: Vec2 | null = null;
|
||||||
|
|
||||||
// Context for predictive visual
|
// Context for predictive visual
|
||||||
private world: World | null = null;
|
private world: World | null = null;
|
||||||
private accessor: EntityAccessor | null = null;
|
private accessor: EntityAccessor | null = null;
|
||||||
@@ -25,7 +25,7 @@ export class TargetingSystem {
|
|||||||
constructor(scene: Phaser.Scene) {
|
constructor(scene: Phaser.Scene) {
|
||||||
this.graphics = scene.add.graphics();
|
this.graphics = scene.add.graphics();
|
||||||
this.graphics.setDepth(2000); // High depth to draw over world
|
this.graphics.setDepth(2000); // High depth to draw over world
|
||||||
|
|
||||||
// Create crosshair sprite but hide it initially
|
// Create crosshair sprite but hide it initially
|
||||||
this.crosshairSprite = scene.add.sprite(0, 0, UI_CONFIG.targeting.crosshair.textureKey, UI_CONFIG.targeting.crosshair.frame);
|
this.crosshairSprite = scene.add.sprite(0, 0, UI_CONFIG.targeting.crosshair.textureKey, UI_CONFIG.targeting.crosshair.frame);
|
||||||
this.crosshairSprite.setDepth(2001); // On top of line
|
this.crosshairSprite.setDepth(2001); // On top of line
|
||||||
@@ -94,6 +94,12 @@ export class TargetingSystem {
|
|||||||
const player = accessor.getCombatant(playerId);
|
const player = accessor.getCombatant(playerId);
|
||||||
if (!player || !player.inventory) return false;
|
if (!player || !player.inventory) return false;
|
||||||
|
|
||||||
|
// Prevent targeting self
|
||||||
|
if (this.cursor.x === player.pos.x && this.cursor.y === player.pos.y) {
|
||||||
|
console.log("Cannot target self!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const itemIdx = player.inventory.items.findIndex(it => it.id === this.targetingItemId);
|
const itemIdx = player.inventory.items.findIndex(it => it.id === this.targetingItemId);
|
||||||
if (itemIdx === -1) {
|
if (itemIdx === -1) {
|
||||||
console.log("Item not found!");
|
console.log("Item not found!");
|
||||||
@@ -102,15 +108,15 @@ export class TargetingSystem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const item = player.inventory.items[itemIdx];
|
const item = player.inventory.items[itemIdx];
|
||||||
|
|
||||||
// Only remove if it's a consumable throwable
|
// Only remove if it's a consumable throwable
|
||||||
if (item.type === "Consumable" && item.throwable) {
|
if (item.type === "Consumable" && item.throwable) {
|
||||||
// Handle stack decrement if applicable, or remove
|
// Handle stack decrement if applicable, or remove
|
||||||
if (item.quantity && item.quantity > 1) {
|
if (item.quantity && item.quantity > 1) {
|
||||||
item.quantity--;
|
item.quantity--;
|
||||||
} else {
|
} else {
|
||||||
player.inventory.items.splice(itemIdx, 1);
|
player.inventory.items.splice(itemIdx, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const start = player.pos;
|
const start = player.pos;
|
||||||
@@ -187,7 +193,7 @@ export class TargetingSystem {
|
|||||||
if (this.world && this.accessor && this.playerId !== null) {
|
if (this.world && this.accessor && this.playerId !== null) {
|
||||||
const result = traceProjectile(this.world, playerPos, this.cursor, this.accessor, this.playerId);
|
const result = traceProjectile(this.world, playerPos, this.cursor, this.accessor, this.playerId);
|
||||||
const bPos = result.blockedPos;
|
const bPos = result.blockedPos;
|
||||||
|
|
||||||
finalEndX = bPos.x * TILE_SIZE + TILE_SIZE / 2;
|
finalEndX = bPos.x * TILE_SIZE + TILE_SIZE / 2;
|
||||||
finalEndY = bPos.y * TILE_SIZE + TILE_SIZE / 2;
|
finalEndY = bPos.y * TILE_SIZE + TILE_SIZE / 2;
|
||||||
}
|
}
|
||||||
@@ -222,27 +228,27 @@ export class TargetingSystem {
|
|||||||
private drawDashedLine(x1: number, y1: number, x2: number, y2: number): void {
|
private drawDashedLine(x1: number, y1: number, x2: number, y2: number): void {
|
||||||
const dashLen = GAME_CONFIG.ui.targetingLineDash;
|
const dashLen = GAME_CONFIG.ui.targetingLineDash;
|
||||||
const gapLen = GAME_CONFIG.ui.targetingLineGap;
|
const gapLen = GAME_CONFIG.ui.targetingLineGap;
|
||||||
|
|
||||||
const dx = x2 - x1;
|
const dx = x2 - x1;
|
||||||
const dy = y2 - y1;
|
const dy = y2 - y1;
|
||||||
const distance = Math.sqrt(dx * dx + dy * dy);
|
const distance = Math.sqrt(dx * dx + dy * dy);
|
||||||
|
|
||||||
if (distance === 0) return;
|
if (distance === 0) return;
|
||||||
|
|
||||||
const angle = Math.atan2(dy, dx);
|
const angle = Math.atan2(dy, dx);
|
||||||
const cos = Math.cos(angle);
|
const cos = Math.cos(angle);
|
||||||
const sin = Math.sin(angle);
|
const sin = Math.sin(angle);
|
||||||
|
|
||||||
let currentDist = 0;
|
let currentDist = 0;
|
||||||
while (currentDist < distance) {
|
while (currentDist < distance) {
|
||||||
const len = Math.min(dashLen, distance - currentDist);
|
const len = Math.min(dashLen, distance - currentDist);
|
||||||
const sx = x1 + currentDist * cos;
|
const sx = x1 + currentDist * cos;
|
||||||
const sy = y1 + currentDist * sin;
|
const sy = y1 + currentDist * sin;
|
||||||
const ex = sx + len * cos;
|
const ex = sx + len * cos;
|
||||||
const ey = sy + len * sin;
|
const ey = sy + len * sin;
|
||||||
|
|
||||||
this.graphics.lineBetween(sx, sy, ex, ey);
|
this.graphics.lineBetween(sx, sy, ex, ey);
|
||||||
currentDist += dashLen + gapLen;
|
currentDist += dashLen + gapLen;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,34 +3,34 @@ import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|||||||
|
|
||||||
// Mock Phaser
|
// Mock Phaser
|
||||||
vi.mock('phaser', () => {
|
vi.mock('phaser', () => {
|
||||||
const mockGraphics = {
|
const mockGraphics = {
|
||||||
setDepth: vi.fn().mockReturnThis(),
|
setDepth: vi.fn().mockReturnThis(),
|
||||||
clear: vi.fn().mockReturnThis(),
|
clear: vi.fn().mockReturnThis(),
|
||||||
lineStyle: vi.fn().mockReturnThis(),
|
lineStyle: vi.fn().mockReturnThis(),
|
||||||
lineBetween: vi.fn().mockReturnThis(),
|
lineBetween: vi.fn().mockReturnThis(),
|
||||||
};
|
};
|
||||||
|
|
||||||
const mockSprite = {
|
const mockSprite = {
|
||||||
setDepth: vi.fn().mockReturnThis(),
|
setDepth: vi.fn().mockReturnThis(),
|
||||||
setVisible: vi.fn().mockReturnThis(),
|
setVisible: vi.fn().mockReturnThis(),
|
||||||
setAlpha: vi.fn().mockReturnThis(),
|
setAlpha: vi.fn().mockReturnThis(),
|
||||||
setPosition: vi.fn().mockReturnThis(),
|
setPosition: vi.fn().mockReturnThis(),
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
default: {
|
default: {
|
||||||
GameObjects: {
|
GameObjects: {
|
||||||
Sprite: vi.fn(() => mockSprite),
|
Sprite: vi.fn(() => mockSprite),
|
||||||
Graphics: vi.fn(() => mockGraphics),
|
Graphics: vi.fn(() => mockGraphics),
|
||||||
},
|
},
|
||||||
Scene: class {
|
Scene: class {
|
||||||
add = {
|
add = {
|
||||||
graphics: vi.fn(() => mockGraphics),
|
graphics: vi.fn(() => mockGraphics),
|
||||||
sprite: vi.fn(() => mockSprite),
|
sprite: vi.fn(() => mockSprite),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
// Mock CombatLogic
|
// Mock CombatLogic
|
||||||
@@ -53,7 +53,7 @@ describe('TargetingSystem', () => {
|
|||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
vi.clearAllMocks();
|
vi.clearAllMocks();
|
||||||
|
|
||||||
mockGraphics = {
|
mockGraphics = {
|
||||||
setDepth: vi.fn().mockReturnThis(),
|
setDepth: vi.fn().mockReturnThis(),
|
||||||
clear: vi.fn().mockReturnThis(),
|
clear: vi.fn().mockReturnThis(),
|
||||||
@@ -77,7 +77,7 @@ describe('TargetingSystem', () => {
|
|||||||
|
|
||||||
targetingSystem = new TargetingSystem(mockScene);
|
targetingSystem = new TargetingSystem(mockScene);
|
||||||
mockWorld = { width: 10, height: 10 };
|
mockWorld = { width: 10, height: 10 };
|
||||||
|
|
||||||
// Default return for traceProjectile
|
// Default return for traceProjectile
|
||||||
(traceProjectile as any).mockReturnValue({
|
(traceProjectile as any).mockReturnValue({
|
||||||
blockedPos: { x: 0, y: 0 },
|
blockedPos: { x: 0, y: 0 },
|
||||||
@@ -171,4 +171,33 @@ describe('TargetingSystem', () => {
|
|||||||
expect(mockGraphics.clear).toHaveBeenCalled();
|
expect(mockGraphics.clear).toHaveBeenCalled();
|
||||||
expect(mockSprite.setVisible).toHaveBeenCalledWith(false);
|
expect(mockSprite.setVisible).toHaveBeenCalledWith(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should prevent targeting self', () => {
|
||||||
|
const playerPos = { x: 1, y: 1 };
|
||||||
|
|
||||||
|
// Setup targeting
|
||||||
|
targetingSystem.startTargeting(
|
||||||
|
'item-1',
|
||||||
|
playerPos,
|
||||||
|
mockWorld,
|
||||||
|
{ getCombatant: vi.fn().mockReturnValue({ pos: playerPos, inventory: { items: [{ id: 'item-1' }] } }) } as any,
|
||||||
|
1 as EntityId,
|
||||||
|
new Uint8Array(100),
|
||||||
|
10
|
||||||
|
);
|
||||||
|
|
||||||
|
// Manually set cursor to player pos (startTargeting might do it, but we ensure it)
|
||||||
|
targetingSystem.updateCursor(playerPos, playerPos);
|
||||||
|
|
||||||
|
const callback = vi.fn();
|
||||||
|
const result = targetingSystem.executeThrow(
|
||||||
|
mockWorld,
|
||||||
|
1 as EntityId,
|
||||||
|
{ getCombatant: vi.fn().mockReturnValue({ pos: playerPos, inventory: { items: [{ id: 'item-1' }] } }) } as any,
|
||||||
|
callback
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result).toBe(false);
|
||||||
|
expect(callback).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user