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); 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..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 @@ -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..a30fbc03 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(ArenaCloser.BASE_SIZE / this.baseSize); 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; @@ -89,7 +91,6 @@ export default class ArenaCloser extends TankBody { } super.tick(tick); - this.ai.movementSpeed = this.cameraEntity.cameraData.movementSpeed = 80; } } 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/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..dc36ef25 100644 --- a/src/Entity/Tank/Addons.ts +++ b/src/Entity/Tank/Addons.ts @@ -97,12 +97,9 @@ 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; + if (base.ai.state === AIState.idle) base.positionData.angle = angle + rotator.positionData.values.angle; tickBase.call(base, tick); - - if (base.ai.state === AIState.idle) base.positionData.angle = angle + rotator.positionData.values.angle; } rotator.turrets.push(base); @@ -112,7 +109,6 @@ export class Addon { } } - const AutoTurretMiniDefinition: BarrelDefinition = { angle: 0, offset: 0, @@ -134,7 +130,7 @@ const AutoTurretMiniDefinition: BarrelDefinition = { sizeRatio: 1, absorbtionFactor: 1 } -}; +} /** * A smasher-like guard object. @@ -149,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); @@ -174,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; } /** @@ -195,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); @@ -213,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) { @@ -221,6 +208,7 @@ class DomBaseAddon extends Addon { this.createGuard(6, 1.24, 0, 0); } } + /** Smasher addon. */ class SmasherAddon extends Addon { public constructor(owner: BarrelBase) { @@ -229,6 +217,7 @@ class SmasherAddon extends Addon { this.createGuard(6, 1.15, 0, .1); } } + /** Landmine addon. */ class LandmineAddon extends Addon { public constructor(owner: BarrelBase) { @@ -238,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) { @@ -259,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) { @@ -287,6 +270,7 @@ class AutoSmasherAddon extends Addon { new AutoTurret(owner); } } + /** 5 Auto Turrets */ class Auto5Addon extends Addon { public constructor(owner: BarrelBase) { @@ -295,6 +279,7 @@ class Auto5Addon extends Addon { this.createAutoTurrets(5); } } + /** 3 Auto Turrets */ class Auto3Addon extends Addon { public constructor(owner: BarrelBase) { @@ -303,6 +288,7 @@ class Auto3Addon extends Addon { this.createAutoTurrets(3); } } + /** The thing above ranger's barrel. */ class PronouncedAddon extends Addon { public constructor(owner: BarrelBase) { @@ -326,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) { @@ -359,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 be227465..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,22 @@ 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.size = this.baseSize * this.sizeFactor; + 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; this.styleData.values.flags |= StyleFlags.showsAboveParent; @@ -110,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 @@ -133,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.physicsData.size = this.baseSize * this.sizeFactor; - this.ai.aimSpeed = this.turret.bulletAccel; // Top Speed this.ai.movementSpeed = 0; @@ -142,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} @@ -161,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/Barrel.ts b/src/Entity/Tank/Barrel.ts index 3011716c..630576f7 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) { @@ -215,23 +215,8 @@ 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/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 b69fe4ac..a963c1bd 100644 --- a/src/Entity/Tank/TankBody.ts +++ b/src/Entity/Tank/TankBody.ts @@ -39,10 +39,9 @@ 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 }; +export type BarrelBase = ObjectEntity & { cameraEntity: CameraEntity, reloadTime: number, inputs: Inputs }; /** * The Tank Body, which could also be called the Player class, converts defined @@ -110,11 +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; @@ -154,6 +148,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 +179,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 +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.cameraEntity.sizeFactor; - 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/Native/Camera.ts b/src/Native/Camera.ts index 364934d5..bedff207 100644 --- a/src/Native/Camera.ts +++ b/src/Native/Camera.ts @@ -41,25 +41,31 @@ 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; /** 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 (this.getClient()?.inputs.isPossessing) return; // TODO rework possession logic + + if (TankBody.isTank(player)) { + const scaleFactor = Math.pow(1.01, level - previousLevel); + player.scale(scaleFactor); + + if (isMaxLevel) { + player.scoreData.score = levelScore; + player.scoreReward = levelScore; } } @@ -69,7 +75,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; @@ -204,7 +209,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); } }