Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Entity/AI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ export class AI {
this._aiHash = (AI._aiHashCounter++) % 16384;

this.inputs.mouse.set({
x: 20,
x: 0,
y: 0
});

Expand Down
2 changes: 1 addition & 1 deletion src/Entity/Boss/AbstractBoss.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ export default class AbstractBoss extends LivingEntity {
this.styleData.values.color = Color.Fallen;

this.physicsData.values.sides = 1;
this.physicsData.values.size = 50 * Math.pow(1.01, 75 - 1);
this.physicsData.values.size = 50;

this.reloadTime = 15 * Math.pow(0.914, 7);

Expand Down
19 changes: 3 additions & 16 deletions src/Entity/Boss/Defender.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,12 @@ const MountedTurretDefinition: BarrelDefinition = {
...AutoTurretDefinition,
bullet: {
...AutoTurretDefinition.bullet,
speed: 2.3,
damage: 1.3,
speed: 2.46,
damage: 1.2,
health: 5.75,
color: Color.Neutral
}
};
}

/**
* Definitions (stats and data) of the trap launcher on Defender
Expand Down Expand Up @@ -78,7 +78,6 @@ const DEFENDER_SIZE = 150;
* Class which represents the boss "Defender"
*/
export default class Defender extends AbstractBoss {

/** Defender's trap launchers */
private trappers: Barrel[] = [];
/** See AbstractBoss.movementSpeed */
Expand Down Expand Up @@ -116,21 +115,9 @@ export default class Defender extends AbstractBoss {
base.positionData.values.x = this.physicsData.values.size * Math.cos(angle) * offset;

base.physicsData.values.flags |= PositionFlags.absoluteRotation;

const tickBase = base.tick;
base.tick = (tick: number) => {
base.positionData.y = this.physicsData.values.size * Math.sin(angle) * offset;
base.positionData.x = this.physicsData.values.size * Math.cos(angle) * offset;

tickBase.call(base, tick);
}
}
}

public get sizeFactor() {
return (this.physicsData.values.size / Math.SQRT1_2) / DEFENDER_SIZE;
}

public tick(tick: number) {
super.tick(tick);

Expand Down
5 changes: 1 addition & 4 deletions src/Entity/Boss/FallenBooster.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,7 @@ export default class FallenBooster extends AbstractBoss {
def.bullet = Object.assign({}, def.bullet, { speed: 1.7, health: 6.25, damage:def.bullet.damage * 0.8 });
this.barrels.push(new Barrel(this, def));
}
}

public get sizeFactor() {
return this.physicsData.values.size / 50;
this.scale(Math.pow(1.01, 75 - 1)); // Level 75 size
}

protected moveAroundMap() {
Expand Down
5 changes: 1 addition & 4 deletions src/Entity/Boss/FallenOverlord.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,12 @@ export default class FallenOverlord extends AbstractBoss {
this.nameData.values.name = "Fallen Overlord";

for (const barrelDefinition of TankDefinitions[Tank.Overlord].barrels) {

const def = Object.assign({}, barrelDefinition, { droneCount: 7, reload: 0.36 });
def.bullet = Object.assign({}, def.bullet, { sizeRatio: 0.5, speed: 1.7, damage: 0.56, health: 12.5 });
this.barrels.push(new Barrel(this, def));
}
}

public get sizeFactor() {
return this.physicsData.values.size / 50;
this.scale(Math.pow(1.01, 75 - 1)); // Level 75 size
}

public tick(tick: number) {
Expand Down
9 changes: 5 additions & 4 deletions src/Entity/Misc/ArenaCloser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,13 @@ export default class ArenaCloser extends TankBody {
const inputs = new Inputs();
const camera = new CameraEntity(game);

super(game, camera, inputs);

camera.cameraData.values.player = this;
camera.setLevel(300);
camera.sizeFactor = (ArenaCloser.BASE_SIZE / 50);

super(game, camera, inputs);
this.scaleFactor = 1;
this.scale(ArenaCloser.BASE_SIZE / this.baseSize);

Comment on lines +40 to 47
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to Dominator: camera.setLevel(300) currently runs after player is set, which scales the initial Basic tank body/barrels and is then immediately followed by resetting scaleFactor/rescales and setTank(Tank.ArenaCloser). If the intent is to set stats/level without applying that level-based scaling to the body, consider calling setLevel() before assigning player (or otherwise skipping the initial scale) to avoid extra scaling and transient inconsistent state.

Copilot uses AI. Check for mistakes.
this.relationsData.values.team = game.arena;

Expand Down Expand Up @@ -68,7 +71,6 @@ export default class ArenaCloser extends TankBody {
this.styleData.values.color = Color.Neutral;
this.positionData.values.flags |= PositionFlags.canMoveThroughWalls;
this.physicsData.values.flags |= PhysicsFlags.canEscapeArena;
camera.cameraData.values.player = this;

for (let i = Stat.MovementSpeed; i < Stat.BodyDamage; ++i) camera.cameraData.values.statLevels.values[i] = 7;

Expand All @@ -89,7 +91,6 @@ export default class ArenaCloser extends TankBody {
}

super.tick(tick);

this.ai.movementSpeed = this.cameraEntity.cameraData.movementSpeed = 80;
}
}
8 changes: 2 additions & 6 deletions src/Entity/Misc/BaseDrones.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ import { CameraEntity } from "../../Native/Camera";
const DroneSpawnerDefinition = (count: number): BarrelDefinition => ({
angle: 0,
offset: 0,
size: 95 / 5,
width: 42 / 5,
size: 95,
width: 42,
delay: 0,
reload: 0,
recoil: 0,
Expand Down Expand Up @@ -92,8 +92,4 @@ export default class BaseDrones extends ObjectEntity implements BarrelBase {
this.droneSpawner.styleData.values.flags = this.styleData.values.flags ^= StyleFlags.isVisible;

}

public get sizeFactor() {
return 5; // Large drone AI range, hacky
}
}
1 change: 1 addition & 0 deletions src/Entity/Misc/Boss/FallenAC.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export default class FallenAC extends AbstractBoss {
for (const barrelDefinition of TankDefinitions[Tank.ArenaCloser].barrels) {
this.barrels.push(new Barrel(this, barrelDefinition));
}
this.scale(Math.pow(1.01, 75 - 1)); // Level 75 size
}

public get sizeFactor() {
Expand Down
1 change: 1 addition & 0 deletions src/Entity/Misc/Boss/FallenMegaTrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export default class FallenMegaTrapper extends AbstractBoss {
def.bullet = Object.assign({}, def.bullet, { speed: 1.7, damage: 20, health: 20, });
this.barrels.push(new Barrel(this, def));
}
this.scale(Math.pow(1.01, 75 - 1)); // Level 75 size
this.ai.aimSpeed = this.barrels[0].bulletAccel;

}
Expand Down
2 changes: 1 addition & 1 deletion src/Entity/Misc/Boss/FallenSpike.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ export default class FallenSpike extends AbstractBoss {

// Sharp
this.damagePerTick *= 2;

if (AddonById.spike) new AddonById['spike'](this);
this.scale(Math.pow(1.01, 75 - 1)); // Level 75 size
}

public get sizeFactor() {
Expand Down
37 changes: 22 additions & 15 deletions src/Entity/Misc/Dominator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,31 @@
along with this program. If not, see <https://www.gnu.org/licenses/>
*/

import { Color, ColorsHexCode, NameFlags, StyleFlags, EntityTags, Tank, ClientBound } from "../../Const/Enums";
import ArenaEntity from "../../Native/Arena";
import ClientCamera, { CameraEntity } from "../../Native/Camera";

import { Entity } from "../../Native/Entity";
import { AI, AIState, Inputs } from "../AI";

import ObjectEntity from "../Object";
import LivingEntity from "../Live";
import Bullet from "../Tank/Projectile/Bullet";
import TankBody from "../Tank/TankBody";
import TeamBase from "./TeamBase";

import { TeamEntity } from "./TeamEntity";
import { Color, ColorsHexCode, NameFlags, StyleFlags, EntityTags, Tank, ClientBound } from "../../Const/Enums";
import { randomFrom } from "../../util";

/**
* Dominator Tank
*/
export default class Dominator extends TankBody {
/** Size of a dominator */
public static SIZE = 160;

/** All dominator tank classes */
public static DOMINATOR_CLASSES: Tank[] = [Tank.DominatorD, Tank.DominatorG, Tank.DominatorT];

/** The AI that controls how the Dominator aims. */
public ai: AI;
Expand All @@ -44,22 +51,20 @@ export default class Dominator extends TankBody {
public prefix: string | null = "";

public constructor(arena: ArenaEntity, base: TeamBase, pTankId: Tank | null = null) {
let tankId: Tank;
if (pTankId === null) {
const r = Math.random() * 3;

if (r < 1) tankId = Tank.DominatorD;
else if (r < 2) tankId = Tank.DominatorG;
else tankId = Tank.DominatorT;
} else tankId = pTankId;
const tankId = pTankId || randomFrom(Dominator.DOMINATOR_CLASSES);

const inputs = new Inputs();
const camera = new CameraEntity(arena.game);

super(arena.game, camera, inputs);

camera.cameraData.values.player = this;
camera.setLevel(75);
camera.sizeFactor = (Dominator.SIZE / 50);

super(arena.game, camera, inputs);
this.scaleFactor = 1;
this.scale(Dominator.SIZE / this.baseSize);

Comment on lines +59 to +66
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This constructor calls camera.setLevel(75) after assigning camera.cameraData.values.player = this, which triggers a scale of the temporary Basic tank body/barrels, and then immediately resets scaleFactor / rescales again before setTank(). Since the level is only used for stats here (and is above maxPlayerLevel anyway), consider reordering so setLevel() happens before assigning player (or otherwise avoiding the initial scale) to prevent redundant scaling work and transient inconsistent scaleFactor/size state.

Copilot uses AI. Check for mistakes.
this.setTank(tankId);

this.relationsData.values.team = arena;
this.physicsData.values.size = Dominator.SIZE;
Expand All @@ -73,7 +78,6 @@ export default class Dominator extends TankBody {
this.ai.viewRange = 2000;
this.ai.doAimPrediction = true;

this.setTank(tankId);
const def = (this.definition = Object.assign({}, this.definition));
def.speed = camera.cameraData.values.movementSpeed = 0;
this.nameData.values.name = "Dominator";
Expand Down Expand Up @@ -118,7 +122,7 @@ export default class Dominator extends TankBody {
this.styleData.color = killerTeam.teamData.values.teamColor
this.game.broadcast()
.u8(ClientBound.Notification)
.stringNT(`The ${this.prefix}${this.nameData.values.name} is now controlled by ${killerTeam.teamName}`)
.stringNT(`The ${this.prefix}${this.nameData.values.name} is now controlled by ${killerTeam.teamName || "a mysterious group"}`)
.u32(ColorsHexCode[killerTeam.teamData.values.teamColor])
.float(7500)
.stringNT("").send();
Expand All @@ -127,9 +131,12 @@ export default class Dominator extends TankBody {
const camera = client.camera;
if (!camera) continue;

if (camera.relationsData.values.team === this.relationsData.values.team) client.notify(`Press H to take control of the ${this.nameData.values.name}`, ColorsHexCode[killerTeam.teamData.values.teamColor])
if (camera.relationsData.values.team === this.relationsData.values.team) {
client.notify(`Press H to take control of the ${this.nameData.values.name}`, ColorsHexCode[killerTeam.teamData.values.teamColor]);
}
}
} else {
// set to neutral team
this.relationsData.team = this.game.arena
this.styleData.color = this.game.arena.teamData.teamColor;

Expand All @@ -142,7 +149,7 @@ export default class Dominator extends TankBody {
}

this.base.styleData.color = this.styleData.values.color;
this.base.relationsData.team = this.relationsData.values.team;;
this.base.relationsData.team = this.relationsData.values.team;

this.healthData.health = this.healthData.values.maxHealth;

Expand Down
10 changes: 3 additions & 7 deletions src/Entity/Misc/Mothership.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,6 @@ export default class Mothership extends TankBody {
const inputs = new Inputs();
const camera = new CameraEntity(game);

camera.setLevel(140);

super(game, camera, inputs);

this.relationsData.values.team = game.arena;
Expand All @@ -55,12 +53,10 @@ export default class Mothership extends TankBody {
this.ai = new AI(this, true);
this.ai.inputs = inputs;
this.ai.viewRange = 2000;

this.positionData.values.x = 0;
this.positionData.values.y = 0;


camera.cameraData.values.player = this;
this.setTank(Tank.Mothership);

camera.setLevel(140);
this.nameData.values.name = "Mothership"

this.scoreReward = 0;
Expand Down
22 changes: 20 additions & 2 deletions src/Entity/Object.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,7 @@ class DeletionAnimation {
case 5:
this.entity.styleData.opacity = 1 - (1 / 6);
default:
this.entity.physicsData.size *= 1.1;
this.entity.physicsData.width *= 1.1;
this.entity.scale(1.1);
this.entity.styleData.opacity -= 1 / 6;
if (this.entity.styleData.values.opacity < 0) this.entity.styleData.opacity = 0;
break;
Expand Down Expand Up @@ -95,6 +94,9 @@ export default class ObjectEntity extends Entity {
/** Used to determine the parent of all parents. */
public rootParent: ObjectEntity = this;

/** Entity size multiplier */
public scaleFactor: number = 1;

/** Entity bit flag tags. */
public entityTags: number = 0;

Expand Down Expand Up @@ -390,6 +392,22 @@ export default class ObjectEntity extends Entity {
}
}

public scale(value: number) {
this.scaleFactor *= value;

this.physicsData.size *= value;
this.physicsData.width *= value;

if (this.isChild) {
this.positionData.x *= value;
this.positionData.y *= value;
}

for (const entity of this.children) {
entity.scale(value);
}
}

public tick(tick: number) {
this.deletionAnimation?.tick();

Expand Down
Loading