diff --git a/gameserver/commands/OnCaptureFlagCreateCommand.ts b/gameserver/commands/OnCaptureFlagCreateCommand.ts index 6d539c8..79150fd 100644 --- a/gameserver/commands/OnCaptureFlagCreateCommand.ts +++ b/gameserver/commands/OnCaptureFlagCreateCommand.ts @@ -21,7 +21,7 @@ export class OnCaptureFlagCreateCommand extends Command< const sessionState = this.state; gameManager ?.getPlayer(client.id) - ?.createCaptureFlag(message.x, message.y, sessionState); + ?.createCaptureFlag(message.x, message.y, sessionState, gameManager); } catch (error) { console.error(error); } diff --git a/gameserver/core/types/SceneObject.ts b/gameserver/core/types/SceneObject.ts index 25f2ab0..d7d6a18 100644 --- a/gameserver/core/types/SceneObject.ts +++ b/gameserver/core/types/SceneObject.ts @@ -3,7 +3,7 @@ import SAT from "sat"; * @class SceneObject * @classdesc Any object that is meant to be part of the Scene should extend this class. */ -export type SceneObjectType = "FIXED" | "MOVABLE"; +export type SceneObjectType = "FIXED" | "MOVABLE" | "CAPTURE_FLAG"; export class SceneObject extends SAT.Box { readonly id: string; @@ -24,7 +24,7 @@ export class SceneObject extends SAT.Box { y: number, size = 32, type: SceneObjectType, - collidable: boolean = true + collidable: boolean = true, ) { super(new SAT.Vector(x, y), size, size); this.width = size; diff --git a/gameserver/schema/CaptureFlagState.ts b/gameserver/schema/CaptureFlagState.ts index 2059461..4caaf1a 100644 --- a/gameserver/schema/CaptureFlagState.ts +++ b/gameserver/schema/CaptureFlagState.ts @@ -22,7 +22,10 @@ export class CaptureFlagState extends Schema implements ISceneItem { constructor(x: number, y: number) { super(); this.pos = new VectorState(x, y); - this.sceneItemRef = new SceneObject(this.id, x, y, 64, "FIXED", false); + this.sceneItemRef = new SceneObject(this.id, x, y, 64, "CAPTURE_FLAG", false); + } + setHealth(health: number) { + this.health = Math.max(0,health); } getSceneItem() { return this.sceneItemRef; diff --git a/gameserver/schema/PlayerState.ts b/gameserver/schema/PlayerState.ts index 0408f90..8445037 100644 --- a/gameserver/schema/PlayerState.ts +++ b/gameserver/schema/PlayerState.ts @@ -88,7 +88,13 @@ export class PlayerState extends Schema implements ISceneItem { return this.sceneItemRef; } - createCaptureFlag(x: number, y: number, sessionState: SessionState) { + createCaptureFlag( + x: number, + y: number, + sessionState: SessionState, + gameManager: GameStateManagerType + ) { + const scene = gameManager.scene; if (this.captureFlags.length >= 4) { return; } @@ -111,10 +117,15 @@ export class PlayerState extends Schema implements ISceneItem { if (tileOwner !== "NONE") return; this.resources = this.resources - CaptureFlagState.cost; + const captureFlag = new CaptureFlagState(x, y); this.captureFlags.push(captureFlag); + scene.addSceneItem(captureFlag); + this.resourceGrowthRateHz = this.resourceGrowthRateHz * (1 + 0.2 * this.captureFlags.length); + + sessionState.onCaptureFlagAdded(captureFlag.id, this.id); sessionState.tilemap.updateOwnershipMap(sessionState.getPlayers()); } @@ -123,16 +134,24 @@ export class PlayerState extends Schema implements ISceneItem { sessionState: SessionState, gameManager: GameStateManagerType ) { + const scene = gameManager.scene; const flagObj = this.captureFlags.findIndex((flag) => flag.id === flagId); if (flagObj < 0) { return; } gameManager.scene.removeSceneItem(flagId); this.captureFlags.deleteAt(flagObj); + scene.removeSceneItem(flagId); + + sessionState.onCaptureFlagRemoved(flagId); this.resourceGrowthRateHz = 2 * (1 + 0.2 * this.captureFlags.length); sessionState.tilemap.updateOwnershipMap(sessionState.getPlayers()); } - removeBulkCaptureFlag(flagIds: string[], sessionState: SessionState, gameManager: GameStateManagerType) { + removeBulkCaptureFlag( + flagIds: string[], + sessionState: SessionState, + gameManager: GameStateManagerType + ) { let flagsRemoved = 0; flagIds.forEach((flagId) => { const flagIndex = this.captureFlags.findIndex( @@ -142,6 +161,7 @@ export class PlayerState extends Schema implements ISceneItem { return; } gameManager.scene.removeSceneItem(flagId); + sessionState.onCaptureFlagRemoved(flagId); flagsRemoved += this.captureFlags.deleteAt(flagIndex) ? 1 : 0; }); diff --git a/gameserver/schema/SessionState.ts b/gameserver/schema/SessionState.ts index 70f2e19..c3697db 100644 --- a/gameserver/schema/SessionState.ts +++ b/gameserver/schema/SessionState.ts @@ -15,6 +15,8 @@ export class SessionState extends Schema { @type("number") countdown: number = SERVER_CONFIG.COUNTDOWN_DEFAULT; @type("string") mapId: string = "map1"; @type(TilemapState) tilemap = new TilemapState(); + + captureFlagIdToParentId: Map = new Map(); constructor() { super(); } @@ -38,6 +40,14 @@ export class SessionState extends Schema { } return playersArr; } + + onCaptureFlagAdded(flagId: string, parentId: string) { + this.captureFlagIdToParentId.set(flagId, parentId); + } + onCaptureFlagRemoved(flagId: string) { + this.captureFlagIdToParentId.delete(flagId); + } + public removePlayer(sessionId: string, gameManager: GameStateManagerType) { const player = this.players.get(sessionId); if (!player) { diff --git a/gameserver/schema/SoldierState.ts b/gameserver/schema/SoldierState.ts index 4e8da5f..1962186 100644 --- a/gameserver/schema/SoldierState.ts +++ b/gameserver/schema/SoldierState.ts @@ -82,7 +82,7 @@ export class SoldierState extends Schema implements ISceneItem, IBoidAgent { this.attackTarget = null; this.targetVector = null; - const v = new SAT.Vector(x,y); + const v = new SAT.Vector(x, y); this.currentPosition.setVector(v); this.expectedPosition.setVector(v); this.targetPosition.setVector(v); @@ -270,7 +270,11 @@ export class SoldierState extends Schema implements ISceneItem, IBoidAgent { return this.velocityVector.clone(); } - tick(delta: number, stateManager: GameStateManagerType, sessionState: SessionState) { + tick( + delta: number, + stateManager: GameStateManagerType, + sessionState: SessionState + ) { this.currentState = this.stateMachine .currentState as keyof typeof SoldierStateMachineJSON.states; @@ -341,7 +345,7 @@ export class SoldierState extends Schema implements ISceneItem, IBoidAgent { ); const soldierCenterPosition = this.getSceneItem().getCircleCenter(); - const enemyTowers = stateManager.scene + const enemyCastles = stateManager.scene .getNearbyUnits(soldierCenterPosition.x, soldierCenterPosition.y, 100, [ "FIXED", ]) @@ -359,15 +363,48 @@ export class SoldierState extends Schema implements ISceneItem, IBoidAgent { ) .map((d) => stateManager.getPlayer(d.id)); - enemyTowers.forEach((enemyTower) => { + enemyCastles.forEach((enemyTower) => { if (!enemyTower) return; enemyTower.castleHealth = Math.max( 0, enemyTower.castleHealth - 0.5 * delta ); - if(enemyTower.castleHealth <= 0) + if (enemyTower.castleHealth <= 0) sessionState.removePlayer(enemyTower.id, stateManager); }); + + let nearbyCaptureFlags = stateManager.scene.getNearbyUnits( + soldierCenterPosition.x, + soldierCenterPosition.y, + 100, + ["CAPTURE_FLAG"] + ); + + const enemyCaptureFlags = nearbyCaptureFlags.filter( + (quadtreeItem) => + sessionState.captureFlagIdToParentId.get(quadtreeItem.id) !== + this.playerId + ); + + enemyCaptureFlags.forEach((flagQuatree) => { + const flagOwnerId = sessionState.captureFlagIdToParentId.get( + flagQuatree.id + ); + if (!flagOwnerId) return; + const flag = sessionState + .getPlayer(flagOwnerId) + ?.captureFlags.toArray() + .filter((flag) => flag.id === flagQuatree.id); + + if (flag && flag?.[0]) { + flag[0].setHealth(flag[0].health - 0.5 * delta); + if(flag[0].health === 0) + sessionState + .getPlayer(flagOwnerId) + ?.removeCaptureFlag(flag[0].id, sessionState, stateManager); + } + }); + this.stateMachine.tick({ delta, stateManager, soldier: this }); }