From 35da093d0d724f6f95bee24a574da59cc0ffec85 Mon Sep 17 00:00:00 2001 From: c86ec23b-fef1-4979-b2fa-b9adc351b8cc <87239823+c86ec23b-fef1-4979-b2fa-b9adc351b8cc@users.noreply.github.com> Date: Mon, 2 Feb 2026 05:34:41 +0200 Subject: [PATCH 1/8] Add files via upload . --- src/Entity/AI.ts | 2 +- src/Entity/Boss/AbstractBoss.ts | 2 +- src/Entity/Boss/Defender.ts | 13 ------------- src/Entity/Boss/FallenBooster.ts | 5 +---- src/Entity/Boss/FallenOverlord.ts | 5 +---- src/Entity/Misc/ArenaCloser.ts | 10 ++++++---- src/Entity/Misc/Mothership.ts | 10 +++------- src/Entity/Object.ts | 22 ++++++++++++++++++++-- src/Entity/Tank/Addons.ts | 7 ++----- src/Entity/Tank/AutoTurret.ts | 5 +++-- src/Entity/Tank/Barrel.ts | 23 ++++++----------------- src/Entity/Tank/TankBody.ts | 10 +++++++--- src/Native/Camera.ts | 28 +++++++++++++++++----------- 13 files changed, 68 insertions(+), 74 deletions(-) diff --git a/src/Entity/AI.ts b/src/Entity/AI.ts index 97d760ed..4b74c2d8 100644 --- a/src/Entity/AI.ts +++ b/src/Entity/AI.ts @@ -113,7 +113,7 @@ export class AI { this._aiHash = (AI._aiHashCounter++) % 16384; this.inputs.mouse.set({ - x: 20, + x: 0, y: 0 }); diff --git a/src/Entity/Boss/AbstractBoss.ts b/src/Entity/Boss/AbstractBoss.ts index 914dfef0..b858b202 100644 --- a/src/Entity/Boss/AbstractBoss.ts +++ b/src/Entity/Boss/AbstractBoss.ts @@ -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); diff --git a/src/Entity/Boss/Defender.ts b/src/Entity/Boss/Defender.ts index 65fca6b0..21cd84a8 100644 --- a/src/Entity/Boss/Defender.ts +++ b/src/Entity/Boss/Defender.ts @@ -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 */ @@ -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); diff --git a/src/Entity/Boss/FallenBooster.ts b/src/Entity/Boss/FallenBooster.ts index 86baa06a..7f94b069 100644 --- a/src/Entity/Boss/FallenBooster.ts +++ b/src/Entity/Boss/FallenBooster.ts @@ -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() { diff --git a/src/Entity/Boss/FallenOverlord.ts b/src/Entity/Boss/FallenOverlord.ts index 7589f087..ed12f785 100644 --- a/src/Entity/Boss/FallenOverlord.ts +++ b/src/Entity/Boss/FallenOverlord.ts @@ -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) { diff --git a/src/Entity/Misc/ArenaCloser.ts b/src/Entity/Misc/ArenaCloser.ts index 509879fe..4aaee741 100644 --- a/src/Entity/Misc/ArenaCloser.ts +++ b/src/Entity/Misc/ArenaCloser.ts @@ -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(175 / 50); this.relationsData.values.team = game.arena; @@ -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; @@ -77,6 +79,7 @@ export default class ArenaCloser extends TankBody { } public tick(tick: number) { + console.log(this.physicsData.values.size); this.inputs = this.ai.inputs; if (this.ai.state === AIState.idle) { @@ -89,7 +92,6 @@ export default class ArenaCloser extends TankBody { } super.tick(tick); - this.ai.movementSpeed = this.cameraEntity.cameraData.movementSpeed = 80; } } diff --git a/src/Entity/Misc/Mothership.ts b/src/Entity/Misc/Mothership.ts index 145cf335..561b769f 100644 --- a/src/Entity/Misc/Mothership.ts +++ b/src/Entity/Misc/Mothership.ts @@ -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; @@ -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; diff --git a/src/Entity/Object.ts b/src/Entity/Object.ts index e4107268..0f0e8448 100644 --- a/src/Entity/Object.ts +++ b/src/Entity/Object.ts @@ -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; @@ -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; @@ -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(); diff --git a/src/Entity/Tank/Addons.ts b/src/Entity/Tank/Addons.ts index 2e86c14f..c7bb0eec 100644 --- a/src/Entity/Tank/Addons.ts +++ b/src/Entity/Tank/Addons.ts @@ -97,9 +97,6 @@ export class Addon { const tickBase = base.tick; base.tick = (tick: number) => { - base.positionData.y = this.owner.physicsData.values.size * Math.sin(angle) * ROT_OFFSET; - base.positionData.x = this.owner.physicsData.values.size * Math.cos(angle) * ROT_OFFSET; - tickBase.call(base, tick); if (base.ai.state === AIState.idle) base.positionData.angle = angle + rotator.positionData.values.angle; @@ -260,13 +257,13 @@ class LauncherAddon extends Addon { launcher.physicsData.values.flags |= PhysicsFlags.isTrapezoid; launcher.physicsData.values.sides = 2; - launcher.tick = () => { + /*launcher.tick = () => { const size = this.owner.physicsData.values.size; launcher.physicsData.size = sizeRatio * size; launcher.physicsData.width = widthRatio * size; launcher.positionData.x = launcher.physicsData.values.size / 2; - } + }*/ } } /** Centered Auto Turret addon. */ diff --git a/src/Entity/Tank/AutoTurret.ts b/src/Entity/Tank/AutoTurret.ts index be227465..908cf969 100644 --- a/src/Entity/Tank/AutoTurret.ts +++ b/src/Entity/Tank/AutoTurret.ts @@ -97,7 +97,8 @@ export default class AutoTurret extends ObjectEntity { this.physicsData.values.sides = 1; this.baseSize = baseSize; - this.physicsData.values.size = this.baseSize * this.sizeFactor; + this.physicsData.values.size = this.baseSize * this.owner.rootParent.scaleFactor; + this.scaleFactor = this.owner.rootParent.scaleFactor; this.styleData.values.color = Color.Barrel; this.styleData.values.flags |= StyleFlags.showsAboveParent; @@ -133,7 +134,7 @@ export default class AutoTurret extends ObjectEntity { if (this.ai.state === AIState.hasTarget) this.ai.passiveRotation = Math.random() < .5 ? AI.PASSIVE_ROTATION : -AI.PASSIVE_ROTATION; - this.physicsData.size = this.baseSize * this.sizeFactor; + this.scaleFactor = this.owner.rootParent.scaleFactor; this.ai.aimSpeed = this.turret.bulletAccel; // Top Speed diff --git a/src/Entity/Tank/Barrel.ts b/src/Entity/Tank/Barrel.ts index 3011716c..7c04245b 100644 --- a/src/Entity/Tank/Barrel.ts +++ b/src/Entity/Tank/Barrel.ts @@ -126,13 +126,13 @@ export default class Barrel extends ObjectEntity { this.relationsData.values.owner = owner; this.relationsData.values.team = owner.relationsData.values.team; - const sizeFactor = this.tank.sizeFactor; - const size = this.physicsData.values.size = this.definition.size * sizeFactor; + const scaleFactor = this.tank.scaleFactor; + const size = this.physicsData.values.size = this.definition.size * scaleFactor; - this.physicsData.values.width = this.definition.width * sizeFactor; + this.physicsData.values.width = this.definition.width * scaleFactor; this.positionData.values.angle = this.definition.angle + (this.definition.trapezoidDirection); - this.positionData.values.x = Math.cos(this.definition.angle) * (size / 2 + ((this.definition.distance ?? 0) * sizeFactor)) - Math.sin(this.definition.angle) * this.definition.offset * sizeFactor; - this.positionData.values.y = Math.sin(this.definition.angle) * (size / 2 + ((this.definition.distance ?? 0) * sizeFactor)) + Math.cos(this.definition.angle) * this.definition.offset * sizeFactor; + this.positionData.values.x = Math.cos(this.definition.angle) * (size / 2 + ((this.definition.distance ?? 0) * scaleFactor)) - Math.sin(this.definition.angle) * this.definition.offset * scaleFactor; + this.positionData.values.y = Math.sin(this.definition.angle) * (size / 2 + ((this.definition.distance ?? 0) * scaleFactor)) + Math.cos(this.definition.angle) * this.definition.offset * scaleFactor; // addons are below barrel, use StyleFlags.aboveParent to go above parent if (barrelDefinition.addon) { @@ -217,21 +217,10 @@ export default class Barrel extends ObjectEntity { /** Resizes the barrel; when the tank gets bigger, the barrel must as well. */ protected resize() { - const sizeFactor = this.tank.sizeFactor; - const size = this.physicsData.size = this.definition.size * sizeFactor; - - this.physicsData.width = this.definition.width * sizeFactor; - this.positionData.angle = this.definition.angle + (this.definition.trapezoidDirection); - this.positionData.x = Math.cos(this.definition.angle) * (size / 2 + (this.definition.distance || 0)) - Math.sin(this.definition.angle) * this.definition.offset * sizeFactor; - this.positionData.y = Math.sin(this.definition.angle) * (size / 2 + (this.definition.distance || 0)) + Math.cos(this.definition.angle) * this.definition.offset * sizeFactor; - - // Updates bullet accel too - this.bulletAccel = (20 + (this.tank.cameraEntity.cameraData?.values.statLevels.values[Stat.BulletSpeed] || 0) * 3) * this.definition.bullet.speed; } public tick(tick: number) { - this.resize(); - + this.bulletAccel = (20 + (this.tank.cameraEntity.cameraData?.values.statLevels.values[Stat.BulletSpeed] || 0) * 3) * this.definition.bullet.speed; this.relationsData.values.team = this.tank.relationsData.values.team; if (!this.tank.rootParent.deletionAnimation){ diff --git a/src/Entity/Tank/TankBody.ts b/src/Entity/Tank/TankBody.ts index b69fe4ac..019bc947 100644 --- a/src/Entity/Tank/TankBody.ts +++ b/src/Entity/Tank/TankBody.ts @@ -39,7 +39,6 @@ import { AccessLevel, maxPlayerLevel } from "../../config"; /** * Abstract type of entity which barrels can connect to. - * - `sizeFactor` is required and must be a `number` * - `cameraEntity` is required and must be a `Camera` */ export type BarrelBase = ObjectEntity & { sizeFactor: number, cameraEntity: CameraEntity, reloadTime: number, inputs: Inputs }; @@ -114,6 +113,7 @@ export default class TankBody extends LivingEntity implements BarrelBase { public get sizeFactor() { return this.physicsData.values.size / this.baseSize; } + /** The current tank type / tank id. */ public get currentTank() { @@ -154,6 +154,7 @@ export default class TankBody extends LivingEntity implements BarrelBase { // Size ratios this.baseSize = tank.baseSizeOverride ?? tank.sides === 4 ? Math.SQRT2 * 32.5 : tank.sides === 16 ? Math.SQRT2 * 25 : 50; + this.physicsData.size = this.baseSize * this.scaleFactor; this.physicsData.absorbtionFactor = this.isInvulnerable ? 0 : tank.absorbtionFactor; if (tank.absorbtionFactor === 0) this.positionData.flags |= PositionFlags.canMoveThroughWalls; else if (this.positionData.flags & PositionFlags.canMoveThroughWalls) this.positionData.flags ^= PositionFlags.canMoveThroughWalls; @@ -184,6 +185,8 @@ export default class TankBody extends LivingEntity implements BarrelBase { // Yeah, yeah why not this.cameraEntity.cameraData.tankOverride = tank.name; camera.setFieldFactor(tank.fieldFactor); + + this.scale(1); // Update addons and etc } /** See LivingEntity.onKill */ public onKill(entity: LivingEntity) { @@ -288,8 +291,9 @@ export default class TankBody extends LivingEntity implements BarrelBase { if (client && client.accessLevel < AccessLevel.FullAccess) this.setInvulnerability(false); } } - if (!this.deletionAnimation && !this.inputs.deleted) this.physicsData.size = this.baseSize * this.cameraEntity.sizeFactor; - else this.regenPerTick = 0; + + // if (!this.deletionAnimation && !this.inputs.deleted) this.physicsData.size = this.baseSize * this.scaleFactor + // else this.regenPerTick = 0; super.tick(tick); diff --git a/src/Native/Camera.ts b/src/Native/Camera.ts index 364934d5..61278429 100644 --- a/src/Native/Camera.ts +++ b/src/Native/Camera.ts @@ -41,25 +41,32 @@ export class CameraEntity extends Entity { /** Always existant relations field group. Present in all GUI/camera entities. */ public relationsData: RelationsGroup = new RelationsGroup(this); - /** The current size of the tank the camera is in charge of. Calculated with level stuff */ - public sizeFactor: number = 1; - /** Entity being spectated if any (deathscreen). */ public spectatee: ObjectEntity | null = null; + + /** The current size of the tank the camera is in charge of. Calculated with level stuff */ + public sizeFactor: number = 1; /** Used to set the current camera's level. Should be the only way used to set level. */ public setLevel(level: number) { const previousLevel = this.cameraData.values.level; + this.cameraData.level = level; - this.sizeFactor = Math.pow(1.01, level - 1); this.cameraData.levelbarMax = level < maxPlayerLevel ? 1 : 0; // quick hack, not correct values - if (level <= maxPlayerLevel) { - this.cameraData.score = levelToScore(level); + + const levelScore = levelToScore(level); + const isMaxLevel = level <= maxPlayerLevel; + const player = this.cameraData.values.player; + + if (isMaxLevel) this.cameraData.score = levelScore; - const player = this.cameraData.values.player; - if (TankBody.isTank(player)) { - player.scoreData.score = this.cameraData.values.score; - player.scoreReward = this.cameraData.values.score; + if (TankBody.isTank(player)) { + const sizeFactor = Math.pow(1.01, level - previousLevel); + player.scale(sizeFactor); + + if (isMaxLevel) { + player.scoreData.score = levelScore; + player.scoreReward = levelScore; } } @@ -69,7 +76,6 @@ export class CameraEntity extends Entity { this.setFieldFactor(getTankById(this.cameraData.values.tank)?.fieldFactor || 1); } - /** Returns the camera's client if it exists */ public getClient(): Client | null { return null; From 7f0dc6499e2f6a9a85aa80e3f94c2bd046d5a1ff Mon Sep 17 00:00:00 2001 From: c86ec23b-fef1-4979-b2fa-b9adc351b8cc <87239823+c86ec23b-fef1-4979-b2fa-b9adc351b8cc@users.noreply.github.com> Date: Wed, 4 Feb 2026 03:46:50 +0200 Subject: [PATCH 2/8] fixes --- src/Entity/Boss/Defender.ts | 6 +-- src/Entity/Misc/ArenaCloser.ts | 3 +- src/Entity/Misc/BaseDrones.ts | 8 +--- src/Entity/Misc/Boss/FallenAC.ts | 1 + src/Entity/Misc/Boss/FallenMegaTrapper.ts | 1 + src/Entity/Misc/Boss/FallenSpike.ts | 2 +- src/Entity/Misc/Dominator.ts | 37 +++++++++------ src/Entity/Tank/Addons.ts | 58 +++++++---------------- src/Entity/Tank/AutoTurret.ts | 30 +++++------- src/Entity/Tank/Projectile/Bullet.ts | 6 +-- src/Entity/Tank/Projectile/Drone.ts | 2 +- src/Entity/Tank/Projectile/Minion.ts | 5 +- src/Entity/Tank/Projectile/Rocket.ts | 18 ++++--- src/Entity/Tank/Projectile/Skimmer.ts | 36 +++++++------- src/Entity/Tank/TankBody.ts | 13 ++--- src/Gamemodes/Misc/FactoryTest.ts | 4 +- src/Native/Arena.ts | 4 +- src/index.ts | 2 +- 18 files changed, 103 insertions(+), 133 deletions(-) diff --git a/src/Entity/Boss/Defender.ts b/src/Entity/Boss/Defender.ts index 21cd84a8..5512c0da 100644 --- a/src/Entity/Boss/Defender.ts +++ b/src/Entity/Boss/Defender.ts @@ -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 diff --git a/src/Entity/Misc/ArenaCloser.ts b/src/Entity/Misc/ArenaCloser.ts index 4aaee741..a30fbc03 100644 --- a/src/Entity/Misc/ArenaCloser.ts +++ b/src/Entity/Misc/ArenaCloser.ts @@ -43,7 +43,7 @@ export default class ArenaCloser extends TankBody { camera.setLevel(300); this.scaleFactor = 1; - this.scale(175 / 50); + this.scale(ArenaCloser.BASE_SIZE / this.baseSize); this.relationsData.values.team = game.arena; @@ -79,7 +79,6 @@ export default class ArenaCloser extends TankBody { } public tick(tick: number) { - console.log(this.physicsData.values.size); this.inputs = this.ai.inputs; if (this.ai.state === AIState.idle) { diff --git a/src/Entity/Misc/BaseDrones.ts b/src/Entity/Misc/BaseDrones.ts index f238edde..c43a9183 100644 --- a/src/Entity/Misc/BaseDrones.ts +++ b/src/Entity/Misc/BaseDrones.ts @@ -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, @@ -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 - } } diff --git a/src/Entity/Misc/Boss/FallenAC.ts b/src/Entity/Misc/Boss/FallenAC.ts index 43634641..4512cb9a 100644 --- a/src/Entity/Misc/Boss/FallenAC.ts +++ b/src/Entity/Misc/Boss/FallenAC.ts @@ -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() { diff --git a/src/Entity/Misc/Boss/FallenMegaTrapper.ts b/src/Entity/Misc/Boss/FallenMegaTrapper.ts index e0699456..24069d7c 100644 --- a/src/Entity/Misc/Boss/FallenMegaTrapper.ts +++ b/src/Entity/Misc/Boss/FallenMegaTrapper.ts @@ -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; } diff --git a/src/Entity/Misc/Boss/FallenSpike.ts b/src/Entity/Misc/Boss/FallenSpike.ts index 71b9251a..b699a7e9 100644 --- a/src/Entity/Misc/Boss/FallenSpike.ts +++ b/src/Entity/Misc/Boss/FallenSpike.ts @@ -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() { diff --git a/src/Entity/Misc/Dominator.ts b/src/Entity/Misc/Dominator.ts index 1fcf709e..6e164a93 100644 --- a/src/Entity/Misc/Dominator.ts +++ b/src/Entity/Misc/Dominator.ts @@ -16,17 +16,21 @@ along with this program. If not, see */ -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 @@ -34,6 +38,9 @@ import { TeamEntity } from "./TeamEntity"; 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; @@ -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); + + this.setTank(tankId); this.relationsData.values.team = arena; this.physicsData.values.size = Dominator.SIZE; @@ -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"; @@ -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(); @@ -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; @@ -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; diff --git a/src/Entity/Tank/Addons.ts b/src/Entity/Tank/Addons.ts index c7bb0eec..dc36ef25 100644 --- a/src/Entity/Tank/Addons.ts +++ b/src/Entity/Tank/Addons.ts @@ -97,9 +97,9 @@ export class Addon { const tickBase = base.tick; base.tick = (tick: number) => { - tickBase.call(base, tick); - if (base.ai.state === AIState.idle) base.positionData.angle = angle + rotator.positionData.values.angle; + + tickBase.call(base, tick); } rotator.turrets.push(base); @@ -109,7 +109,6 @@ export class Addon { } } - const AutoTurretMiniDefinition: BarrelDefinition = { angle: 0, offset: 0, @@ -131,7 +130,7 @@ const AutoTurretMiniDefinition: BarrelDefinition = { sizeRatio: 1, absorbtionFactor: 1 } -}; +} /** * A smasher-like guard object. @@ -146,20 +145,18 @@ export class GuardObject extends ObjectEntity implements BarrelBase { /** Helps the class determine size ratio as well as who is the owner */ protected owner: BarrelBase; - /** To store the size ratio (in compared to the owner) */ - public sizeRatio: number; /** Radians per tick, how many radians the guard will rotate in a tick */ public radiansPerTick: number; - public constructor(game: GameServer, owner: BarrelBase, sides: number, sizeRatio: number, offsetAngle: number, radiansPerTick: number) { + public constructor(game: GameServer, owner: BarrelBase, sides: number, scaleFactor: number, offsetAngle: number, radiansPerTick: number) { super(game); this.owner = owner; this.inputs = owner.inputs; this.cameraEntity = owner.cameraEntity; // It's weird, but it's how it works - sizeRatio *= Math.SQRT1_2 - this.sizeRatio = sizeRatio; + scaleFactor *= Math.SQRT1_2 + this.scaleFactor = scaleFactor; this.radiansPerTick = radiansPerTick; this.setParent(owner); @@ -171,14 +168,7 @@ export class GuardObject extends ObjectEntity implements BarrelBase { this.positionData.values.angle = offsetAngle; this.physicsData.values.sides = sides; this.reloadTime = owner.reloadTime; - this.physicsData.values.size = owner.physicsData.values.size * sizeRatio; - } - - /** - * Size factor, used for calculation of the turret and base size. - */ - get sizeFactor() { - return this.owner.sizeFactor; + this.physicsData.values.size = owner.physicsData.values.size * scaleFactor; } /** @@ -192,7 +182,6 @@ export class GuardObject extends ObjectEntity implements BarrelBase { public tick(tick: number): void { this.reloadTime = this.owner.reloadTime; - this.physicsData.size = this.sizeRatio * this.owner.physicsData.values.size; this.positionData.angle += this.radiansPerTick; // It won't ever do any collisions, so no need to tick the object // super.tick(tick); @@ -210,6 +199,7 @@ class SpikeAddon extends Addon { this.createGuard(3, 1.3, Math.PI / 2, 0.17); } } + /** Dominator's Base addon. */ class DomBaseAddon extends Addon { public constructor(owner: BarrelBase) { @@ -218,6 +208,7 @@ class DomBaseAddon extends Addon { this.createGuard(6, 1.24, 0, 0); } } + /** Smasher addon. */ class SmasherAddon extends Addon { public constructor(owner: BarrelBase) { @@ -226,6 +217,7 @@ class SmasherAddon extends Addon { this.createGuard(6, 1.15, 0, .1); } } + /** Landmine addon. */ class LandmineAddon extends Addon { public constructor(owner: BarrelBase) { @@ -235,6 +227,7 @@ class LandmineAddon extends Addon { this.createGuard(6, 1.15, 0, .05); } } + /** The thing underneath Rocketeer and Twister addon. */ class LauncherAddon extends Addon { public constructor(owner: BarrelBase) { @@ -256,16 +249,9 @@ class LauncherAddon extends Addon { launcher.styleData.values.color = Color.Barrel; launcher.physicsData.values.flags |= PhysicsFlags.isTrapezoid; launcher.physicsData.values.sides = 2; - - /*launcher.tick = () => { - const size = this.owner.physicsData.values.size; - - launcher.physicsData.size = sizeRatio * size; - launcher.physicsData.width = widthRatio * size; - launcher.positionData.x = launcher.physicsData.values.size / 2; - }*/ } } + /** Centered Auto Turret addon. */ class AutoTurretAddon extends Addon { public constructor(owner: BarrelBase) { @@ -284,6 +270,7 @@ class AutoSmasherAddon extends Addon { new AutoTurret(owner); } } + /** 5 Auto Turrets */ class Auto5Addon extends Addon { public constructor(owner: BarrelBase) { @@ -292,6 +279,7 @@ class Auto5Addon extends Addon { this.createAutoTurrets(5); } } + /** 3 Auto Turrets */ class Auto3Addon extends Addon { public constructor(owner: BarrelBase) { @@ -300,6 +288,7 @@ class Auto3Addon extends Addon { this.createAutoTurrets(3); } } + /** The thing above ranger's barrel. */ class PronouncedAddon extends Addon { public constructor(owner: BarrelBase) { @@ -323,16 +312,9 @@ class PronouncedAddon extends Addon { pronounce.styleData.values.color = Color.Barrel; pronounce.physicsData.values.flags |= PhysicsFlags.isTrapezoid; pronounce.physicsData.values.sides = 2; - - pronounce.tick = () => { - const size = this.owner.physicsData.values.size; - - pronounce.physicsData.size = sizeRatio * size; - pronounce.physicsData.width = widthRatio * size; - pronounce.positionData.x = offsetRatio * size; - } } } + /** The thing above Gunner + Destroyer Dominator's barrel. */ class PronouncedDomAddon extends Addon { public constructor(owner: BarrelBase) { @@ -356,14 +338,6 @@ class PronouncedDomAddon extends Addon { pronounce.styleData.values.color = Color.Barrel; pronounce.physicsData.values.flags |= PhysicsFlags.isTrapezoid; pronounce.physicsData.values.sides = 2; - - pronounce.tick = () => { - const size = this.owner.physicsData.values.size; - - pronounce.physicsData.size = sizeRatio * size; - pronounce.physicsData.width = widthRatio * size; - pronounce.positionData.x = offsetRatio * size; - } } } /** Weird spike addon. Based on the arrasio Original. */ diff --git a/src/Entity/Tank/AutoTurret.ts b/src/Entity/Tank/AutoTurret.ts index 908cf969..d25e452f 100644 --- a/src/Entity/Tank/AutoTurret.ts +++ b/src/Entity/Tank/AutoTurret.ts @@ -50,7 +50,7 @@ export const AutoTurretDefinition: BarrelDefinition = { sizeRatio: 1, absorbtionFactor: 1 } -}; +} /** * Auto Turret Barrel + Barrel Base @@ -62,13 +62,17 @@ export default class AutoTurret extends ObjectEntity { public nameData: NameGroup = new NameGroup(this); /** Barrel's owner (Tank-like object). */ - private owner: BarrelBase; + public owner: BarrelBase; + /** Actual turret / barrel. */ public turret: Barrel; + /** The AI controlling the turret. */ public ai: AI; + /** The AI's inputs, for determining whether to shoot or not. */ public inputs: Inputs; + /** Camera entity / team of the turret. */ public cameraEntity: CameraEntity; @@ -83,21 +87,21 @@ export default class AutoTurret extends ObjectEntity { public constructor(owner: BarrelBase, turretDefinition: BarrelDefinition = AutoTurretDefinition, baseSize: number = 25) { super(owner.game); + this.owner = owner; this.cameraEntity = owner.cameraEntity; + this.ai = new AI(this); this.ai.doAimPrediction = true; this.inputs = this.ai.inputs; - - this.owner = owner; this.setParent(owner); this.relationsData.values.owner = owner; - this.relationsData.values.team = owner.relationsData.values.team; - this.physicsData.values.sides = 1; this.baseSize = baseSize; + this.physicsData.values.sides = 1; this.physicsData.values.size = this.baseSize * this.owner.rootParent.scaleFactor; + this.scaleFactor = this.owner.rootParent.scaleFactor; this.styleData.values.color = Color.Barrel; @@ -111,13 +115,6 @@ export default class AutoTurret extends ObjectEntity { this.turret = new Barrel(this, turretDefinition); this.turret.physicsData.values.flags |= PhysicsFlags.doChildrenCollision; } - - /** - * Size factor, used for calculation of the turret and base size. - */ - public get sizeFactor() { - return this.owner.sizeFactor; - } /** * Called similarly to LivingEntity.onKill @@ -134,8 +131,6 @@ export default class AutoTurret extends ObjectEntity { if (this.ai.state === AIState.hasTarget) this.ai.passiveRotation = Math.random() < .5 ? AI.PASSIVE_ROTATION : -AI.PASSIVE_ROTATION; - this.scaleFactor = this.owner.rootParent.scaleFactor; - this.ai.aimSpeed = this.turret.bulletAccel; // Top Speed this.ai.movementSpeed = 0; @@ -143,8 +138,9 @@ export default class AutoTurret extends ObjectEntity { this.reloadTime = this.owner.reloadTime; let useAI = !(this.influencedByOwnerInputs && (this.owner.inputs.attemptingRepel() || this.owner.inputs.attemptingShot())); + if (!useAI) { - const {x, y} = this.getWorldPosition(); + const { x, y } = this.getWorldPosition(); let flip = this.owner.inputs.attemptingRepel() ? -1 : 1; const deltaPos = {x: (this.owner.inputs.mouse.x - x) * flip, y: (this.owner.inputs.mouse.y - y) * flip} @@ -162,7 +158,7 @@ export default class AutoTurret extends ObjectEntity { this.turret.attemptingShot = false; } else { // Uh. Yeah - const {x, y} = this.getWorldPosition(); + const { x, y } = this.getWorldPosition(); this.positionData.angle = Math.atan2(this.ai.inputs.mouse.y - y, this.ai.inputs.mouse.x - x); } } diff --git a/src/Entity/Tank/Projectile/Bullet.ts b/src/Entity/Tank/Projectile/Bullet.ts index be587d73..92460611 100644 --- a/src/Entity/Tank/Projectile/Bullet.ts +++ b/src/Entity/Tank/Projectile/Bullet.ts @@ -65,7 +65,7 @@ export default class Bullet extends LivingEntity { tank.rootParent.styleData.zIndex = barrel.game.entities.zIndex++; const bulletDefinition = barrel.definition.bullet; - const sizeFactor = tank.sizeFactor; + const scaleFactor = tank.scaleFactor; const statLevels = tank.cameraEntity.cameraData?.values.statLevels.values; this.relationsData.values.team = barrel.relationsData.values.team; @@ -97,8 +97,8 @@ export default class Bullet extends LivingEntity { const {x, y} = tank.getWorldPosition(); - this.positionData.values.x = x + (Math.cos(shootAngle) * barrel.physicsData.values.size) - Math.sin(shootAngle) * barrel.definition.offset * sizeFactor + Math.cos(shootAngle) * (barrel.definition.distance || 0); - this.positionData.values.y = y + (Math.sin(shootAngle) * barrel.physicsData.values.size) + Math.cos(shootAngle) * barrel.definition.offset * sizeFactor + Math.sin(shootAngle) * (barrel.definition.distance || 0); + this.positionData.values.x = x + (Math.cos(shootAngle) * barrel.physicsData.values.size) - Math.sin(shootAngle) * barrel.definition.offset * scaleFactor + Math.cos(shootAngle) * (barrel.definition.distance || 0); + this.positionData.values.y = y + (Math.sin(shootAngle) * barrel.physicsData.values.size) + Math.cos(shootAngle) * barrel.definition.offset * scaleFactor + Math.sin(shootAngle) * (barrel.definition.distance || 0); this.positionData.values.angle = shootAngle; } diff --git a/src/Entity/Tank/Projectile/Drone.ts b/src/Entity/Tank/Projectile/Drone.ts index 885c28dc..89d0827d 100644 --- a/src/Entity/Tank/Projectile/Drone.ts +++ b/src/Entity/Tank/Projectile/Drone.ts @@ -49,7 +49,7 @@ export default class Drone extends Bullet { this.usePosAngle = true; this.ai = new AI(this); - this.ai.viewRange = 850 * tank.sizeFactor; + this.ai.viewRange = 900; this.ai.targetFilter = (targetPos) => (targetPos.x - this.tank.positionData.values.x) ** 2 + (targetPos.y - this.tank.positionData.values.y) ** 2 <= this.ai.viewRange ** 2; // (1000 ** 2) 1000 radius this.canControlDrones = typeof this.barrelEntity.definition.canControlDrones === 'boolean' && this.barrelEntity.definition.canControlDrones; this.physicsData.values.sides = 3; diff --git a/src/Entity/Tank/Projectile/Minion.ts b/src/Entity/Tank/Projectile/Minion.ts index 629bd2dd..0205892a 100644 --- a/src/Entity/Tank/Projectile/Minion.ts +++ b/src/Entity/Tank/Projectile/Minion.ts @@ -79,6 +79,7 @@ export default class Minion extends Drone implements BarrelBase { this.physicsData.values.sides = 1; this.physicsData.values.size *= 1.2; + this.scaleFactor = this.physicsData.values.size / 50; if (this.physicsData.values.flags & PhysicsFlags.noOwnTeamCollision) this.physicsData.values.flags ^= PhysicsFlags.noOwnTeamCollision; if (this.physicsData.values.flags & PhysicsFlags.canEscapeArena) this.physicsData.values.flags ^= PhysicsFlags.canEscapeArena; @@ -93,10 +94,6 @@ export default class Minion extends Drone implements BarrelBase { this.arenaMobID = "factoryDrone"; } - public get sizeFactor() { - return this.physicsData.values.size / 50; - } - /** This allows for factory to hook in before the entity moves. */ protected tickMixin(tick: number) { this.reloadTime = this.tank.reloadTime; diff --git a/src/Entity/Tank/Projectile/Rocket.ts b/src/Entity/Tank/Projectile/Rocket.ts index a5c9668e..8536583f 100644 --- a/src/Entity/Tank/Projectile/Rocket.ts +++ b/src/Entity/Tank/Projectile/Rocket.ts @@ -32,7 +32,7 @@ const RocketBarrelDefinition: BarrelDefinition = { angle: Math.PI, offset: 0, size: 70, - width: 72, + width: 36, delay: 0, reload: 0.15, recoil: 3.3, @@ -65,23 +65,27 @@ export default class Rocket extends Bullet implements BarrelBase { /** The inputs for when to shoot or not. (Rocket) */ public inputs = new Inputs(); - public constructor(barrel: Barrel, tank: BarrelBase, tankDefinition: TankDefinition | null, shootAngle: number) { super(barrel, tank, tankDefinition, shootAngle); + + this.scaleFactor = this.physicsData.values.size / 50; this.cameraEntity = tank.cameraEntity; - const rocketBarrel = this.rocketBarrel = new Barrel(this, {...RocketBarrelDefinition}); + const rocketBarrel = new Barrel(this, RocketBarrelDefinition); + const rocketScale = rocketBarrel.scale.bind(rocketBarrel); + rocketBarrel.scale = (value: number) => { + rocketScale(value); + if (!this.deletionAnimation) rocketBarrel.physicsData.width = rocketBarrel.definition.width; + } rocketBarrel.styleData.values.color = this.styleData.values.color; - } + this.rocketBarrel = rocketBarrel; - public get sizeFactor() { - return this.physicsData.values.size / 50; + this.scale(1); // Update barrels } public tick(tick: number) { this.reloadTime = this.tank.reloadTime; - if (!this.deletionAnimation && this.rocketBarrel) this.rocketBarrel.definition.width = ((this.barrelEntity.definition.width / 2) * RocketBarrelDefinition.width) / this.physicsData.values.size; super.tick(tick); diff --git a/src/Entity/Tank/Projectile/Skimmer.ts b/src/Entity/Tank/Projectile/Skimmer.ts index c48f66fc..f4c219d7 100644 --- a/src/Entity/Tank/Projectile/Skimmer.ts +++ b/src/Entity/Tank/Projectile/Skimmer.ts @@ -73,33 +73,33 @@ export default class Skimmer extends Bullet implements BarrelBase { /** The direction the bullet will rotating in. */ private rotationPerTick = Skimmer.BASE_ROTATION; - public constructor(barrel: Barrel, tank: BarrelBase, tankDefinition: TankDefinition | null, shootAngle: number, direction: number) { super(barrel, tank, tankDefinition, shootAngle); + + this.scaleFactor = this.physicsData.values.size / 50; this.rotationPerTick = direction; this.cameraEntity = tank.cameraEntity; - const skimmerBarrels: Barrel[] = this.skimmerBarrels =[]; + const skimmerBarrels: Barrel[] = this.skimmerBarrels = []; + + const s1 = new Barrel(this, SkimmerBarrelDefinition); + const s1Scale = s1.scale.bind(s1); + s1.scale = (value: number) => { + s1Scale(value); + if (!this.deletionAnimation) s1.physicsData.width = s1.definition.width; + } - const s1 = new class extends Barrel { - // Keep the width constant - protected resize() { - super.resize(); - this.physicsData.values.width = this.definition.width - // this.physicsData.state.width = 0; - } - }(this, {...SkimmerBarrelDefinition}); const s2Definition = {...SkimmerBarrelDefinition}; s2Definition.angle += Math.PI - const s2 = new class extends Barrel { - // Keep the width constant - protected resize() { - super.resize(); - this.physicsData.width = this.definition.width - } - }(this, s2Definition); + + const s2 = new Barrel(this, s2Definition); + const s2Scale = s2.scale.bind(s2); + s2.scale = (value: number) => { + s2Scale(value); + if (!this.deletionAnimation) s2.physicsData.width = s2.definition.width; + } s1.styleData.values.color = this.styleData.values.color; s2.styleData.values.color = this.styleData.values.color; @@ -108,6 +108,8 @@ export default class Skimmer extends Bullet implements BarrelBase { this.inputs = new Inputs(); this.inputs.flags |= InputFlags.leftclick; + + this.scale(1); // Updates barrels } public get sizeFactor() { diff --git a/src/Entity/Tank/TankBody.ts b/src/Entity/Tank/TankBody.ts index 019bc947..a963c1bd 100644 --- a/src/Entity/Tank/TankBody.ts +++ b/src/Entity/Tank/TankBody.ts @@ -41,7 +41,7 @@ import { AccessLevel, maxPlayerLevel } from "../../config"; * Abstract type of entity which barrels can connect to. * - `cameraEntity` is required and must be a `Camera` */ -export type BarrelBase = ObjectEntity & { sizeFactor: number, cameraEntity: CameraEntity, reloadTime: number, inputs: Inputs }; +export type BarrelBase = ObjectEntity & { cameraEntity: CameraEntity, reloadTime: number, inputs: Inputs }; /** * The Tank Body, which could also be called the Player class, converts defined @@ -109,12 +109,6 @@ export default class TankBody extends LivingEntity implements BarrelBase { return !!(entity.entityTags & EntityTags.isTank); } - /** The active change in size from the base size to the current. Contributes to barrel and addon sizes. */ - public get sizeFactor() { - return this.physicsData.values.size / this.baseSize; - } - - /** The current tank type / tank id. */ public get currentTank() { return this._currentTank; @@ -291,9 +285,8 @@ export default class TankBody extends LivingEntity implements BarrelBase { if (client && client.accessLevel < AccessLevel.FullAccess) this.setInvulnerability(false); } } - - // if (!this.deletionAnimation && !this.inputs.deleted) this.physicsData.size = this.baseSize * this.scaleFactor - // else this.regenPerTick = 0; + + if (this.deletionAnimation || this.inputs.deleted) this.regenPerTick = 0; super.tick(tick); diff --git a/src/Gamemodes/Misc/FactoryTest.ts b/src/Gamemodes/Misc/FactoryTest.ts index 1208d7ed..27626878 100644 --- a/src/Gamemodes/Misc/FactoryTest.ts +++ b/src/Gamemodes/Misc/FactoryTest.ts @@ -75,8 +75,8 @@ export default class FactoryTestArena extends ArenaEntity { const barrel = this.nimdac.barrels[0]; const shootAngle = barrel.definition.angle + this.nimdac.positionData.values.angle - tank.positionData.values.x = x + (Math.cos(shootAngle) * barrel.physicsData.values.size * 0.5) - Math.sin(shootAngle) * barrel.definition.offset * this.nimdac.sizeFactor; - tank.positionData.values.y = y + (Math.sin(shootAngle) * barrel.physicsData.values.size * 0.5) + Math.cos(shootAngle) * barrel.definition.offset * this.nimdac.sizeFactor; + tank.positionData.values.x = x + (Math.cos(shootAngle) * barrel.physicsData.values.size * 0.5) - Math.sin(shootAngle) * barrel.definition.offset * this.nimdac.scaleFactor; + tank.positionData.values.y = y + (Math.sin(shootAngle) * barrel.physicsData.values.size * 0.5) + Math.cos(shootAngle) * barrel.definition.offset * this.nimdac.scaleFactor; tank.addVelocity(shootAngle, 40); } diff --git a/src/Native/Arena.ts b/src/Native/Arena.ts index 2bc6befd..6e704b4e 100644 --- a/src/Native/Arena.ts +++ b/src/Native/Arena.ts @@ -337,8 +337,8 @@ export default class ArenaEntity extends Entity implements TeamGroupEntity { const barrel = factory.barrels[0]; const shootAngle = barrel.definition.angle + factory.positionData.values.angle; - tank.positionData.values.x = x + (Math.cos(shootAngle) * barrel.physicsData.values.size) - Math.sin(shootAngle) * barrel.definition.offset * factory.sizeFactor; - tank.positionData.values.y = y + (Math.sin(shootAngle) * barrel.physicsData.values.size) + Math.cos(shootAngle) * barrel.definition.offset * factory.sizeFactor; + tank.positionData.values.x = x + (Math.cos(shootAngle) * barrel.physicsData.values.size) - Math.sin(shootAngle) * barrel.definition.offset * factory.scaleFactor; + tank.positionData.values.y = y + (Math.sin(shootAngle) * barrel.physicsData.values.size) + Math.cos(shootAngle) * barrel.definition.offset * factory.scaleFactor; tank.addVelocity(shootAngle, 25); return true; diff --git a/src/index.ts b/src/index.ts index 7a981a30..3416ed1d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -155,7 +155,7 @@ app.listen(PORT, (success) => { // RULES(0): No two game servers should share the same endpoint // // NOTES(0): As of now, both servers run on the same process (and thread) here - const ffa = new GameServer(FFAArena, "FFA"); + const ffa = new GameServer("dom", "FFA"); const sbx = new GameServer(SandboxArena, "Sandbox"); games.push(ffa, sbx); From d8ceca0f4e786216d0363902d23972c159a18a5c Mon Sep 17 00:00:00 2001 From: c86ec23b-fef1-4979-b2fa-b9adc351b8cc <87239823+c86ec23b-fef1-4979-b2fa-b9adc351b8cc@users.noreply.github.com> Date: Wed, 4 Feb 2026 03:49:18 +0200 Subject: [PATCH 3/8] Update index.ts --- src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.ts b/src/index.ts index 3416ed1d..7a981a30 100644 --- a/src/index.ts +++ b/src/index.ts @@ -155,7 +155,7 @@ app.listen(PORT, (success) => { // RULES(0): No two game servers should share the same endpoint // // NOTES(0): As of now, both servers run on the same process (and thread) here - const ffa = new GameServer("dom", "FFA"); + const ffa = new GameServer(FFAArena, "FFA"); const sbx = new GameServer(SandboxArena, "Sandbox"); games.push(ffa, sbx); From 8c74cd9174af06783e150416f214b5282f97f4ec Mon Sep 17 00:00:00 2001 From: c86ec23b-fef1-4979-b2fa-b9adc351b8cc <87239823+c86ec23b-fef1-4979-b2fa-b9adc351b8cc@users.noreply.github.com> Date: Thu, 5 Feb 2026 04:35:04 +0200 Subject: [PATCH 4/8] Update Camera.ts --- src/Native/Camera.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/Native/Camera.ts b/src/Native/Camera.ts index 61278429..8cb74061 100644 --- a/src/Native/Camera.ts +++ b/src/Native/Camera.ts @@ -43,9 +43,6 @@ export class CameraEntity extends Entity { /** Entity being spectated if any (deathscreen). */ public spectatee: ObjectEntity | null = null; - - /** The current size of the tank the camera is in charge of. Calculated with level stuff */ - public sizeFactor: number = 1; /** Used to set the current camera's level. Should be the only way used to set level. */ public setLevel(level: number) { @@ -61,8 +58,8 @@ export class CameraEntity extends Entity { if (isMaxLevel) this.cameraData.score = levelScore; if (TankBody.isTank(player)) { - const sizeFactor = Math.pow(1.01, level - previousLevel); - player.scale(sizeFactor); + const scaleFactor = Math.pow(1.01, level - previousLevel); + player.scale(scaleFactor); if (isMaxLevel) { player.scoreData.score = levelScore; From 5dc2157fee11788e1e78f4d18c98296821e5cd67 Mon Sep 17 00:00:00 2001 From: c86ec23b-fef1-4979-b2fa-b9adc351b8cc <87239823+c86ec23b-fef1-4979-b2fa-b9adc351b8cc@users.noreply.github.com> Date: Thu, 5 Feb 2026 10:22:58 +0200 Subject: [PATCH 5/8] Hopefully fix floating barrels --- src/Native/Camera.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Native/Camera.ts b/src/Native/Camera.ts index 8cb74061..55afe512 100644 --- a/src/Native/Camera.ts +++ b/src/Native/Camera.ts @@ -207,7 +207,7 @@ export default class ClientCamera extends CameraEntity { entity.positionData.values.x + width > l && entity.positionData.values.y - size < b ) { - if (entity !== this.cameraData.values.player && entity.styleData.values.opacity !== 0) { // Invisible tanks shouldn't be sent + if (entity !== this.cameraData.values.player && !(entity.styleData.values.opacity === 0 && !entity.deletionAnimation)) { // Invisible tanks shouldn't be sent entitiesInRange.push(entity); } } From d41a052253c47d2f92a7828a7ad45ae748688835 Mon Sep 17 00:00:00 2001 From: ABC <79597906+abcxff@users.noreply.github.com> Date: Tue, 10 Feb 2026 10:58:55 -0500 Subject: [PATCH 6/8] Remove unused resize method in Barrel class Removed unused resize method from Barrel class. --- src/Entity/Tank/Barrel.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Entity/Tank/Barrel.ts b/src/Entity/Tank/Barrel.ts index 7c04245b..630576f7 100644 --- a/src/Entity/Tank/Barrel.ts +++ b/src/Entity/Tank/Barrel.ts @@ -215,10 +215,6 @@ export default class Barrel extends ObjectEntity { } } - /** Resizes the barrel; when the tank gets bigger, the barrel must as well. */ - protected resize() { - } - public tick(tick: number) { this.bulletAccel = (20 + (this.tank.cameraEntity.cameraData?.values.statLevels.values[Stat.BulletSpeed] || 0) * 3) * this.definition.bullet.speed; this.relationsData.values.team = this.tank.relationsData.values.team; From aa5ca17a7c28977802550f84093e086f21cc6803 Mon Sep 17 00:00:00 2001 From: c86ec23b-fef1-4979-b2fa-b9adc351b8cc <87239823+c86ec23b-fef1-4979-b2fa-b9adc351b8cc@users.noreply.github.com> Date: Tue, 10 Feb 2026 23:09:16 +0200 Subject: [PATCH 7/8] Workaround for setLevel bugs while in possession --- src/Native/Camera.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Native/Camera.ts b/src/Native/Camera.ts index 55afe512..bedff207 100644 --- a/src/Native/Camera.ts +++ b/src/Native/Camera.ts @@ -57,6 +57,8 @@ export class CameraEntity extends Entity { if (isMaxLevel) this.cameraData.score = levelScore; + if (this.getClient()?.inputs.isPossessing) return; // TODO rework possession logic + if (TankBody.isTank(player)) { const scaleFactor = Math.pow(1.01, level - previousLevel); player.scale(scaleFactor); From 034782f2d04e58d29e987cff6e2255b7ed07a4ef Mon Sep 17 00:00:00 2001 From: c86ec23b-fef1-4979-b2fa-b9adc351b8cc <87239823+c86ec23b-fef1-4979-b2fa-b9adc351b8cc@users.noreply.github.com> Date: Tue, 10 Feb 2026 23:15:56 +0200 Subject: [PATCH 8/8] FOV + name fix if overridden by gamemode --- src/Client.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Client.ts b/src/Client.ts index 08df2ad2..1ab9bfd7 100644 --- a/src/Client.ts +++ b/src/Client.ts @@ -494,6 +494,7 @@ export default class Client { this.camera.cameraData.FOV = 0.35; } else { this.camera.setLevel(30); + this.camera.cameraData.FOV = 0.35; } this.camera.cameraData.statsAvailable = 0; @@ -541,9 +542,9 @@ export default class Client { const tank = camera.cameraData.player = camera.relationsData.owner = camera.relationsData.parent = new TankBody(this.game, camera, this.inputs); tank.setTank(Tank.Basic); + tank.nameData.values.name = name; this.game.arena.spawnPlayer(tank, this); camera.setLevel(camera.cameraData.values.respawnLevel); - tank.nameData.values.name = name; if (this.hasCheated()) this.setHasCheated(true);