Skip to content

Commit

Permalink
fix(client): improve combat
Browse files Browse the repository at this point in the history
  • Loading branch information
Veradictus committed Sep 17, 2023
1 parent 9e4a248 commit 81849fb
Show file tree
Hide file tree
Showing 17 changed files with 117 additions and 28 deletions.
45 changes: 45 additions & 0 deletions packages/client/data/sprites.json
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,51 @@
{ "id": "mobs/cowwarrior", "width": 42, "height": 42, "offsetX": -13, "offsetY": -18 },
{ "id": "mobs/rooster", "width": 42, "height": 42, "offsetX": -13, "offsetY": -18 },
{ "id": "mobs/adherer", "width": 32, "height": 32, "offsetX": -8, "offsetY": -12 },
{
"id": "mobs/goldgolem",
"width": 32,
"height": 32,
"animations": {
"atk_right": {
"length": 5,
"row": 0
},
"walk_right": {
"length": 4,
"row": 1
},
"idle_right": {
"length": 2,
"row": 2
},
"atk_up": {
"length": 5,
"row": 3
},
"walk_up": {
"length": 4,
"row": 4
},
"idle_up": {
"length": 2,
"row": 5
},
"atk_down": {
"length": 5,
"row": 6
},
"walk_down": {
"length": 4,
"row": 7
},
"idle_down": {
"length": 2,
"row": 8
}
},
"offsetX": -8,
"offsetY": -24
},
{
"id": "mobs/ant",
"width": 48,
Expand Down
4 changes: 3 additions & 1 deletion packages/client/src/controllers/input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -471,7 +471,9 @@ export default class InputController {
if (this.player.canAttackTarget())
this.game.socket.send(Packets.Target, [
Opcodes.Target.Attack,
this.entity.instance
this.entity.instance,
this.entity.gridX,
this.entity.gridY
]);
}
return;
Expand Down
6 changes: 3 additions & 3 deletions packages/client/src/entity/character/character.ts
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ export default class Character extends Entity {
*/

public trade(entity: Entity): void {
if (this.dead) return;
if (this.dead || this.teleporting) return;

this.trading = true;

Expand All @@ -252,7 +252,7 @@ export default class Character extends Entity {
if (Date.now() - this.lastFollow < 300) return;

// Prevent following when entity is stunned or dead.
if (this.dead || this.isStunned()) return;
if (this.dead || this.isStunned() || this.teleporting) return;

this.lastFollow = Date.now();

Expand All @@ -270,7 +270,7 @@ export default class Character extends Entity {
*/

public pursue(character: Character): void {
if (this.dead || this.isStunned()) return;
if (this.dead || this.isStunned() || this.teleporting) return;

this.setTarget(character);
this.move(character.gridX, character.gridY);
Expand Down
14 changes: 9 additions & 5 deletions packages/client/src/game.ts
Original file line number Diff line number Diff line change
Expand Up @@ -346,8 +346,7 @@ export default class Game {
position.gridY!,
radius
),
closest: Entity | undefined,
boundary = this.map.tileSize - 2;
closest: Entity | undefined;

/**
* The `position` parameter contains the absolute x and y coordinates
Expand All @@ -361,10 +360,15 @@ export default class Game {
// Skip pets from the search.
if (entity.isPet()) continue;

let entityX = entity.x - entity.sprite.offsetX / 2,
entityY = entity.y - entity.sprite.offsetY / 2,
distance = Utils.distance(position.x, position.y, entityX, entityY);
let { x, y, sprite } = entity,
{ width, height, offsetX, offsetY } = sprite,
largest = width > height ? width : height,
toX = x - offsetX / 2,
toY = y + offsetY / 2,
distance = Utils.distance(position.x, position.y, toX, toY),
boundary = largest / 2 + Utils.halfTile + (width > 32 ? this.map.tileSize : 0);

// Skip if the distance is greater than the boundary.
if (distance > boundary) continue;

if (!closest || distance < closest.distance) {
Expand Down
2 changes: 1 addition & 1 deletion packages/client/src/map/map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export default class Map {
// Store tile size globally into the utils.
Utils.tileSize = this.tileSize;
Utils.sideLength = this.width / Modules.Constants.MAP_DIVISION_SIZE;
Utils.thirdTile = this.tileSize / 3;
Utils.halfTile = this.tileSize / 2;
Utils.tileAndAQuarter = this.tileSize * 1.25;
}

Expand Down
2 changes: 1 addition & 1 deletion packages/client/src/network/connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,7 @@ export default class Connection {
let currentPlayer = entity.instance === this.game.player.instance;

// Stop and freeze the player until teleprtation is complete.
entity.stop(true);
entity.stop();
entity.frozen = true;

// Clears all bubbles when our main entity teleports.
Expand Down
2 changes: 1 addition & 1 deletion packages/client/src/renderer/renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1698,7 +1698,7 @@ export default class Renderer {
this.camera.forEachVisiblePosition((x, y) => {
if (!this.map.isOutOfBounds(x, y) && grids.renderingGrid[y][x])
for (let entity of Object.values(grids.renderingGrid[y][x])) callback(entity);
});
}, 10);
}

/**
Expand Down
2 changes: 1 addition & 1 deletion packages/client/src/utils/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export let isInt = (n: number): boolean => n % 1 === 0;
export default {
tileSize: -1,
sideLength: -1,
thirdTile: -1,
halfTile: -1,
tileAndAQuarter: -1,

/**
Expand Down
2 changes: 2 additions & 0 deletions packages/server/data/plugins/mobs/ogrelord.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ export default class OgreLord extends Default {
let minion = super.spawn(key, position.x, position.y),
target = super.getTarget();

minion.roamDistance = 24;

// Have the minions attack one of the boss' attackers.
if (target) minion.combat.attack(target);
}
Expand Down
5 changes: 3 additions & 2 deletions packages/server/data/plugins/mobs/piratecaptain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export default class PirateCaptain extends Default {
for (let minion of Object.values(this.minions)) minion.deathCallback?.();

this.minionsSpawned = 0;
this.mob.attackRange = 1;
}

/**
Expand Down Expand Up @@ -69,7 +70,7 @@ export default class PirateCaptain extends Default {
// Stop all players from attacking the pirate captain.
this.mob.world.cleanCombat(this.mob);

this.mob.attackRange = 14;
this.mob.attackRange = 16;

// Update the position and teleport the captain with an animation.
this.mob.teleport(position.x, position.y, true);
Expand All @@ -87,7 +88,7 @@ export default class PirateCaptain extends Default {
target = super.getTarget(); // Pick a random target from the attackers

// Update the roam distance for minions (so they don't go back to spawn point).
minion.roamDistance = this.mob.roamDistance;
minion.roamDistance = 20;

// Set the target for the minion.
if (target) minion.combat.attack(target);
Expand Down
2 changes: 1 addition & 1 deletion packages/server/data/plugins/mobs/skeletonking.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export default class SkeletonKing extends Default {
target = super.getTarget();

// Minions have the same roaming distance as the skeleton king.
minion.roamDistance = this.mob.roamDistance;
minion.roamDistance = 24;

if (target) minion.combat.attack(target);

Expand Down
4 changes: 4 additions & 0 deletions packages/server/src/controllers/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1267,6 +1267,10 @@ export default class Commands {
case 'crystalcave': {
return this.player.teleport(886, 622, true, false, true);
}

case 'piratecaptain': {
return this.player.teleport(930, 752, true, false, true);
}
}

break;
Expand Down
2 changes: 1 addition & 1 deletion packages/server/src/game/entity/character/character.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export default abstract class Character extends Entity {
public projectileName = 'arrow';

public lastStep = -1;
public lastMovement = -1;
public lastMovement = Date.now();
public lastRegionChange = -1;

private healingInterval?: NodeJS.Timeout | undefined;
Expand Down
9 changes: 5 additions & 4 deletions packages/server/src/game/entity/character/combat/combat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,8 @@ export default class Combat {
this.character.follow();
this.lastFollow = Date.now();

if (this.shouldTeleportNearby()) this.character.findAdjacentTile();
if (this.shouldTeleportNearby())
this.character.setPosition(this.character.target!.x, this.character.target!.y);
}
}

Expand Down Expand Up @@ -270,13 +271,13 @@ export default class Combat {
/**
* Mob positions may not be updated if there is not a spectator and the player switches
* tabs. In this case we just teleport the mob next to the player. Because the lastMovement
* exceeds 3 seconds and the mob is still not nearby, we can conclude it's not able to
* exceeds 5 seconds and the mob is still not nearby, we can conclude it's not able to
* move and we should teleport it.
* @returns Whether the character is a mob and it hasn't moved in the last 3 seconds.
* @returns Whether the character is a mob and it hasn't moved in the last 5 seconds.
*/

private shouldTeleportNearby(): boolean {
return this.character.isMob() && Date.now() - this.character.lastMovement > 3000;
return this.character.isMob() && Date.now() - this.character.lastMovement > 5000;
}

/**
Expand Down
32 changes: 31 additions & 1 deletion packages/server/src/game/entity/character/mob/mob.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import PluginIndex from '../../../../../data/plugins/mobs';
import log from '@kaetram/common/util/log';
import Utils from '@kaetram/common/util/utils';
import { Modules, Opcodes } from '@kaetram/common/network';
import { HealPacket, MovementPacket } from '@kaetram/common/network/impl';
import { HealPacket, MovementPacket, TeleportPacket } from '@kaetram/common/network/impl';
import { SpecialEntityTypes } from '@kaetram/common/network/modules';

import type Area from '../../../map/areas/area';
Expand Down Expand Up @@ -292,6 +292,32 @@ export default class Mob extends Character {
this.world.entities.spawnLootBag(this.x, this.y, player.username, items);
}

/**
* Override for the teleport functionality with added support for stopping
* all additional packets from being sent to the regions.
* @param x The x grid coordinate.
* @param y The y grid coordinate.
* @param withAnimation Whether or not to teleport with an animation.
*/

public override teleport(x: number, y: number, withAnimation = false): void {
this.setPosition(x, y, false);

this.teleporting = true;

this.sendToRegions(
new TeleportPacket({
instance: this.instance,
x,
y,
withAnimation
})
);

// Untoggle the teleporting flag after 500ms.
setTimeout(() => (this.teleporting = false), 500);
}

/**
* Moves the mob and broadcasts the action
* to all the adjacent regions.
Expand All @@ -301,6 +327,8 @@ export default class Mob extends Character {
*/

public override setPosition(x: number, y: number, withPacket = true): void {
if (this.teleporting) return;

super.setPosition(x, y);

this.calculateOrientation();
Expand All @@ -314,6 +342,8 @@ export default class Mob extends Character {
y
})
});

this.lastMovement = Date.now();
}

/**
Expand Down
8 changes: 3 additions & 5 deletions packages/server/src/game/entity/character/player/incoming.ts
Original file line number Diff line number Diff line change
Expand Up @@ -369,16 +369,14 @@ export default class Incoming {
// Prevent crazy position updates, add some leeway to the roaming distance.
if (entity.outsideRoaming(requestX!, requestY!, entity.roamDistance * 2)) return;

entity.lastMovement = Date.now();

// For mobs update the position without a packet.
return entity.setPosition(requestX!, requestY!, false);
}
}
}

private handleTarget(message: [Opcodes.Target, string]): void {
let [opcode, instance] = message;
private handleTarget(message: [Opcodes.Target, string, number?, number?]): void {
let [opcode, instance, x, y] = message;

switch (opcode) {
case Opcodes.Target.Talk: {
Expand All @@ -402,7 +400,7 @@ export default class Incoming {
}

case Opcodes.Target.Attack: {
return this.player.handleTargetAttack(instance);
return this.player.handleTargetAttack(instance, x, y);
}

case Opcodes.Target.Object: {
Expand Down
4 changes: 3 additions & 1 deletion packages/server/src/game/entity/character/player/player.ts
Original file line number Diff line number Diff line change
Expand Up @@ -745,7 +745,7 @@ export default class Player extends Character {
* @param instance The instance of the target we are attacking.
*/

public handleTargetAttack(instance: string): void {
public handleTargetAttack(instance: string, x?: number, y?: number): void {
// Prevent targetting yourself.
if (instance === this.instance) return;

Expand All @@ -757,6 +757,8 @@ export default class Player extends Character {
// Ensure that the player can actually attack the target.
if (!this.canAttack(target)) return;

if (target.isMob() && !target.combat.started && x && y) target.setPosition(x, y);

// Clear the cheat score
this.cheatScore = 0;

Expand Down

0 comments on commit 81849fb

Please sign in to comment.