From 76700a542ba0b4536293679082b721f284503532 Mon Sep 17 00:00:00 2001 From: Supalosa Date: Sun, 14 Apr 2024 23:41:15 +1000 Subject: [PATCH 001/141] add max melee gear --- assets.md | 16 ++- .../images/equipment/Amulet_of_torture.png | Bin 0 -> 286 bytes src/assets/images/equipment/Infernal_cape.png | Bin 0 -> 779 bytes .../images/equipment/Primordial_boots.png | Bin 0 -> 748 bytes .../images/equipment/Scythe_of_vitur.png | Bin 0 -> 369 bytes .../images/equipment/Torva_full_helm.png | Bin 0 -> 624 bytes .../images/equipment/Torva_platebody.png | Bin 0 -> 621 bytes .../images/equipment/Torva_platelegs.png | Bin 0 -> 472 bytes src/assets/sounds/scythe_swing_2524.ogg | Bin 0 -> 5702 bytes src/content/equipment/InfernalCape.ts | 53 ++++++++++ src/content/equipment/MasoriMaskF.ts | 4 +- src/content/equipment/PrimordialBoots.ts | 54 ++++++++++ src/content/equipment/TorvaFullhelm.ts | 53 ++++++++++ src/content/equipment/TorvaPlatebody.ts | 53 ++++++++++ src/content/equipment/TorvaPlatelegs.ts | 53 ++++++++++ src/content/inferno/js/InfernoLoadout.ts | 57 +++++++++++ src/content/weapons/ScytheOfVitur.ts | 94 ++++++++++++++++++ src/index.html | 1 + src/sdk/AttackStylesController.ts | 32 +++++- src/sdk/ItemName.ts | 7 ++ src/sdk/Player.ts | 18 ++-- src/sdk/Unit.ts | 5 + src/sdk/gear/Weapon.ts | 9 +- src/sdk/rendering/GLTFAnimationConstants.ts | 16 +-- src/sdk/utils/Assets.ts | 6 ++ src/sdk/weapons/MeleeWeapon.ts | 8 +- src/sdk/weapons/Projectile.ts | 8 +- src/sdk/weapons/RangedWeapon.ts | 8 +- 28 files changed, 521 insertions(+), 34 deletions(-) create mode 100644 src/assets/images/equipment/Amulet_of_torture.png create mode 100644 src/assets/images/equipment/Infernal_cape.png create mode 100644 src/assets/images/equipment/Primordial_boots.png create mode 100644 src/assets/images/equipment/Scythe_of_vitur.png create mode 100644 src/assets/images/equipment/Torva_full_helm.png create mode 100644 src/assets/images/equipment/Torva_platebody.png create mode 100644 src/assets/images/equipment/Torva_platelegs.png create mode 100644 src/assets/sounds/scythe_swing_2524.ogg create mode 100644 src/content/equipment/InfernalCape.ts create mode 100644 src/content/equipment/PrimordialBoots.ts create mode 100644 src/content/equipment/TorvaFullhelm.ts create mode 100644 src/content/equipment/TorvaPlatebody.ts create mode 100644 src/content/equipment/TorvaPlatelegs.ts create mode 100644 src/content/weapons/ScytheOfVitur.ts diff --git a/assets.md b/assets.md index 428fb412..2171f8ba 100644 --- a/assets.md +++ b/assets.md @@ -28,9 +28,9 @@ Using Dezinator's `osrscachereader` at https://github.com/Dezinater/osrscacherea ### Player models - npm run cmd modelBuilder item 26684,27235,27238,27241,26235,28902,13237,22249,12926,20997,11959 maleModel0 anim 808,819,824,820,822,821,426,5061,7618 name player split + npm run cmd modelBuilder item 26684,27235,27238,27241,26235,28902,13237,22249,12926,20997,11959,28254,28256,28258,20366,22981,13239,25739,21295 maleModel0 anim 808,819,824,820,822,821,426,5061,7618,8057,8056 name player split - where: + which corresponds to - 26684 # tzkal slayer helmet - 27235 # masori mask (f) @@ -43,6 +43,15 @@ Using Dezinator's `osrscachereader` at https://github.com/Dezinater/osrscacherea - 20997 # twisted bow - 12926 # toxic blowpipe - 11959 # black chinchompa + - 28254 # sanguine torva full helm + - 28256 # sanguine torva platebody + - 28258 # sanguine torva platelegs + - 20366 # torture or + - 22981 # ferocious gloves + - 13239 # primordial boots + - 25739 # sanguine scythe of vitur + - 21295 # infernal cape + - 808 # idle - 819 # walk @@ -53,6 +62,9 @@ Using Dezinator's `osrscachereader` at https://github.com/Dezinater/osrscacherea - 426 # fire bow - 5061 # fire blowpipe - 7618 # throw chinchompa + - 8057 # scythe idle + - 8056 # scythe swing + ### NPC models diff --git a/src/assets/images/equipment/Amulet_of_torture.png b/src/assets/images/equipment/Amulet_of_torture.png new file mode 100644 index 0000000000000000000000000000000000000000..13373dd0a3009e3cd3fafb6fcfe973946e38465c GIT binary patch literal 286 zcmeAS@N?(olHy`uVBq!ia0vp^LO?9b!3-oPxSiPmq&xzALR^9L$t>|52_oxaMdk(x zG=|#E3=nAY(VyTYP~)jr?QWE2rI>1|m}stOYwH_tER~`!WNPYcrY5JPq@yp&DkY^P z!^6bDzim5xbttJtAz6M|yWrB(0`J|X>{8r!$B?f`z4=V6&BAiu)%_ew gN@u^`t^UFAeW5`0o%Am!f$m}OboFyt=akR{0KqC|asU7T literal 0 HcmV?d00001 diff --git a/src/assets/images/equipment/Infernal_cape.png b/src/assets/images/equipment/Infernal_cape.png new file mode 100644 index 0000000000000000000000000000000000000000..61cc9da714785c02eb19b33d14d5daebde64c886 GIT binary patch literal 779 zcmV+m1N8ifP)C+xyf|WHGsb8f1TqG?fo2leT!`+2CQJu0vbSV2gEm{TKV`|1 z{gG$qxtA7oekoK>aza|d`JLxEr?*T^1s)oW^43G6?NW(y>+AGrdHF7&Bj6pt5DNG| z>{cw+XepDSr}_M~;u=|VbF{Xy5+qckR|^XgconJ=76)jvMy6@XJWeEJ;lk!7?bWJO ztyHANH`_c`X!I!-rNK)mMI&EMx(SA zi_xzy)4{>)7lOXm1w9-pL)r}?VQvNhQ%hhU=~QL~nA&0*R3N7*s28>9EPJ0U?jBiSxC=bs>+`fB zmEpUwVX;WW133GFoLrbzXJ_SgFPWqUf1hFSc|1m~NnsMg$~<5(hd0tye9HItB1);Jz9sy^)VwZINm<<4;@lOo^QB?o z4uh(!0!jdIffDKus5THkv>!j94K7&cZTt#2E4)&8D@@L_kOVkgU0RFAe8JoqK^5%6 zrwiyWrey<{?aK_Wq1Y!3F`OB%_j?q;b9AhG^V*Kbl@eA3Fo3YsYhcy%5B%FPC zVFm{yYXbw`l=#O5r2~HF4Jtx55C9ONj<)Lw)$SIL@>U~Q$Uh?c_<}6;p-un*002ov JPDHLkV1k#XW(5EM literal 0 HcmV?d00001 diff --git a/src/assets/images/equipment/Primordial_boots.png b/src/assets/images/equipment/Primordial_boots.png new file mode 100644 index 0000000000000000000000000000000000000000..14d8a2386b65150dee2e40efde7335ca544270ad GIT binary patch literal 748 zcmVBG%`6kMm;$=hZ+q$I5&hE4S*UAH8n#xH8p%14OA#5LoO~iGc$M?4Rja{H8C+j zEGjTCJTx#ca2O3fDkp6f4KXb(EG#)MEGuah2`VZzWEBZ6Dk>`|C}0r@CMGaj5eX>+-03Hz$ zA`J~L2>=lh6&MW-8VLy|000aM3LO9d0004nJBbtk0004WQchCTeUZ5CqXM z2Rd6{@0kz;1!h=!+ZbW$VQ9)x6b*-2`s&4aEqagcRMITh^UwYSMNR^sY>cL)J1h+* zmT`1@qp~xavdIo_Ev1uI^~P9S-Z*GVs&2VHqxnX!YU|He>P9B0mKSnbc+whFu`P(Y zOC)M8OKI+Jw`v=0U2}5cFW=Rb%ct3o@*uFbb8u;~oIbwa{CxB*%TbyjYv%X1&vV6) zWhdmsmGXB)Rku8r@DGY%noh!r8Mg>gkTlcv={jDk+m7dr(f)_8C0)0?_yUr)Z~H7v za`NrFvb$f7fA#@E)*U5Gcus`M&lRyJs;0}*oG6ZG20_#`%M0l`?qgbPxsWW&dD7e z6WZF^>uPIDN~(*BDhmtB^Ycn`bBeRG^U~6CQc}_r5>n%0lVhS|!^0zjg2Dm-hX=Pp+R|nOWpVJ|`C=hAr1lS*k1y3p%xEgSpCzX^$@&oZjSE?%uS@ z#{I;_$K8HcRttSQ#wa-Vk+DqF{rG;#D%IC3YD`Q8RBl)aL>+Fr`K}~!*H_uAvyTP! zm7cu4-eR6}z`lpSm}1uN*!Raj+@GgPW?j$hZB~!X^~&4c^8f$Iz&l;|!5%G7P}nhe My85}Sb4q9e0B8@1w*UYD literal 0 HcmV?d00001 diff --git a/src/assets/images/equipment/Torva_full_helm.png b/src/assets/images/equipment/Torva_full_helm.png new file mode 100644 index 0000000000000000000000000000000000000000..432f8dc904ea00bc5c68c96f4d4b0a8733bb897b GIT binary patch literal 624 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 literal 0 HcmV?d00001 diff --git a/src/content/equipment/InfernalCape.ts b/src/content/equipment/InfernalCape.ts new file mode 100644 index 00000000..475eb9af --- /dev/null +++ b/src/content/equipment/InfernalCape.ts @@ -0,0 +1,53 @@ +import { ImageLoader } from "../../sdk/utils/ImageLoader"; +import InventImage from "../../assets/images/equipment/Infernal_cape.png"; +import { ItemName } from "../../sdk/ItemName"; +import { Assets } from "../../sdk/utils/Assets"; +import { Cape } from "../../sdk/gear/Cape"; + +export class InfernalCape extends Cape { + inventorySprite: HTMLImageElement = ImageLoader.createImage(this.inventoryImage); + + get itemName(): ItemName { + return ItemName.INFERNAL_CAPE; + } + get weight(): number { + return 1.814; + } + + get inventoryImage() { + return InventImage; + } + constructor() { + super(); + this.bonuses = { + attack: { + stab: 4, + slash: 4, + crush: 4, + magic: 1, + range: 1, + }, + defence: { + stab: 12, + slash: 12, + crush: 12, + magic: 12, + range: 12, + }, + other: { + meleeStrength: 8, + rangedStrength: 0, + magicDamage: 0, + prayer: 2, + }, + targetSpecific: { + undead: 0, + slayer: 0, + }, + }; + } + + override get model() { + return Assets.getAssetUrl("models/player_infernal_cape.glb"); + } +} diff --git a/src/content/equipment/MasoriMaskF.ts b/src/content/equipment/MasoriMaskF.ts index 934d4845..123e0e39 100644 --- a/src/content/equipment/MasoriMaskF.ts +++ b/src/content/equipment/MasoriMaskF.ts @@ -1,10 +1,10 @@ import { ImageLoader } from "../../sdk/utils/ImageLoader"; import InventImage from "../../assets/images/equipment/Masori_mask_(f).png"; -import { Chest } from "../../sdk/gear/Chest"; import { ItemName } from "../../sdk/ItemName"; import { Assets } from "../../sdk/utils/Assets"; +import { Helmet } from "../../sdk/gear/Helmet"; -export class MasoriMaskF extends Chest { +export class MasoriMaskF extends Helmet { inventorySprite: HTMLImageElement = ImageLoader.createImage(this.inventoryImage); get inventoryImage() { diff --git a/src/content/equipment/PrimordialBoots.ts b/src/content/equipment/PrimordialBoots.ts new file mode 100644 index 00000000..3c1bd81e --- /dev/null +++ b/src/content/equipment/PrimordialBoots.ts @@ -0,0 +1,54 @@ +import { Feet } from "../../sdk/gear/Feet"; +import { ImageLoader } from "../../sdk/utils/ImageLoader"; +import InventImage from "../../assets/images/equipment/Primordial_boots.png"; +import { ItemName } from "../../sdk/ItemName"; +import { Assets } from "../../sdk/utils/Assets"; + +export class PrimordialBoots extends Feet { + inventorySprite: HTMLImageElement = ImageLoader.createImage(this.inventoryImage); + + get inventoryImage() { + return InventImage; + } + get itemName(): ItemName { + return ItemName.PRIMORDIAL_BOOTS; + } + get weight(): number { + return 1.814; + } + + constructor() { + super(); + this.bonuses = { + attack: { + stab: 2, + slash: 2, + crush: 2, + magic: -14, + range: -1, + }, + defence: { + stab: 22, + slash: 22, + crush: 22, + magic: 5, + range: 5, + }, + other: { + meleeStrength: 5, + rangedStrength: 0, + magicDamage: 0, + prayer: 0, + }, + targetSpecific: { + undead: 0, + slayer: 0, + }, + }; + } + + Model = Assets.getAssetUrl("models/player_primordial_boots.glb"); + override get model() { + return this.Model; + } +} diff --git a/src/content/equipment/TorvaFullhelm.ts b/src/content/equipment/TorvaFullhelm.ts new file mode 100644 index 00000000..087d4ebd --- /dev/null +++ b/src/content/equipment/TorvaFullhelm.ts @@ -0,0 +1,53 @@ +import { ImageLoader } from "../../sdk/utils/ImageLoader"; +import InventImage from "../../assets/images/equipment/Torva_full_helm.png"; +import { ItemName } from "../../sdk/ItemName"; +import { Assets } from "../../sdk/utils/Assets"; +import { Helmet } from "../../sdk/gear/Helmet"; + +export class TorvaFullhelm extends Helmet { + inventorySprite: HTMLImageElement = ImageLoader.createImage(this.inventoryImage); + + get itemName(): ItemName { + return ItemName.TORVA_FULL_HELM; + } + get weight(): number { + return 2.721; + } + + get inventoryImage() { + return InventImage; + } + constructor() { + super(); + this.bonuses = { + attack: { + stab: 0, + slash: 0, + crush: 0, + magic: -5, + range: -5, + }, + defence: { + stab: 59, + slash: 60, + crush: 62, + magic: -2, + range: 57, + }, + other: { + meleeStrength: 8, + rangedStrength: 0, + magicDamage: 0, + prayer: 1, + }, + targetSpecific: { + undead: 0, + slayer: 0, + }, + }; + } + + override get model() { + return Assets.getAssetUrl("models/player_sanguine_torva_full_helm.glb"); + } +} diff --git a/src/content/equipment/TorvaPlatebody.ts b/src/content/equipment/TorvaPlatebody.ts new file mode 100644 index 00000000..e4fe3bec --- /dev/null +++ b/src/content/equipment/TorvaPlatebody.ts @@ -0,0 +1,53 @@ +import { Chest } from "../../sdk/gear/Chest"; +import { ImageLoader } from "../../sdk/utils/ImageLoader"; +import InventImage from "../../assets/images/equipment/Torva_platebody.png"; +import { ItemName } from "../../sdk/ItemName"; +import { Assets } from "../../sdk/utils/Assets"; + +export class TorvaPlatebody extends Chest { + inventorySprite: HTMLImageElement = ImageLoader.createImage(this.inventoryImage); + + get itemName(): ItemName { + return ItemName.TORVA_PLATEBODY; + } + get weight(): number { + return 9.979; + } + + get inventoryImage() { + return InventImage; + } + constructor() { + super(); + this.bonuses = { + attack: { + stab: 0, + slash: 0, + crush: 0, + magic: -18, + range: -14, + }, + defence: { + stab: 117, + slash: 111, + crush: 117, + magic: -11, + range: 142, + }, + other: { + meleeStrength: 6, + rangedStrength: 0, + magicDamage: 0, + prayer: 1, + }, + targetSpecific: { + undead: 0, + slayer: 0, + }, + }; + } + + override get model() { + return Assets.getAssetUrl("models/player_sanguine_torva_platebody.glb"); + } +} diff --git a/src/content/equipment/TorvaPlatelegs.ts b/src/content/equipment/TorvaPlatelegs.ts new file mode 100644 index 00000000..c823d088 --- /dev/null +++ b/src/content/equipment/TorvaPlatelegs.ts @@ -0,0 +1,53 @@ +import { ImageLoader } from "../../sdk/utils/ImageLoader"; +import InventImage from "../../assets/images/equipment/Torva_platelegs.png"; +import { ItemName } from "../../sdk/ItemName"; +import { Legs } from "../../sdk/gear/Legs"; +import { Assets } from "../../sdk/utils/Assets"; + +export class TorvaPlatelegs extends Legs { + inventorySprite: HTMLImageElement = ImageLoader.createImage(this.inventoryImage); + + get itemName(): ItemName { + return ItemName.TORVA_PLATELEGS; + } + get weight(): number { + return 9.071; + } + + get inventoryImage() { + return InventImage; + } + constructor() { + super(); + this.bonuses = { + attack: { + stab: 0, + slash: 0, + crush: 0, + magic: -24, + range: -11, + }, + defence: { + stab: 87, + slash: 78, + crush: 79, + magic: -9, + range: 102, + }, + other: { + meleeStrength: 4, + rangedStrength: 0, + magicDamage: 0, + prayer: 1, + }, + targetSpecific: { + undead: 0, + slayer: 0, + }, + }; + } + + override get model() { + return Assets.getAssetUrl("models/player_sanguine_torva_platelegs.glb"); + } +} diff --git a/src/content/inferno/js/InfernoLoadout.ts b/src/content/inferno/js/InfernoLoadout.ts index 5c7008b9..6958f54d 100644 --- a/src/content/inferno/js/InfernoLoadout.ts +++ b/src/content/inferno/js/InfernoLoadout.ts @@ -58,6 +58,12 @@ import { Chest } from "../../../sdk/gear/Chest"; import { Legs } from "../../../sdk/gear/Legs"; import { Player } from "../../../sdk/Player"; import { BlackChinchompa } from "../../weapons/BlackChinchompa"; +import { ScytheOfVitur } from "../../weapons/ScytheOfVitur"; +import { TorvaFullhelm } from "../../equipment/TorvaFullhelm"; +import { InfernalCape } from "../../equipment/InfernalCape"; +import { TorvaPlatebody } from "../../equipment/TorvaPlatebody"; +import { TorvaPlatelegs } from "../../equipment/TorvaPlatelegs"; +import { PrimordialBoots } from "../../equipment/PrimordialBoots"; export class InfernoLoadout { wave: number; @@ -70,6 +76,54 @@ export class InfernoLoadout { this.onTask = onTask; } + loadoutMaxMelee() { + return { + equipment: { + weapon: new ScytheOfVitur(), + offhand: null, + helmet: new TorvaFullhelm(), + necklace: new OccultNecklace(), // TODO + cape: new InfernalCape(), + ammo: new DragonArrows(), + chest: new TorvaPlatebody(), + legs: new TorvaPlatelegs(), + feet: new PrimordialBoots(), + gloves: new ZaryteVambraces(), // TODO + ring: new RingOfSufferingImbued(), // TODO + }, + inventory: [ + new TwistedBow(), + new MasoriBodyF(), + new DizanasQuiver(), + new PegasianBoots(), + new NecklaceOfAnguish(), + new MasoriChapsF(), + new MasoriMaskF(), + new SaradominBrew(), + new SaradominBrew(), + new SaradominBrew(), + new SuperRestore(), + new SuperRestore(), + new SaradominBrew(), + new SaradominBrew(), + new SuperRestore(), + new SuperRestore(), + new SaradominBrew(), + new SaradominBrew(), + new SuperRestore(), + new SuperRestore(), + new SaradominBrew(), + new SaradominBrew(), + new SuperRestore(), + new SuperRestore(), + new BastionPotion(), + new StaminaPotion(), + new SuperRestore(), + new SuperRestore(), + ], + }; + } + loadoutMaxTbowSpeedrunner() { return { ...this.loadoutMaxTbow(), @@ -407,6 +461,9 @@ export class InfernoLoadout { case "rcb": loadout = this.loadoutRcb(); break; + case "max_melee": + loadout = this.loadoutMaxMelee(); + break; } if (this.wave > 66) { diff --git a/src/content/weapons/ScytheOfVitur.ts b/src/content/weapons/ScytheOfVitur.ts new file mode 100644 index 00000000..6d911e2c --- /dev/null +++ b/src/content/weapons/ScytheOfVitur.ts @@ -0,0 +1,94 @@ +import ScytheInventImage from "../../assets/images/weapons/scytheOfVitur.png"; +import { MeleeWeapon } from "../../sdk/weapons/MeleeWeapon"; +import { ItemName } from "../../sdk/ItemName"; +import { AttackStyle, AttackStyleTypes } from "../../sdk/AttackStylesController"; +import { Assets } from "../../sdk/utils/Assets"; +import { PlayerAnimationIndices } from "../../sdk/rendering/GLTFAnimationConstants"; +import { Sound } from "../../sdk/utils/SoundCache"; + +import ScytheAttackSound from "../../assets/sounds/scythe_swing_2524.ogg"; + +export class ScytheOfVitur extends MeleeWeapon { + constructor() { + super(); + + this.bonuses = { + attack: { + stab: 70, + slash: 125, + crush: 30, + magic: -6, + range: 0, + }, + defence: { + stab: -2, + slash: 8, + crush: 10, + magic: 0, + range: 0, + }, + other: { + meleeStrength: 75, + rangedStrength: 0, + magicDamage: 0, + prayer: 0, + }, + targetSpecific: { + undead: 0, + slayer: 0, + }, + }; + } + + attackStyles() { + return [AttackStyle.REAP, AttackStyle.AGGRESSIVESLASH, AttackStyle.AGGRESSIVECRUSH, AttackStyle.DEFENSIVE]; + } + + attackStyleCategory(): AttackStyleTypes { + return AttackStyleTypes.SCYTHE; + } + + defaultStyle(): AttackStyle { + return AttackStyle.AGGRESSIVESLASH; + } + + get itemName(): ItemName { + return ItemName.SCYTHE_OF_VITUR; + } + + get isTwoHander(): boolean { + return true; + } + + hasSpecialAttack(): boolean { + return false; + } + + get attackRange() { + return 1; + } + + get attackSpeed() { + return 5; + } + + get inventoryImage() { + return ScytheInventImage; + } + + override get model() { + return Assets.getAssetUrl("models/player_sanguine_scythe_of_vitur.glb"); + } + + override get attackAnimationId() { + return PlayerAnimationIndices.ScytheSwing; + } + + override get idleAnimationId() { + return PlayerAnimationIndices.ScytheIdle; + } + + get attackSound() { + return new Sound(ScytheAttackSound, 0.1); + } +} diff --git a/src/index.html b/src/index.html index afc2ef86..b1492985 100644 --- a/src/index.html +++ b/src/index.html @@ -2130,6 +2130,7 @@ +
= { + [AttackStyle.ACCURATE]: ["range"], + [AttackStyle.RAPID]: ["range"], + // TODO: defence here + [AttackStyle.LONGRANGE]: ["range"], + [AttackStyle.REAP]: ["attack"], + [AttackStyle.AGGRESSIVECRUSH]: ["strength"], + [AttackStyle.AGGRESSIVESLASH]: ["strength"], + // TODO: add different defensives for different weapons + [AttackStyle.DEFENSIVE]: ["defence"], + [AttackStyle.CONTROLLED]: ["attack"], + [AttackStyle.AUTOCAST]: ["attack"], + [AttackStyle.SHORT_FUSE]: ["range"], + [AttackStyle.MEDIUM_FUSE]: ["range"], + // TODO defence here + [AttackStyle.LONG_FUSE]: ["range"], + } + static controller: AttackStylesController = new AttackStylesController(); stylesMap: AttackStyleStorage = {}; @@ -136,4 +155,11 @@ export class AttackStylesController { getWeaponAttackStyle(weapon: Weapon) { return this.stylesMap[weapon.attackStyleCategory()]; } + + getWeaponXpDrops(style: AttackStyle, damage: number, multiplier: number): { xp: number, skill: string}[] { + return [ + ...AttackStylesController.attackStyleXpType[style].map((skill) => ({ xp: damage * multiplier * 4, skill })), + { xp: damage * multiplier * 1.33, skill: 'hitpoint'}, + ]; + } } diff --git a/src/sdk/ItemName.ts b/src/sdk/ItemName.ts index a861a9fc..ea5eb84a 100644 --- a/src/sdk/ItemName.ts +++ b/src/sdk/ItemName.ts @@ -60,4 +60,11 @@ export enum ItemName { MASORI_BODY_F = "Masori body (f)", MASORI_MASK_F = "Masori mask (f)", DIZANAS_QUIVER = "Dizana's Quiver", + TORVA_PLATEBODY = "Torva platebody", + TORVA_PLATELEGS = "Torva platelegs", + TORVA_FULL_HELM = "Torva full helm", + AMULET_OF_TORTURE = "Amulet of torture", + PRIMORDIAL_BOOTS = "Primordial boots", + FEROCIOUS_GLOVES = "Ferocious gloves", + INFERNAL_CAPE = "Infernal cape", } diff --git a/src/sdk/Player.ts b/src/sdk/Player.ts index 9c352306..8752be26 100644 --- a/src/sdk/Player.ts +++ b/src/sdk/Player.ts @@ -32,14 +32,6 @@ import HumanHit from "../assets/sounds/human_hit_513.ogg"; import { Model } from "./rendering/Model"; import { TileMarker } from "../content/TileMarker"; -import SlayerHelmetModel from "../assets/models/male_Tzkal_slayer helmet (i).gltf"; -import TwistedBowModel from "../assets/models/male_Twisted_bow.gltf"; -import ToxicBlowpipeModel from "../assets/models/male_Toxic_blowpipe.gltf"; -import MasoriBodyModel from "../assets/models/male_Masori_body (f).gltf"; -import MasoriChapsModel from "../assets/models/male_Masori_chaps (f).gltf"; -import PegasianBootsModel from "../assets/models/male_Pegasian_boots.gltf"; -import DizanasMaxCapeModel from "../assets/models/male_Dizana's_max cape.gltf"; - import { GLTFModel } from "./rendering/GLTFModel"; import { PlayerAnimationIndices } from "./rendering/GLTFAnimationConstants"; @@ -56,7 +48,6 @@ const PLAYER_ROTATION_RATE_JAU = 64; const CLIENT_TICKS_PER_SECOND = 50; const JAU_PER_RADIAN = 512; const RADIANS_PER_TICK = ((CLIENT_TICKS_PER_SECOND * PLAYER_ROTATION_RATE_JAU) / JAU_PER_RADIAN) * 0.6; -const LOCAL_POINTS_PER_CELL = 128; const ENABLE_POSITION_DEBUG = false; @@ -248,6 +239,9 @@ export class Player extends Unit { }); this.setEffects = completeSetEffects; + if (this.path.length === 0) { + this.currentPoseAnimation = this.getIdlePoseId(); + } this.invalidateModel(); } @@ -520,6 +514,10 @@ export class Player extends Unit { } } + private getIdlePoseId() { + return this.equipment.weapon ? this.equipment.weapon.idleAnimationId : PlayerAnimationIndices.Idle; + } + clientTick(tickPercent) { // based on https://github.com/dennisdev/rs-map-viewer/blob/master/src/mapviewer/webgl/npc/Npc.ts#L115 if (this.path.length === 0) { @@ -583,7 +581,7 @@ export class Player extends Unit { this.region.removeEntity(headTile); } if (this.path.length === 0) { - this.currentPoseAnimation = PlayerAnimationIndices.Idle; + this.currentPoseAnimation = this.getIdlePoseId(); this.restingAngle = this.nextAngle; } else { this.nextAngle = this.getTargetAngle(); diff --git a/src/sdk/Unit.ts b/src/sdk/Unit.ts index 78ef984e..373ad4e5 100644 --- a/src/sdk/Unit.ts +++ b/src/sdk/Unit.ts @@ -729,4 +729,9 @@ export abstract class Unit extends Renderable { get attackAnimationId(): number | null { return null; } + + get xpBonusMultiplier() { + return 1.0; + } } + diff --git a/src/sdk/gear/Weapon.ts b/src/sdk/gear/Weapon.ts index d4a7fbbf..556646cb 100644 --- a/src/sdk/gear/Weapon.ts +++ b/src/sdk/gear/Weapon.ts @@ -12,6 +12,7 @@ import { ItemName } from "../ItemName"; import { AttackStylesController, AttackStyle, AttackStyleTypes } from "../AttackStylesController"; import { Random } from "../Random"; import { Sound, SoundCache } from "../utils/SoundCache"; +import { PlayerAnimationIndices } from "../rendering/GLTFAnimationConstants"; interface EffectivePrayers { magic?: BasePrayer; @@ -179,7 +180,7 @@ export class Weapon extends Equipment { ); } - this.grantXp(from); + this.grantXp(from, to); this.registerProjectile(from, to, bonuses); return true; } @@ -216,7 +217,7 @@ export class Weapon extends Equipment { return false; // weapons implement this at the type tier } - grantXp(from: Unit) { + grantXp(from: Unit, to: Unit) { // weapons implement this at the type tier } @@ -281,4 +282,8 @@ export class Weapon extends Equipment { get attackLandingSound(): Sound | null { return null; } + + get idleAnimationId() { + return PlayerAnimationIndices.Idle; + } } diff --git a/src/sdk/rendering/GLTFAnimationConstants.ts b/src/sdk/rendering/GLTFAnimationConstants.ts index 99b829b0..83681660 100644 --- a/src/sdk/rendering/GLTFAnimationConstants.ts +++ b/src/sdk/rendering/GLTFAnimationConstants.ts @@ -2,11 +2,13 @@ export enum PlayerAnimationIndices { Idle = 0, Walk = 1, - Run, - Rotate180, - StrafeLeft, - StrafeRight, - FireBow, - FireBlowpipe, - ThrowChinchompa, + Run = 2, + Rotate180 = 3, + StrafeLeft =4, + StrafeRight =5, + FireBow =6, + FireBlowpipe =7, + ThrowChinchompa= 8, + ScytheIdle=9, + ScytheSwing =10, } diff --git a/src/sdk/utils/Assets.ts b/src/sdk/utils/Assets.ts index aa1ab2f9..dd957207 100644 --- a/src/sdk/utils/Assets.ts +++ b/src/sdk/utils/Assets.ts @@ -4,11 +4,16 @@ export class Assets { static onProgressFns: ((loaded: number, total: number) => void)[] = []; static onLoadFns: (() => void)[] = []; + + static loadedAssets = {}; /** * Returns the appropriate URL for an asset and also schedules it for preloading. */ static getAssetUrl(asset: string) { const url = `https://assets-soltrainer.netlify.app/${asset}`; + if (Assets.loadedAssets[url]) { + return url; + } Assets.loadingAssetUrls.push(url); Assets.assetCount++; Promise.resolve().then(async () => { @@ -20,6 +25,7 @@ export class Assets { onProgressFns(this.assetCount - this.loadingAssetUrls.length, this.assetCount), ); Assets.loadingAssetUrls = this.loadingAssetUrls.filter((u) => u !== url); + Assets.loadedAssets[url] = true; }); return url; } diff --git a/src/sdk/weapons/MeleeWeapon.ts b/src/sdk/weapons/MeleeWeapon.ts index 5bd2d3d1..9fdff07e 100644 --- a/src/sdk/weapons/MeleeWeapon.ts +++ b/src/sdk/weapons/MeleeWeapon.ts @@ -1,3 +1,4 @@ +import { AttackStylesController } from "../AttackStylesController"; import { EquipmentTypes } from "../Equipment"; import { Weapon, AttackBonuses } from "../gear/Weapon"; import { Unit, UnitTypes } from "../Unit"; @@ -13,10 +14,11 @@ export class MeleeWeapon extends Weapon { return super.attack(from, to, bonuses); } - grantXp(from: Unit) { + grantXp(from: Unit, to: Unit) { if (from.type === UnitTypes.PLAYER && this.damage > 0) { - from.grantXp(new XpDrop("hitpoint", this.damage * 1.33)); - from.grantXp(new XpDrop("attack", this.damage * 4)); + AttackStylesController.controller.getWeaponXpDrops(this.attackStyle(), this.damage, to.xpBonusMultiplier).forEach(({skill, xp}) => { + from.grantXp(new XpDrop(skill, xp)); + }); } } diff --git a/src/sdk/weapons/Projectile.ts b/src/sdk/weapons/Projectile.ts index 0ce400a3..c918caf7 100644 --- a/src/sdk/weapons/Projectile.ts +++ b/src/sdk/weapons/Projectile.ts @@ -135,8 +135,12 @@ export class Projectile extends Renderable { } } + private isMeleeStyle() { + return (this.attackStyle === "slash" || this.attackStyle === "crush" || this.attackStyle === "stab"); + } + private getColor() { - if (this.attackStyle === "slash" || this.attackStyle === "crush" || this.attackStyle === "stab") { + if (this.isMeleeStyle()) { return "#FF0000"; } else if (this.attackStyle === "range") { return "#00FF00"; @@ -173,7 +177,7 @@ export class Projectile extends Renderable { } get visible() { - return this.age >= this.visualDelayTicks && this.age < this.totalDelay; + return !this.isMeleeStyle() && this.age >= this.visualDelayTicks && this.age < this.totalDelay; } getPerceivedLocation(tickPercent: number) { diff --git a/src/sdk/weapons/RangedWeapon.ts b/src/sdk/weapons/RangedWeapon.ts index 531c1f0b..7a0ae801 100644 --- a/src/sdk/weapons/RangedWeapon.ts +++ b/src/sdk/weapons/RangedWeapon.ts @@ -3,6 +3,7 @@ import { XpDrop } from "../XpDrop"; import { Projectile, ProjectileOptions } from "./Projectile"; import { AttackBonuses, Weapon } from "../gear/Weapon"; import { EquipmentTypes } from "../Equipment"; +import { AttackStylesController } from "../AttackStylesController"; export class RangedWeapon extends Weapon { get type() { @@ -19,10 +20,11 @@ export class RangedWeapon extends Weapon { ); } - grantXp(from: Unit) { + grantXp(from: Unit, to: Unit) { if (from.type === UnitTypes.PLAYER && this.damage > 0) { - from.grantXp(new XpDrop("hitpoint", this.damage * 1.33)); - from.grantXp(new XpDrop("range", this.damage * 4)); + AttackStylesController.controller.getWeaponXpDrops(this.attackStyle(), this.damage, to.xpBonusMultiplier).forEach(({skill, xp}) => { + from.grantXp(new XpDrop(skill, xp)); + }); } } From ea4f335cb3ab7ac942e0169eee54b84cc72f4e5b Mon Sep 17 00:00:00 2001 From: Supalosa Date: Mon, 15 Apr 2024 00:10:39 +1000 Subject: [PATCH 002/141] scythe now scans for targets --- src/content/weapons/ScytheOfVitur.ts | 62 +++++++++++++++++++++++++++- src/sdk/Player.ts | 4 +- 2 files changed, 63 insertions(+), 3 deletions(-) diff --git a/src/content/weapons/ScytheOfVitur.ts b/src/content/weapons/ScytheOfVitur.ts index 6d911e2c..3390c0e2 100644 --- a/src/content/weapons/ScytheOfVitur.ts +++ b/src/content/weapons/ScytheOfVitur.ts @@ -7,6 +7,28 @@ import { PlayerAnimationIndices } from "../../sdk/rendering/GLTFAnimationConstan import { Sound } from "../../sdk/utils/SoundCache"; import ScytheAttackSound from "../../assets/sounds/scythe_swing_2524.ogg"; +import { AttackBonuses } from "../../sdk/gear/Weapon"; +import { Unit } from "../../sdk/Unit"; +import { Collision } from "../../sdk/Collision"; + +const EXTRA_HIT_LOCATIONS = [ + [ + [-1, -1], + [1, -1], + ], // North + [ + [1, 1], + [1, -1], + ], // East + [ + [-1, 1], + [1, 1], + ], // South + [ + [-1, 1], + [-1, -1], + ], // West +]; export class ScytheOfVitur extends MeleeWeapon { constructor() { @@ -75,7 +97,45 @@ export class ScytheOfVitur extends MeleeWeapon { get inventoryImage() { return ScytheInventImage; } - + + override attack(from: Unit, to: Unit, bonuses: AttackBonuses) { + const region = from.region; + // As there is no concept of player direction yet, we dynamically calculate this based on the relative location of + // the attacker. + // Find the closest tile on the npc to us. + const targetTile = to.getClosestTileTo(from.location.x, from.location.y); + + const dx = from.location.x - targetTile[0]; + const dy = from.location.y - targetTile[1]; + let direction; + if (dx < 0) { + direction = 1; // East + } else if (dx > 0) { + direction = 3; // West + } else if (dy < 0) { + direction = 2; // South + } else { + direction = 0; // North + } + // Full damage attack, but each subsequent hit does half of the last. + let multiplier = 1.0; + super.attack(from, to, bonuses); + EXTRA_HIT_LOCATIONS[direction].forEach((hit) => { + const xx = from.location.x + hit[0]; + const yy = from.location.y + hit[1]; + const collision = Collision.collidesWithAnyMobs(region, xx, yy, from.size); + if (collision) { + multiplier *= 0.5; + const extraHitBonuses = { + ...bonuses, + overallMultipler: multiplier, + }; + super.attack(from, collision, extraHitBonuses); + } + }); + return true; + } + override get model() { return Assets.getAssetUrl("models/player_sanguine_scythe_of_vitur.glb"); } diff --git a/src/sdk/Player.ts b/src/sdk/Player.ts index 8752be26..2c03f60d 100644 --- a/src/sdk/Player.ts +++ b/src/sdk/Player.ts @@ -396,9 +396,9 @@ export class Player extends Unit { } override playAttackSound() { - if (this.equipment.weapon?.attackSound) { + /*if (this.equipment.weapon?.attackSound) { SoundCache.play(this.equipment.weapon?.attackSound); - } + }*/ } activatePrayers() { From bcdec2dfe08c9bc3040cf0ecbdaf6c8a0b48a9fc Mon Sep 17 00:00:00 2001 From: Supalosa Date: Mon, 15 Apr 2024 00:31:01 +1000 Subject: [PATCH 003/141] empty From 5dbe062a20497b0a73bf3b202a2b9e0a6b21410f Mon Sep 17 00:00:00 2001 From: supalosa Date: Mon, 15 Apr 2024 09:09:18 +1000 Subject: [PATCH 004/141] wip - starting to split inferno and sdk --- assets.md | 1 - src/content/colosseum/assets/sounds/mager.ogg | Bin 0 -> 9285 bytes src/content/colosseum/js/ColosseumLoadout.ts | 102 ++++++++ src/content/colosseum/js/ColosseumRegion.ts | 148 ++++++++++++ src/content/colosseum/js/ColosseumScene.ts | 41 ++++ src/content/colosseum/js/mobs/JalZek.ts | 182 ++++++++++++++ src/content/equipment/InfernalCape.ts | 2 +- src/content/equipment/TorvaFullhelm.ts | 2 +- src/content/equipment/TorvaPlatebody.ts | 2 +- src/content/equipment/TorvaPlatelegs.ts | 2 +- src/content/inferno/js/InfernoRegion.ts | 207 ++++++++++++++++ src/content/weapons/ScytheOfVitur.ts | 2 +- src/index.ts | 225 +----------------- src/sdk/AttackStylesController.ts | 6 +- src/sdk/ContextMenu.ts | 2 +- src/sdk/Region.ts | 4 +- src/sdk/Unit.ts | 1 - src/sdk/Viewport2d.ts | 6 +- src/sdk/Viewport3d.ts | 2 +- src/sdk/rendering/GLTFAnimationConstants.ts | 14 +- src/sdk/utils/Assets.ts | 1 - src/sdk/utils/__mocks__/Assets.ts | 9 +- src/sdk/utils/__mocks__/SoundCache.ts | 12 +- src/sdk/weapons/MeleeWeapon.ts | 8 +- src/sdk/weapons/Projectile.ts | 2 +- src/sdk/weapons/RangedWeapon.ts | 8 +- test/setupFiles.ts | 20 +- 27 files changed, 738 insertions(+), 273 deletions(-) create mode 100644 src/content/colosseum/assets/sounds/mager.ogg create mode 100644 src/content/colosseum/js/ColosseumLoadout.ts create mode 100644 src/content/colosseum/js/ColosseumRegion.ts create mode 100644 src/content/colosseum/js/ColosseumScene.ts create mode 100644 src/content/colosseum/js/mobs/JalZek.ts diff --git a/assets.md b/assets.md index 2171f8ba..9e4be68f 100644 --- a/assets.md +++ b/assets.md @@ -65,7 +65,6 @@ Using Dezinator's `osrscachereader` at https://github.com/Dezinater/osrscacherea - 8057 # scythe idle - 8056 # scythe swing - ### NPC models # Zuk: Idle, Fire, Flinch, Die diff --git a/src/content/colosseum/assets/sounds/mager.ogg b/src/content/colosseum/assets/sounds/mager.ogg new file mode 100644 index 0000000000000000000000000000000000000000..d67eabd92ed0ebb9565207906de75933fab31e0a GIT binary patch literal 9285 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 L5$q%YJ^lX!Z-0m$ literal 0 HcmV?d00001 diff --git a/src/content/colosseum/js/ColosseumLoadout.ts b/src/content/colosseum/js/ColosseumLoadout.ts new file mode 100644 index 00000000..78a7e5a2 --- /dev/null +++ b/src/content/colosseum/js/ColosseumLoadout.ts @@ -0,0 +1,102 @@ +import { UnitOptions } from "../../../sdk/Unit"; + +import { NecklaceOfAnguish } from "../../equipment/NecklaceOfAnguish"; +import { PegasianBoots } from "../../equipment/PegasianBoots"; +import { OccultNecklace } from "../../equipment/OccultNecklace"; +import { RingOfSufferingImbued } from "../../equipment/RingOfSufferingImbued"; +import { DragonArrows } from "../../equipment/DragonArrows"; +import { StaminaPotion } from "../../items/StaminaPotion"; +import { SaradominBrew } from "../../items/SaradominBrew"; +import { SuperRestore } from "../../items/SuperRestore"; +import { ZaryteVambraces } from "../../equipment/ZaryteVambraces"; +import { MasoriMaskF } from "../../equipment/MasoriMaskF"; +import { MasoriBodyF } from "../../equipment/MasoriBodyF"; +import { MasoriChapsF } from "../../equipment/MasoriChapsF"; +import { DizanasQuiver } from "../../equipment/DizanasQuiver"; +import { BastionPotion } from "../../items/BastionPotion"; + +import { TwistedBow } from "../../weapons/TwistedBow"; +import { Player } from "../../../sdk/Player"; +import { ScytheOfVitur } from "../../weapons/ScytheOfVitur"; +import { TorvaFullhelm } from "../../equipment/TorvaFullhelm"; +import { InfernalCape } from "../../equipment/InfernalCape"; +import { TorvaPlatebody } from "../../equipment/TorvaPlatebody"; +import { TorvaPlatelegs } from "../../equipment/TorvaPlatelegs"; +import { PrimordialBoots } from "../../equipment/PrimordialBoots"; + +export class ColosseumLoadout { + wave: number; + loadoutType: string; + onTask: boolean; + + constructor(wave: number, loadoutType: string, onTask: boolean) { + this.wave = wave; + this.loadoutType = loadoutType; + this.onTask = onTask; + } + + loadoutMaxMelee() { + return { + equipment: { + weapon: new ScytheOfVitur(), + offhand: null, + helmet: new TorvaFullhelm(), + necklace: new OccultNecklace(), // TODO + cape: new InfernalCape(), + ammo: new DragonArrows(), + chest: new TorvaPlatebody(), + legs: new TorvaPlatelegs(), + feet: new PrimordialBoots(), + gloves: new ZaryteVambraces(), // TODO + ring: new RingOfSufferingImbued(), // TODO + }, + inventory: [ + new TwistedBow(), + new MasoriBodyF(), + new DizanasQuiver(), + new PegasianBoots(), + new NecklaceOfAnguish(), + new MasoriChapsF(), + new MasoriMaskF(), + new SaradominBrew(), + new SaradominBrew(), + new SaradominBrew(), + new SuperRestore(), + new SuperRestore(), + new SaradominBrew(), + new SaradominBrew(), + new SuperRestore(), + new SuperRestore(), + new SaradominBrew(), + new SaradominBrew(), + new SuperRestore(), + new SuperRestore(), + new SaradominBrew(), + new SaradominBrew(), + new SuperRestore(), + new SuperRestore(), + new BastionPotion(), + new StaminaPotion(), + new SuperRestore(), + new SuperRestore(), + ], + }; + } + + setStats(player: Player) { + player.stats.prayer = 99; + player.currentStats.prayer = 99; + player.stats.defence = 99; + player.currentStats.defence = 99; + } + + getLoadout(): UnitOptions { + let loadout: UnitOptions; + switch (this.loadoutType) { + case "max_melee": + loadout = this.loadoutMaxMelee(); + break; + } + return loadout; + } +} diff --git a/src/content/colosseum/js/ColosseumRegion.ts b/src/content/colosseum/js/ColosseumRegion.ts new file mode 100644 index 00000000..14baf00f --- /dev/null +++ b/src/content/colosseum/js/ColosseumRegion.ts @@ -0,0 +1,148 @@ +"use strict"; + +import InfernoMapImage from "../assets/images/map.png"; + +import { CardinalDirection, Region } from "../../../sdk/Region"; +import { Settings } from "../../../sdk/Settings"; +import { ImageLoader } from "../../../sdk/utils/ImageLoader"; +import { Viewport } from "../../../sdk/Viewport"; +import { JalZek } from "./mobs/JalZek"; + +/* eslint-disable @typescript-eslint/no-explicit-any */ + +export class ColosseumRegion extends Region { + wave: number; + mapImage: HTMLImageElement = ImageLoader.createImage(InfernoMapImage); + + get initialFacing() { + return CardinalDirection.NORTH; + } + + getName() { + return "Inferno"; + } + + get width(): number { + return 51; + } + + get height(): number { + return 57; + } + + rightClickActions(): any[] { + if (this.wave !== 0) { + return []; + } + + return [ + { + text: [ + { text: "Spawn ", fillStyle: "white" }, + { text: "Mager", fillStyle: "red" }, + ], + action: () => { + Viewport.viewport.clickController.yellowClick(); + const x = Viewport.viewport.contextMenu.destinationLocation.x; + const y = Viewport.viewport.contextMenu.destinationLocation.y; + const mob = new JalZek(this, { x, y }, { aggro: Viewport.viewport.player }); + mob.removableWithRightClick = true; + this.addMob(mob); + }, + }, + ]; + } + + initializeAndGetLoadoutType() { + const loadoutSelector = document.getElementById("loadouts") as HTMLInputElement; + loadoutSelector.value = Settings.loadout; + loadoutSelector.addEventListener("change", () => { + Settings.loadout = loadoutSelector.value; + Settings.persistToStorage(); + }); + + return loadoutSelector.value; + } + + initializeAndGetOnTask() { + const onTaskCheckbox = document.getElementById("onTask") as HTMLInputElement; + onTaskCheckbox.checked = Settings.onTask; + onTaskCheckbox.addEventListener("change", () => { + Settings.onTask = onTaskCheckbox.checked; + Settings.persistToStorage(); + }); + return onTaskCheckbox.checked; + } + + initializeAndGetSouthPillar() { + const southPillarCheckbox = document.getElementById("southPillar") as HTMLInputElement; + southPillarCheckbox.checked = Settings.southPillar; + southPillarCheckbox.addEventListener("change", () => { + Settings.southPillar = southPillarCheckbox.checked; + Settings.persistToStorage(); + }); + return southPillarCheckbox.checked; + } + + initializeAndGetWestPillar() { + const westPillarCheckbox = document.getElementById("westPillar") as HTMLInputElement; + westPillarCheckbox.checked = Settings.westPillar; + westPillarCheckbox.addEventListener("change", () => { + Settings.westPillar = westPillarCheckbox.checked; + Settings.persistToStorage(); + }); + return westPillarCheckbox.checked; + } + + initializeAndGetNorthPillar() { + const northPillarCheckbox = document.getElementById("northPillar") as HTMLInputElement; + northPillarCheckbox.checked = Settings.northPillar; + northPillarCheckbox.addEventListener("change", () => { + Settings.northPillar = northPillarCheckbox.checked; + Settings.persistToStorage(); + }); + return northPillarCheckbox.checked; + } + + initializeAndGetUse3dView() { + const use3dViewCheckbox = document.getElementById("use3dView") as HTMLInputElement; + use3dViewCheckbox.checked = Settings.use3dView; + use3dViewCheckbox.addEventListener("change", () => { + Settings.use3dView = use3dViewCheckbox.checked; + Settings.persistToStorage(); + window.location.reload(); + }); + return use3dViewCheckbox.checked; + } + + drawWorldBackground(context: OffscreenCanvasRenderingContext2D, scale: number) { + context.fillStyle = "black"; + context.fillRect(0, 0, 10000000, 10000000); + if (this.mapImage) { + const ctx = context as any; + ctx.webkitImageSmoothingEnabled = false; + ctx.mozImageSmoothingEnabled = false; + context.imageSmoothingEnabled = false; + + context.fillStyle = "white"; + + context.drawImage(this.mapImage, 0, 0, this.width * scale, this.height * scale); + + ctx.webkitImageSmoothingEnabled = true; + ctx.mozImageSmoothingEnabled = true; + context.imageSmoothingEnabled = true; + } + } + + drawDefaultFloor() { + // replaced by an Entity in 3d view + return !Settings.use3dView; + } + + initialiseRegion() { + throw new Error("Method not implemented."); + return { + player: null, + }; + } +} diff --git a/src/content/colosseum/js/ColosseumScene.ts b/src/content/colosseum/js/ColosseumScene.ts new file mode 100644 index 00000000..2652d625 --- /dev/null +++ b/src/content/colosseum/js/ColosseumScene.ts @@ -0,0 +1,41 @@ +"use strict"; +import { Entity } from "../../../sdk/Entity"; + +import { CollisionType } from "../../../sdk/Collision"; +import { Model } from "../../../sdk/rendering/Model"; +import { LineOfSightMask } from "../../../sdk/LineOfSight"; +import { GLTFModel } from "../../../sdk/rendering/GLTFModel"; +import { Assets } from "../../../sdk/utils/Assets"; + +export class ColosseumScene extends Entity { + get collisionType() { + return CollisionType.NONE; + } + + get size() { + return 1; + } + + draw() { + // force empty draw + } + + get color() { + return "#222222"; + } + + get lineOfSight() { + return LineOfSightMask.NONE; + } + + getPerceivedRotation() { + return -Math.PI / 2; + } + + create3dModel(): Model { + return new GLTFModel(this, [Assets.getAssetUrl("models/colosseum.glb")], 1, -2.5, { + x: -6.5, + y: 12.5, + }); + } +} diff --git a/src/content/colosseum/js/mobs/JalZek.ts b/src/content/colosseum/js/mobs/JalZek.ts new file mode 100644 index 00000000..b73d992c --- /dev/null +++ b/src/content/colosseum/js/mobs/JalZek.ts @@ -0,0 +1,182 @@ +"use strict"; + +import { MagicWeapon } from "../../../../sdk/weapons/MagicWeapon"; +import { MeleeWeapon } from "../../../../sdk/weapons/MeleeWeapon"; +import { Mob, AttackIndicators } from "../../../../sdk/Mob"; +import MagerImage from "../../assets/images/mager.png"; +import MagerSound from "../../assets/sounds/mager.ogg"; +import { UnitBonuses } from "../../../../sdk/Unit"; +import { Collision } from "../../../../sdk/Collision"; +import { EntityName } from "../../../../sdk/EntityName"; +import { Projectile } from "../../../../sdk/weapons/Projectile"; +import { InfernoRegion } from "../InfernoRegion"; +import { Random } from "../../../../sdk/Random"; +import { Sound } from "../../../../sdk/utils/SoundCache"; +import HitSound from "../../../../assets/sounds/dragon_hit_410.ogg"; + +import { GLTFModel } from "../../../../sdk/rendering/GLTFModel"; +import { Assets } from "../../../../sdk/utils/Assets"; + +export const MagerModel = Assets.getAssetUrl("models/7699_33000.glb"); + +export class JalZek extends Mob { + shouldRespawnMobs: boolean; + + mobName(): EntityName { + return EntityName.JAL_ZEK; + } + + shouldChangeAggro(projectile: Projectile) { + return this.aggro != projectile.from && this.autoRetaliate; + } + + get combatLevel() { + return 490; + } + + dead() { + super.dead(); + } + + setStats() { + const region = this.region as InfernoRegion; + this.shouldRespawnMobs = region.wave >= 69; + + this.stunned = 1; + + this.weapons = { + stab: new MeleeWeapon(), + magic: new MagicWeapon(), + }; + + // non boosted numbers + this.stats = { + attack: 370, + strength: 510, + defence: 260, + range: 510, + magic: 300, + hitpoint: 220, + }; + + // with boosts + this.currentStats = JSON.parse(JSON.stringify(this.stats)); + } + + get bonuses(): UnitBonuses { + return { + attack: { + stab: 0, + slash: 0, + crush: 0, + magic: 80, + range: 0, + }, + defence: { + stab: 0, + slash: 0, + crush: 0, + magic: 0, + range: 0, + }, + other: { + meleeStrength: 0, + rangedStrength: 0, + magicDamage: 1.0, + prayer: 0, + }, + }; + } + + get attackSpeed() { + return 4; + } + + get attackRange() { + return 15; + } + + get size() { + return 4; + } + + get image() { + return MagerImage; + } + + get sound() { + return new Sound(MagerSound); + } + + hitSound(damaged) { + return new Sound(HitSound, 0.1); + } + + attackStyleForNewAttack() { + return "magic"; + } + + canMeleeIfClose() { + return "stab" as const; + } + + magicMaxHit() { + return 70; + } + + get maxHit() { + return 70; + } + + attackAnimation(tickPercent: number, context) { + context.rotate(tickPercent * Math.PI * 2); + } + + respawnLocation(mobToResurrect: Mob) { + for (let x = 15 + 11; x < 22 + 11; x++) { + for (let y = 10 + 14; y < 23 + 14; y++) { + if (!Collision.collidesWithAnyMobs(this.region, x, y, mobToResurrect.size)) { + if (!Collision.collidesWithAnyEntities(this.region, x, y, mobToResurrect.size)) { + return { x, y }; + } + } + } + } + + return { x: 21, y: 22 }; + } + + attackIfPossible() { + this.attackStyle = this.attackStyleForNewAttack(); + + this.attackFeedback = AttackIndicators.NONE; + + this.hadLOS = this.hasLOS; + this.setHasLOS(); + + if (this.canAttack() === false) { + return; + } + + const isUnderAggro = Collision.collisionMath( + this.location.x, + this.location.y, + this.size, + this.aggro.location.x, + this.aggro.location.y, + 1, + ); + + if (!isUnderAggro && this.hasLOS && this.attackDelay <= 0) { + this.attack() && this.didAttack(); + } + } + + create3dModel() { + return GLTFModel.forRenderable(this, MagerModel, 0.0075); + } + + override get attackAnimationId() { + return 2; + } +} diff --git a/src/content/equipment/InfernalCape.ts b/src/content/equipment/InfernalCape.ts index 475eb9af..3c51839b 100644 --- a/src/content/equipment/InfernalCape.ts +++ b/src/content/equipment/InfernalCape.ts @@ -46,7 +46,7 @@ export class InfernalCape extends Cape { }, }; } - + override get model() { return Assets.getAssetUrl("models/player_infernal_cape.glb"); } diff --git a/src/content/equipment/TorvaFullhelm.ts b/src/content/equipment/TorvaFullhelm.ts index 087d4ebd..a8322f0a 100644 --- a/src/content/equipment/TorvaFullhelm.ts +++ b/src/content/equipment/TorvaFullhelm.ts @@ -46,7 +46,7 @@ export class TorvaFullhelm extends Helmet { }, }; } - + override get model() { return Assets.getAssetUrl("models/player_sanguine_torva_full_helm.glb"); } diff --git a/src/content/equipment/TorvaPlatebody.ts b/src/content/equipment/TorvaPlatebody.ts index e4fe3bec..84e2127c 100644 --- a/src/content/equipment/TorvaPlatebody.ts +++ b/src/content/equipment/TorvaPlatebody.ts @@ -46,7 +46,7 @@ export class TorvaPlatebody extends Chest { }, }; } - + override get model() { return Assets.getAssetUrl("models/player_sanguine_torva_platebody.glb"); } diff --git a/src/content/equipment/TorvaPlatelegs.ts b/src/content/equipment/TorvaPlatelegs.ts index c823d088..00c0846f 100644 --- a/src/content/equipment/TorvaPlatelegs.ts +++ b/src/content/equipment/TorvaPlatelegs.ts @@ -46,7 +46,7 @@ export class TorvaPlatelegs extends Legs { }, }; } - + override get model() { return Assets.getAssetUrl("models/player_sanguine_torva_platelegs.glb"); } diff --git a/src/content/inferno/js/InfernoRegion.ts b/src/content/inferno/js/InfernoRegion.ts index 17c5c51b..b66f8bb2 100644 --- a/src/content/inferno/js/InfernoRegion.ts +++ b/src/content/inferno/js/InfernoRegion.ts @@ -11,6 +11,20 @@ import { JalImKot } from "./mobs/JalImKot"; import { JalMejRah } from "./mobs/JalMejRah"; import { JalXil } from "./mobs/JalXil"; import { JalZek } from "./mobs/JalZek"; +import { Player } from "../../../sdk/Player"; +import { BrowserUtils } from "../../../sdk/utils/BrowserUtils"; +import { InfernoWaves } from "./InfernoWaves"; +import { InfernoLoadout } from "./InfernoLoadout"; +import { InfernoPillar } from "./InfernoPillar"; +import { EntityName } from "../../../sdk/EntityName"; +import { shuffle } from "lodash"; +import { TileMarker } from "../../TileMarker"; +import { TzKalZuk } from "./mobs/TzKalZuk"; +import { ZukShield } from "./ZukShield"; +import { JalTokJad } from "./mobs/JalTokJad"; +import { Wall } from "../../Wall"; +import { Location } from "../../../sdk/Location"; +import { InfernoScene } from "../../InfernoScene"; /* eslint-disable @typescript-eslint/no-explicit-any */ @@ -179,6 +193,199 @@ export class InfernoRegion extends Region { return use3dViewCheckbox.checked; } + initialiseRegion() { + // create player + const player = new Player(this, { + x: parseInt(BrowserUtils.getQueryVar("x")) || 25, + y: parseInt(BrowserUtils.getQueryVar("y")) || 25, + }); + + this.addPlayer(player); + + const loadoutType = this.initializeAndGetLoadoutType(); + const onTask = this.initializeAndGetOnTask(); + const southPillar = this.initializeAndGetSouthPillar(); + const westPillar = this.initializeAndGetWestPillar(); + const northPillar = this.initializeAndGetNorthPillar(); + + this.initializeAndGetUse3dView(); + this.wave = parseInt(BrowserUtils.getQueryVar("wave")); + + if (isNaN(this.wave)) { + this.wave = 62; + } + if (this.wave < 0) { + this.wave = 0; + } + if (this.wave > InfernoWaves.waves.length + 8) { + this.wave = InfernoWaves.waves.length + 8; + } + + const loadout = new InfernoLoadout(this.wave, loadoutType, onTask); + loadout.setStats(player); // flip this around one day + player.setUnitOptions(loadout.getLoadout()); + + if (this.wave < 67 || this.wave >= 70) { + // Add pillars + InfernoPillar.addPillarsToWorld(this, southPillar, westPillar, northPillar); + } + + const randomPillar = (shuffle(this.entities.filter((entity) => entity.entityName() === EntityName.PILLAR)) || [ + null, + ])[0]; // Since we've only added pillars this is safe. Do not move to after movement blockers. + + const bat = BrowserUtils.getQueryVar("bat") || "[]"; + const blob = BrowserUtils.getQueryVar("blob") || "[]"; + const melee = BrowserUtils.getQueryVar("melee") || "[]"; + const ranger = BrowserUtils.getQueryVar("ranger") || "[]"; + const mager = BrowserUtils.getQueryVar("mager") || "[]"; + const replayLink = document.getElementById("replayLink") as HTMLLinkElement; + + function importSpawn() { + try { + JSON.parse(mager).forEach((spawn: number[]) => + this.addMob(new JalZek(this, { x: spawn[0] + 11, y: spawn[1] + 14 }, { aggro: player })), + ); + JSON.parse(ranger).forEach((spawn: number[]) => + this.addMob(new JalXil(this, { x: spawn[0] + 11, y: spawn[1] + 14 }, { aggro: player })), + ); + JSON.parse(melee).forEach((spawn: number[]) => + this.addMob(new JalImKot(this, { x: spawn[0] + 11, y: spawn[1] + 14 }, { aggro: player })), + ); + JSON.parse(blob).forEach((spawn: number[]) => + this.addMob(new JalAk(this, { x: spawn[0] + 11, y: spawn[1] + 14 }, { aggro: player })), + ); + JSON.parse(bat).forEach((spawn: number[]) => + this.addMob(new JalMejRah(this, { x: spawn[0] + 11, y: spawn[1] + 14 }, { aggro: player })), + ); + + InfernoWaves.spawnNibblers(3, this, randomPillar).forEach(this.addMob.bind(this)); + + replayLink.href = `/${window.location.search}`; + } catch (ex) { + console.log("failed to import wave from inferno stats"); + } + } + // Add mobs + if (this.wave === 0) { + // world.getReadyTimer = 0; + player.location = { x: 28, y: 17 }; + this.world.getReadyTimer = -1; + + InfernoWaves.getRandomSpawns().forEach((spawn: Location) => { + [2, 3, 4].forEach((size: number) => { + const tileMarker = new TileMarker(this, spawn, "#FF730073", size, false); + this.addEntity(tileMarker); + }); + }); + + importSpawn(); + } else if (this.wave < 67) { + player.location = { x: 28, y: 17 }; + if (bat != "[]" || blob != "[]" || melee != "[]" || ranger != "[]" || mager != "[]") { + // Backwards compatibility layer for runelite plugin + this.wave = 1; + + importSpawn(); + } else { + // Native approach + const spawns = BrowserUtils.getQueryVar("spawns") + ? JSON.parse(decodeURIComponent(BrowserUtils.getQueryVar("spawns"))) + : InfernoWaves.getRandomSpawns(); + + InfernoWaves.spawn(this, player, randomPillar, spawns, this.wave).forEach(this.addMob.bind(this)); + + const encodedSpawn = encodeURIComponent(JSON.stringify(spawns)); + replayLink.href = `/?wave=${this.wave}&x=${player.location.x}&y=${player.location.y}&spawns=${encodedSpawn}`; + waveInput.value = String(this.wave); + } + } else if (this.wave === 67) { + player.location = { x: 18, y: 25 }; + const jad = new JalTokJad( + this, + { x: 23, y: 27 }, + { aggro: player, attackSpeed: 8, stun: 1, healers: 5, isZukWave: false }, + ); + this.addMob(jad); + } else if (this.wave === 68) { + player.location = { x: 25, y: 27 }; + + const jad1 = new JalTokJad( + this, + { x: 18, y: 24 }, + { aggro: player, attackSpeed: 9, stun: 1, healers: 3, isZukWave: false }, + ); + this.addMob(jad1); + + const jad2 = new JalTokJad( + this, + { x: 28, y: 24 }, + { aggro: player, attackSpeed: 9, stun: 7, healers: 3, isZukWave: false }, + ); + this.addMob(jad2); + + const jad3 = new JalTokJad( + this, + { x: 23, y: 35 }, + { aggro: player, attackSpeed: 9, stun: 4, healers: 3, isZukWave: false }, + ); + this.addMob(jad3); + } else if (this.wave === 69) { + player.location = { x: 25, y: 15 }; + + // spawn zuk + const shield = new ZukShield(this, { x: 23, y: 13 }, { aggro: player }); + this.addMob(shield); + + this.addMob(new TzKalZuk(this, { x: 22, y: 8 }, { aggro: player })); + + this.addEntity(new Wall(this, { x: 21, y: 8 })); + this.addEntity(new Wall(this, { x: 21, y: 7 })); + this.addEntity(new Wall(this, { x: 21, y: 6 })); + this.addEntity(new Wall(this, { x: 21, y: 5 })); + this.addEntity(new Wall(this, { x: 21, y: 4 })); + this.addEntity(new Wall(this, { x: 21, y: 3 })); + this.addEntity(new Wall(this, { x: 21, y: 2 })); + this.addEntity(new Wall(this, { x: 21, y: 1 })); + this.addEntity(new Wall(this, { x: 21, y: 0 })); + this.addEntity(new Wall(this, { x: 29, y: 8 })); + this.addEntity(new Wall(this, { x: 29, y: 7 })); + this.addEntity(new Wall(this, { x: 29, y: 6 })); + this.addEntity(new Wall(this, { x: 29, y: 5 })); + this.addEntity(new Wall(this, { x: 29, y: 4 })); + this.addEntity(new Wall(this, { x: 29, y: 3 })); + this.addEntity(new Wall(this, { x: 29, y: 2 })); + this.addEntity(new Wall(this, { x: 29, y: 1 })); + this.addEntity(new Wall(this, { x: 29, y: 0 })); + + this.addEntity(new TileMarker(this, { x: 14, y: 14 }, "#00FF00", 1, false)); + + this.addEntity(new TileMarker(this, { x: 16, y: 14 }, "#FF0000", 1, false)); + this.addEntity(new TileMarker(this, { x: 17, y: 14 }, "#FF0000", 1, false)); + this.addEntity(new TileMarker(this, { x: 18, y: 14 }, "#FF0000", 1, false)); + + this.addEntity(new TileMarker(this, { x: 20, y: 14 }, "#00FF00", 1, false)); + + this.addEntity(new TileMarker(this, { x: 30, y: 14 }, "#00FF00", 1, false)); + + this.addEntity(new TileMarker(this, { x: 32, y: 14 }, "#FF0000", 1, false)); + this.addEntity(new TileMarker(this, { x: 33, y: 14 }, "#FF0000", 1, false)); + this.addEntity(new TileMarker(this, { x: 34, y: 14 }, "#FF0000", 1, false)); + + this.addEntity(new TileMarker(this, { x: 36, y: 14 }, "#00FF00", 1, false)); + } else if (this.wave === 74) { + player.location = { x: 28, y: 17 }; + importSpawn(); + } + + // Add 3d scene + if (Settings.use3dView) { + this.addEntity(new InfernoScene(this, { x: 0, y: 48 })); + } + + return { player }; + } + drawWorldBackground(context: OffscreenCanvasRenderingContext2D, scale: number) { context.fillStyle = "black"; context.fillRect(0, 0, 10000000, 10000000); diff --git a/src/content/weapons/ScytheOfVitur.ts b/src/content/weapons/ScytheOfVitur.ts index 3390c0e2..e9cf4fa6 100644 --- a/src/content/weapons/ScytheOfVitur.ts +++ b/src/content/weapons/ScytheOfVitur.ts @@ -104,7 +104,7 @@ export class ScytheOfVitur extends MeleeWeapon { // the attacker. // Find the closest tile on the npc to us. const targetTile = to.getClosestTileTo(from.location.x, from.location.y); - + const dx = from.location.x - targetTile[0]; const dy = from.location.y - targetTile[1]; let direction; diff --git a/src/index.ts b/src/index.ts index 8904fbc6..18c32d7a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -6,23 +6,9 @@ import { Settings } from "./sdk/Settings"; import { ImageLoader } from "./sdk/utils/ImageLoader"; import NewRelicBrowser from "new-relic-browser"; import { Viewport } from "./sdk/Viewport"; -import { Player } from "./sdk/Player"; -import { BrowserUtils } from "./sdk/utils/BrowserUtils"; -import { InfernoLoadout } from "./content/inferno/js/InfernoLoadout"; -import { shuffle, filter } from "lodash"; -import { InfernoPillar } from "./content/inferno/js/InfernoPillar"; -import { InfernoWaves } from "./content/inferno/js/InfernoWaves"; -import { JalAk } from "./content/inferno/js/mobs/JalAk"; -import { JalImKot } from "./content/inferno/js/mobs/JalImKot"; -import { JalMejRah } from "./content/inferno/js/mobs/JalMejRah"; -import { JalTokJad } from "./content/inferno/js/mobs/JalTokJad"; -import { JalXil } from "./content/inferno/js/mobs/JalXil"; -import { JalZek } from "./content/inferno/js/mobs/JalZek"; -import { TzKalZuk } from "./content/inferno/js/mobs/TzKalZuk"; -import { ZukShield } from "./content/inferno/js/ZukShield"; +import { filter } from "lodash"; import { InvisibleMovementBlocker } from "./content/MovementBlocker"; import { TileMarker } from "./content/TileMarker"; -import { Wall } from "./content/Wall"; import { EntityName } from "./sdk/EntityName"; import { Mob } from "./sdk/Mob"; import { Location } from "./sdk/Location"; @@ -32,6 +18,7 @@ import { Chrome } from "./sdk/Chrome"; import SpecialAttackBarBackground from "./assets/images/attackstyles/interface/special_attack_background.png"; import { InfernoScene } from "./content/InfernoScene"; +import { Region } from "./sdk/Region"; declare global { interface Window { @@ -41,7 +28,7 @@ declare global { Settings.readFromStorage(); -const selectedRegion = new InfernoRegion(); +const selectedRegion: Region = new InfernoRegion(); // Create world const world = new World(); @@ -49,47 +36,7 @@ world.getReadyTimer = 6; selectedRegion.world = world; world.addRegion(selectedRegion); -// create player -const player = new Player(selectedRegion, { - x: parseInt(BrowserUtils.getQueryVar("x")) || 25, - y: parseInt(BrowserUtils.getQueryVar("y")) || 25, -}); - -selectedRegion.addPlayer(player); - -// const player2 = new Player( -// selectedRegion, -// { x: 30, y: 40 } -// ) -// player2.autoRetaliate = true; -// new Blowpipe().inventoryLeftClick(player2); -// new NecklaceOfAnguish().inventoryLeftClick(player2); -// new PegasianBoots().inventoryLeftClick(player2); -// selectedRegion.addPlayer(player2); - -const loadoutType = selectedRegion.initializeAndGetLoadoutType(); -const onTask = selectedRegion.initializeAndGetOnTask(); -const southPillar = selectedRegion.initializeAndGetSouthPillar(); -const westPillar = selectedRegion.initializeAndGetWestPillar(); -const northPillar = selectedRegion.initializeAndGetNorthPillar(); - -selectedRegion.initializeAndGetUse3dView(); -selectedRegion.wave = parseInt(BrowserUtils.getQueryVar("wave")); - -if (isNaN(selectedRegion.wave)) { - selectedRegion.wave = 62; -} -if (selectedRegion.wave < 0) { - selectedRegion.wave = 0; -} -if (selectedRegion.wave > InfernoWaves.waves.length + 8) { - selectedRegion.wave = InfernoWaves.waves.length + 8; -} - -const loadout = new InfernoLoadout(selectedRegion.wave, loadoutType, onTask); - -loadout.setStats(player); // flip this around one day -player.setUnitOptions(loadout.getLoadout()); +const { player } = selectedRegion.initialiseRegion(); Viewport.setupViewport(selectedRegion); Viewport.viewport.setPlayer(player); @@ -97,15 +44,6 @@ Viewport.viewport.setPlayer(player); ImageLoader.onAllImagesLoaded(() => { MapController.controller.updateOrbsMask(player.currentStats, player.stats); }); -if (selectedRegion.wave < 67 || selectedRegion.wave >= 70) { - // Add pillars - InfernoPillar.addPillarsToWorld(selectedRegion, southPillar, westPillar, northPillar); -} - -const randomPillar = (shuffle( - selectedRegion.entities.filter((entity) => entity.entityName() === EntityName.PILLAR), -) || [null])[0]; // Since we've only added pillars this is safe. Do not move to after movement blockers. - for (let x = 10; x < 41; x++) { selectedRegion.addEntity(new InvisibleMovementBlocker(this, { x, y: 13 })); selectedRegion.addEntity(new InvisibleMovementBlocker(this, { x, y: 44 })); @@ -192,39 +130,6 @@ exportWaveInput.addEventListener("click", () => { window.location.href = url; }); -const bat = BrowserUtils.getQueryVar("bat") || "[]"; -const blob = BrowserUtils.getQueryVar("blob") || "[]"; -const melee = BrowserUtils.getQueryVar("melee") || "[]"; -const ranger = BrowserUtils.getQueryVar("ranger") || "[]"; -const mager = BrowserUtils.getQueryVar("mager") || "[]"; -const replayLink = document.getElementById("replayLink") as HTMLLinkElement; - -function importSpawn() { - try { - JSON.parse(mager).forEach((spawn: number[]) => - selectedRegion.addMob(new JalZek(selectedRegion, { x: spawn[0] + 11, y: spawn[1] + 14 }, { aggro: player })), - ); - JSON.parse(ranger).forEach((spawn: number[]) => - selectedRegion.addMob(new JalXil(selectedRegion, { x: spawn[0] + 11, y: spawn[1] + 14 }, { aggro: player })), - ); - JSON.parse(melee).forEach((spawn: number[]) => - selectedRegion.addMob(new JalImKot(selectedRegion, { x: spawn[0] + 11, y: spawn[1] + 14 }, { aggro: player })), - ); - JSON.parse(blob).forEach((spawn: number[]) => - selectedRegion.addMob(new JalAk(selectedRegion, { x: spawn[0] + 11, y: spawn[1] + 14 }, { aggro: player })), - ); - JSON.parse(bat).forEach((spawn: number[]) => - selectedRegion.addMob(new JalMejRah(selectedRegion, { x: spawn[0] + 11, y: spawn[1] + 14 }, { aggro: player })), - ); - - InfernoWaves.spawnNibblers(3, selectedRegion, randomPillar).forEach(selectedRegion.addMob.bind(selectedRegion)); - - replayLink.href = `/${window.location.search}`; - } catch (ex) { - console.log("failed to import wave from inferno stats"); - } -} - if (Settings.tile_markers) { Settings.tile_markers .map((location: Location) => { @@ -235,128 +140,6 @@ if (Settings.tile_markers) { }); } -// Add 3d scene -if (Settings.use3dView) { - selectedRegion.addEntity(new InfernoScene(selectedRegion, { x: 0, y: 48 })); -} - -// Add mobs -if (selectedRegion.wave === 0) { - // world.getReadyTimer = 0; - player.location = { x: 28, y: 17 }; - world.getReadyTimer = -1; - - InfernoWaves.getRandomSpawns().forEach((spawn: Location) => { - [2, 3, 4].forEach((size: number) => { - const tileMarker = new TileMarker(selectedRegion, spawn, "#FF730073", size, false); - selectedRegion.addEntity(tileMarker); - }); - }); - - importSpawn(); -} else if (selectedRegion.wave < 67) { - player.location = { x: 28, y: 17 }; - - // this.addMob(new JalMejRah(world, {x: 0, y: 0}, { aggro: player})) - - if (bat != "[]" || blob != "[]" || melee != "[]" || ranger != "[]" || mager != "[]") { - // Backwards compatibility layer for runelite plugin - selectedRegion.wave = 1; - - importSpawn(); - } else { - // Native approach - const spawns = BrowserUtils.getQueryVar("spawns") - ? JSON.parse(decodeURIComponent(BrowserUtils.getQueryVar("spawns"))) - : InfernoWaves.getRandomSpawns(); - - InfernoWaves.spawn(selectedRegion, player, randomPillar, spawns, selectedRegion.wave).forEach( - selectedRegion.addMob.bind(selectedRegion), - ); - - const encodedSpawn = encodeURIComponent(JSON.stringify(spawns)); - replayLink.href = `/?wave=${selectedRegion.wave}&x=${player.location.x}&y=${player.location.y}&spawns=${encodedSpawn}`; - waveInput.value = String(selectedRegion.wave); - } -} else if (selectedRegion.wave === 67) { - player.location = { x: 18, y: 25 }; - const jad = new JalTokJad( - selectedRegion, - { x: 23, y: 27 }, - { aggro: player, attackSpeed: 8, stun: 1, healers: 5, isZukWave: false }, - ); - selectedRegion.addMob(jad); -} else if (selectedRegion.wave === 68) { - player.location = { x: 25, y: 27 }; - - const jad1 = new JalTokJad( - selectedRegion, - { x: 18, y: 24 }, - { aggro: player, attackSpeed: 9, stun: 1, healers: 3, isZukWave: false }, - ); - selectedRegion.addMob(jad1); - - const jad2 = new JalTokJad( - selectedRegion, - { x: 28, y: 24 }, - { aggro: player, attackSpeed: 9, stun: 7, healers: 3, isZukWave: false }, - ); - selectedRegion.addMob(jad2); - - const jad3 = new JalTokJad( - selectedRegion, - { x: 23, y: 35 }, - { aggro: player, attackSpeed: 9, stun: 4, healers: 3, isZukWave: false }, - ); - selectedRegion.addMob(jad3); -} else if (selectedRegion.wave === 69) { - player.location = { x: 25, y: 15 }; - - // spawn zuk - const shield = new ZukShield(selectedRegion, { x: 23, y: 13 }, { aggro: player }); - selectedRegion.addMob(shield); - - selectedRegion.addMob(new TzKalZuk(selectedRegion, { x: 22, y: 8 }, { aggro: player })); - - selectedRegion.addEntity(new Wall(selectedRegion, { x: 21, y: 8 })); - selectedRegion.addEntity(new Wall(selectedRegion, { x: 21, y: 7 })); - selectedRegion.addEntity(new Wall(selectedRegion, { x: 21, y: 6 })); - selectedRegion.addEntity(new Wall(selectedRegion, { x: 21, y: 5 })); - selectedRegion.addEntity(new Wall(selectedRegion, { x: 21, y: 4 })); - selectedRegion.addEntity(new Wall(selectedRegion, { x: 21, y: 3 })); - selectedRegion.addEntity(new Wall(selectedRegion, { x: 21, y: 2 })); - selectedRegion.addEntity(new Wall(selectedRegion, { x: 21, y: 1 })); - selectedRegion.addEntity(new Wall(selectedRegion, { x: 21, y: 0 })); - selectedRegion.addEntity(new Wall(selectedRegion, { x: 29, y: 8 })); - selectedRegion.addEntity(new Wall(selectedRegion, { x: 29, y: 7 })); - selectedRegion.addEntity(new Wall(selectedRegion, { x: 29, y: 6 })); - selectedRegion.addEntity(new Wall(selectedRegion, { x: 29, y: 5 })); - selectedRegion.addEntity(new Wall(selectedRegion, { x: 29, y: 4 })); - selectedRegion.addEntity(new Wall(selectedRegion, { x: 29, y: 3 })); - selectedRegion.addEntity(new Wall(selectedRegion, { x: 29, y: 2 })); - selectedRegion.addEntity(new Wall(selectedRegion, { x: 29, y: 1 })); - selectedRegion.addEntity(new Wall(selectedRegion, { x: 29, y: 0 })); - - selectedRegion.addEntity(new TileMarker(selectedRegion, { x: 14, y: 14 }, "#00FF00", 1, false)); - - selectedRegion.addEntity(new TileMarker(selectedRegion, { x: 16, y: 14 }, "#FF0000", 1, false)); - selectedRegion.addEntity(new TileMarker(selectedRegion, { x: 17, y: 14 }, "#FF0000", 1, false)); - selectedRegion.addEntity(new TileMarker(selectedRegion, { x: 18, y: 14 }, "#FF0000", 1, false)); - - selectedRegion.addEntity(new TileMarker(selectedRegion, { x: 20, y: 14 }, "#00FF00", 1, false)); - - selectedRegion.addEntity(new TileMarker(selectedRegion, { x: 30, y: 14 }, "#00FF00", 1, false)); - - selectedRegion.addEntity(new TileMarker(selectedRegion, { x: 32, y: 14 }, "#FF0000", 1, false)); - selectedRegion.addEntity(new TileMarker(selectedRegion, { x: 33, y: 14 }, "#FF0000", 1, false)); - selectedRegion.addEntity(new TileMarker(selectedRegion, { x: 34, y: 14 }, "#FF0000", 1, false)); - - selectedRegion.addEntity(new TileMarker(selectedRegion, { x: 36, y: 14 }, "#00FF00", 1, false)); -} else if (selectedRegion.wave === 74) { - player.location = { x: 28, y: 17 }; - - importSpawn(); -} player.perceivedLocation = player.location; player.destinationLocation = player.location; /// ///////////////////////////////////////////////////////// diff --git a/src/sdk/AttackStylesController.ts b/src/sdk/AttackStylesController.ts index 3954780e..4fd35b45 100644 --- a/src/sdk/AttackStylesController.ts +++ b/src/sdk/AttackStylesController.ts @@ -137,7 +137,7 @@ export class AttackStylesController { [AttackStyle.MEDIUM_FUSE]: ["range"], // TODO defence here [AttackStyle.LONG_FUSE]: ["range"], - } + }; static controller: AttackStylesController = new AttackStylesController(); stylesMap: AttackStyleStorage = {}; @@ -156,10 +156,10 @@ export class AttackStylesController { return this.stylesMap[weapon.attackStyleCategory()]; } - getWeaponXpDrops(style: AttackStyle, damage: number, multiplier: number): { xp: number, skill: string}[] { + getWeaponXpDrops(style: AttackStyle, damage: number, multiplier: number): { xp: number; skill: string }[] { return [ ...AttackStylesController.attackStyleXpType[style].map((skill) => ({ xp: damage * multiplier * 4, skill })), - { xp: damage * multiplier * 1.33, skill: 'hitpoint'}, + { xp: damage * multiplier * 1.33, skill: "hitpoint" }, ]; } } diff --git a/src/sdk/ContextMenu.ts b/src/sdk/ContextMenu.ts index cc83aef3..30f37a63 100644 --- a/src/sdk/ContextMenu.ts +++ b/src/sdk/ContextMenu.ts @@ -30,7 +30,7 @@ export class ContextMenu { setActive() { this.isActive = true; } - + setInactive() { this.isActive = false; } diff --git a/src/sdk/Region.ts b/src/sdk/Region.ts index 7af5fca5..f3c3f55a 100644 --- a/src/sdk/Region.ts +++ b/src/sdk/Region.ts @@ -23,7 +23,7 @@ export enum CardinalDirection { } // Base class for any trainer region. -export class Region { +export abstract class Region { canvas: OffscreenCanvas; players: Player[] = []; @@ -167,6 +167,8 @@ export class Region { }); } + abstract initialiseRegion(): { player: Player }; + // calls preload on all renderable children async preload() { console.log("preloading region", this.entities, this.mobs, this.players); diff --git a/src/sdk/Unit.ts b/src/sdk/Unit.ts index 373ad4e5..3b8cf162 100644 --- a/src/sdk/Unit.ts +++ b/src/sdk/Unit.ts @@ -734,4 +734,3 @@ export abstract class Unit extends Renderable { return 1.0; } } - diff --git a/src/sdk/Viewport2d.ts b/src/sdk/Viewport2d.ts index 539b4404..4ee11b17 100644 --- a/src/sdk/Viewport2d.ts +++ b/src/sdk/Viewport2d.ts @@ -146,7 +146,7 @@ export class Viewport2d implements ViewportDelegate { context.restore(); }); } - + setMapRotation(direction: CardinalDirection) { if (direction === CardinalDirection.SOUTH) { Settings.rotated = "south"; @@ -154,8 +154,8 @@ export class Viewport2d implements ViewportDelegate { Settings.rotated = "north"; } } - + getMapRotation(): number { - return Settings.rotated === "south" ? Math.PI : 0; + return Settings.rotated === "south" ? Math.PI : 0; } } diff --git a/src/sdk/Viewport3d.ts b/src/sdk/Viewport3d.ts index cdef6bac..0833ce3a 100644 --- a/src/sdk/Viewport3d.ts +++ b/src/sdk/Viewport3d.ts @@ -415,7 +415,7 @@ export class Viewport3d implements ViewportDelegate { }, }; } - + setMapRotation(direction: CardinalDirection) { if (direction === CardinalDirection.SOUTH) { this.yaw.rotation.y = Math.PI; diff --git a/src/sdk/rendering/GLTFAnimationConstants.ts b/src/sdk/rendering/GLTFAnimationConstants.ts index 83681660..5fb30a16 100644 --- a/src/sdk/rendering/GLTFAnimationConstants.ts +++ b/src/sdk/rendering/GLTFAnimationConstants.ts @@ -4,11 +4,11 @@ export enum PlayerAnimationIndices { Walk = 1, Run = 2, Rotate180 = 3, - StrafeLeft =4, - StrafeRight =5, - FireBow =6, - FireBlowpipe =7, - ThrowChinchompa= 8, - ScytheIdle=9, - ScytheSwing =10, + StrafeLeft = 4, + StrafeRight = 5, + FireBow = 6, + FireBlowpipe = 7, + ThrowChinchompa = 8, + ScytheIdle = 9, + ScytheSwing = 10, } diff --git a/src/sdk/utils/Assets.ts b/src/sdk/utils/Assets.ts index dd957207..5ff24b3c 100644 --- a/src/sdk/utils/Assets.ts +++ b/src/sdk/utils/Assets.ts @@ -4,7 +4,6 @@ export class Assets { static onProgressFns: ((loaded: number, total: number) => void)[] = []; static onLoadFns: (() => void)[] = []; - static loadedAssets = {}; /** * Returns the appropriate URL for an asset and also schedules it for preloading. diff --git a/src/sdk/utils/__mocks__/Assets.ts b/src/sdk/utils/__mocks__/Assets.ts index 033ba388..82479a62 100644 --- a/src/sdk/utils/__mocks__/Assets.ts +++ b/src/sdk/utils/__mocks__/Assets.ts @@ -1,6 +1,5 @@ - export class Assets { - static getAssetUrl(x: any) { - return x; - } -} \ No newline at end of file + static getAssetUrl(x: any) { + return x; + } +} diff --git a/src/sdk/utils/__mocks__/SoundCache.ts b/src/sdk/utils/__mocks__/SoundCache.ts index 074538eb..3e70e3a7 100644 --- a/src/sdk/utils/__mocks__/SoundCache.ts +++ b/src/sdk/utils/__mocks__/SoundCache.ts @@ -6,10 +6,10 @@ export class Sound { } export class SoundCache { - static preload() { - return; - } - static play() { - return; - } + static preload() { + return; + } + static play() { + return; + } } diff --git a/src/sdk/weapons/MeleeWeapon.ts b/src/sdk/weapons/MeleeWeapon.ts index 9fdff07e..deb7967d 100644 --- a/src/sdk/weapons/MeleeWeapon.ts +++ b/src/sdk/weapons/MeleeWeapon.ts @@ -16,9 +16,11 @@ export class MeleeWeapon extends Weapon { grantXp(from: Unit, to: Unit) { if (from.type === UnitTypes.PLAYER && this.damage > 0) { - AttackStylesController.controller.getWeaponXpDrops(this.attackStyle(), this.damage, to.xpBonusMultiplier).forEach(({skill, xp}) => { - from.grantXp(new XpDrop(skill, xp)); - }); + AttackStylesController.controller + .getWeaponXpDrops(this.attackStyle(), this.damage, to.xpBonusMultiplier) + .forEach(({ skill, xp }) => { + from.grantXp(new XpDrop(skill, xp)); + }); } } diff --git a/src/sdk/weapons/Projectile.ts b/src/sdk/weapons/Projectile.ts index c918caf7..368dda69 100644 --- a/src/sdk/weapons/Projectile.ts +++ b/src/sdk/weapons/Projectile.ts @@ -136,7 +136,7 @@ export class Projectile extends Renderable { } private isMeleeStyle() { - return (this.attackStyle === "slash" || this.attackStyle === "crush" || this.attackStyle === "stab"); + return this.attackStyle === "slash" || this.attackStyle === "crush" || this.attackStyle === "stab"; } private getColor() { diff --git a/src/sdk/weapons/RangedWeapon.ts b/src/sdk/weapons/RangedWeapon.ts index 7a0ae801..3a8e8e1f 100644 --- a/src/sdk/weapons/RangedWeapon.ts +++ b/src/sdk/weapons/RangedWeapon.ts @@ -22,9 +22,11 @@ export class RangedWeapon extends Weapon { grantXp(from: Unit, to: Unit) { if (from.type === UnitTypes.PLAYER && this.damage > 0) { - AttackStylesController.controller.getWeaponXpDrops(this.attackStyle(), this.damage, to.xpBonusMultiplier).forEach(({skill, xp}) => { - from.grantXp(new XpDrop(skill, xp)); - }); + AttackStylesController.controller + .getWeaponXpDrops(this.attackStyle(), this.damage, to.xpBonusMultiplier) + .forEach(({ skill, xp }) => { + from.grantXp(new XpDrop(skill, xp)); + }); } } diff --git a/test/setupFiles.ts b/test/setupFiles.ts index 77a6905b..4ee70619 100644 --- a/test/setupFiles.ts +++ b/test/setupFiles.ts @@ -6,22 +6,22 @@ jest.mock("../src/sdk/utils/Assets"); jest.mock("../src/sdk/utils/SoundCache"); jest.mock("three", () => ({ Scene: class Scene { - public add(): void { - return; - } + public add(): void { + return; + } }, WebGLRenderer: class WebGlRenderer { - public render(): void { - return; - } - public setSize(): void { - return; - } + public render(): void { + return; + } + public setSize(): void { + return; + } }, GLTFLoader: class GLTFLoader { constructor() {} setMeshoptDecoder() {} - } + }, })); import { Random } from "../src/sdk/Random"; From ebee896848ca64609fee9ae6274fceedfa194117 Mon Sep 17 00:00:00 2001 From: Supalosa Date: Mon, 15 Apr 2024 22:57:02 +1000 Subject: [PATCH 005/141] separation of regions including ui elements --- index.d.ts | 4 + package-lock.json | 522 +++++++++++++++++++++--- package.json | 1 + src/content/colosseum/js/mobs/JalZek.ts | 5 - src/content/inferno/js/InfernoRegion.ts | 113 ++++- src/content/inferno/sidebar.html | 104 +++++ src/index.html | 105 +---- src/index.ts | 95 +---- src/sdk/ControlPanelController.ts | 5 - src/sdk/Region.ts | 4 + test/simulations/Drag.test.ts | 16 +- test/simulations/InfernoRanger.test.ts | 12 +- test/simulations/Pathfinding.test.ts | 17 +- test/simulations/ZukLineOfSight.test.ts | 15 +- test/utils/TestRegion.ts | 20 + webpack.config.js | 4 + 16 files changed, 730 insertions(+), 312 deletions(-) create mode 100644 src/content/inferno/sidebar.html create mode 100644 test/utils/TestRegion.ts diff --git a/index.d.ts b/index.d.ts index a2aa8c5d..999d44eb 100644 --- a/index.d.ts +++ b/index.d.ts @@ -15,3 +15,7 @@ declare module "*.gltf" { const value: string; export default value; } +declare module "*.html" { + const value: string; + export default value; +} diff --git a/package-lock.json b/package-lock.json index e293ef69..c409572c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -29,6 +29,7 @@ "eslint-plugin-import": "^2.23.4", "eslint-plugin-node": "^11.1.0", "eslint-plugin-promise": "^5.1.0", + "html-loader": "^4.2.0", "jest": "^27.5.1", "lodash": "^4.17.21", "prettier": "^3.2.5", @@ -1046,29 +1047,56 @@ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@jridgewell/resolve-uri": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz", - "integrity": "sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew==", - "dev": true, + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "engines": { "node": ">=6.0.0" } }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.11", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz", - "integrity": "sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg==", - "dev": true + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.4.tgz", - "integrity": "sha512-vFv9ttIedivx0ux3QSjhgtCVjPZd5l46ZOMDSCwnH1yUO2e964gO8LZGyv2QkqcgR6TnBU1v+1IFqmeoG+0UJQ==", - "dev": true, + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, "node_modules/@nodelib/fs.scandir": { @@ -2556,6 +2584,22 @@ "node": ">=6" } }, + "node_modules/camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "dev": true, + "dependencies": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + } + }, + "node_modules/camel-case/node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, "node_modules/camelcase": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", @@ -2903,6 +2947,18 @@ "node": ">=0.10.0" } }, + "node_modules/clean-css": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz", + "integrity": "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==", + "dev": true, + "dependencies": { + "source-map": "~0.6.0" + }, + "engines": { + "node": ">= 10.0" + } + }, "node_modules/cli-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", @@ -3957,6 +4013,22 @@ "node": ">=8" } }, + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dev": true, + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/dot-case/node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -4028,6 +4100,18 @@ "node": ">=8.6" } }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/envinfo": { "version": "7.8.1", "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz", @@ -5541,6 +5625,68 @@ "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true }, + "node_modules/html-loader": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/html-loader/-/html-loader-4.2.0.tgz", + "integrity": "sha512-OxCHD3yt+qwqng2vvcaPApCEvbx+nXWu+v69TYHx1FO8bffHn/JjHtE3TTQZmHjwvnJe4xxzuecetDVBrQR1Zg==", + "dev": true, + "dependencies": { + "html-minifier-terser": "^7.0.0", + "parse5": "^7.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/html-loader/node_modules/parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dev": true, + "dependencies": { + "entities": "^4.4.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/html-minifier-terser": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-7.2.0.tgz", + "integrity": "sha512-tXgn3QfqPIpGl9o+K5tpcj3/MN4SfLtsx2GWwBC3SSd0tXQGyF3gsSqad8loJgKZGM3ZxbYDd5yhiBIdWpmvLA==", + "dev": true, + "dependencies": { + "camel-case": "^4.1.2", + "clean-css": "~5.3.2", + "commander": "^10.0.0", + "entities": "^4.4.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.15.1" + }, + "bin": { + "html-minifier-terser": "cli.js" + }, + "engines": { + "node": "^14.13.1 || >=16.0.0" + } + }, + "node_modules/html-minifier-terser/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true, + "engines": { + "node": ">=14" + } + }, "node_modules/http-deceiver": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", @@ -7578,6 +7724,21 @@ "url": "https://tidelift.com/funding/github/npm/loglevel" } }, + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dev": true, + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/lower-case/node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -8070,6 +8231,22 @@ "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", "dev": true }, + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dev": true, + "dependencies": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, + "node_modules/no-case/node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, "node_modules/node-forge": { "version": "0.10.0", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", @@ -8472,6 +8649,22 @@ "node": ">=6" } }, + "node_modules/param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "dev": true, + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/param-case/node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -8520,6 +8713,22 @@ "node": ">= 0.8" } }, + "node_modules/pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "dev": true, + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/pascal-case/node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, "node_modules/pascalcase": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", @@ -9395,6 +9604,15 @@ "url": "https://github.com/sponsors/mysticatea" } }, + "node_modules/relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/remove-trailing-separator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", @@ -10174,9 +10392,9 @@ } }, "node_modules/source-map-support": { - "version": "0.5.19", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", - "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -10608,13 +10826,14 @@ } }, "node_modules/terser": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.7.1.tgz", - "integrity": "sha512-b3e+d5JbHAe/JSjwsC3Zn55wsBIM7AsHLjKxT31kGCldgbpFePaFo+PiddtO6uwRZWRw7sPXmAN8dTW61xmnSg==", + "version": "5.30.3", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.30.3.tgz", + "integrity": "sha512-STdUgOUx8rLbMGO9IOwHLpCqolkDITFFQSMYYwKE1N2lY6MVSaeoi10z/EhWxRc6ybqoVmKSkhKYH/XUpl7vSA==", "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", "commander": "^2.20.0", - "source-map": "~0.7.2", - "source-map-support": "~0.5.19" + "source-map-support": "~0.5.20" }, "bin": { "terser": "bin/terser" @@ -10646,12 +10865,15 @@ "webpack": "^5.1.0" } }, - "node_modules/terser/node_modules/source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "node_modules/terser/node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "bin": { + "acorn": "bin/acorn" + }, "engines": { - "node": ">= 8" + "node": ">=0.4.0" } }, "node_modules/test-exclude": { @@ -12927,26 +13149,47 @@ "chalk": "^4.0.0" } }, + "@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "requires": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, "@jridgewell/resolve-uri": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz", - "integrity": "sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew==", - "dev": true + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==" + }, + "@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==" + }, + "@jridgewell/source-map": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "requires": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } }, "@jridgewell/sourcemap-codec": { - "version": "1.4.11", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz", - "integrity": "sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg==", - "dev": true + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" }, "@jridgewell/trace-mapping": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.4.tgz", - "integrity": "sha512-vFv9ttIedivx0ux3QSjhgtCVjPZd5l46ZOMDSCwnH1yUO2e964gO8LZGyv2QkqcgR6TnBU1v+1IFqmeoG+0UJQ==", - "dev": true, + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, "@nodelib/fs.scandir": { @@ -14103,6 +14346,24 @@ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true }, + "camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "dev": true, + "requires": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + }, + "dependencies": { + "tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + } + } + }, "camelcase": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", @@ -14379,6 +14640,15 @@ "static-extend": "^0.1.1" } }, + "clean-css": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz", + "integrity": "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==", + "dev": true, + "requires": { + "source-map": "~0.6.0" + } + }, "cli-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", @@ -15198,6 +15468,24 @@ } } }, + "dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dev": true, + "requires": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + }, + "dependencies": { + "tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + } + } + }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -15254,6 +15542,12 @@ "ansi-colors": "^4.1.1" } }, + "entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true + }, "envinfo": { "version": "7.8.1", "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz", @@ -16427,6 +16721,50 @@ "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true }, + "html-loader": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/html-loader/-/html-loader-4.2.0.tgz", + "integrity": "sha512-OxCHD3yt+qwqng2vvcaPApCEvbx+nXWu+v69TYHx1FO8bffHn/JjHtE3TTQZmHjwvnJe4xxzuecetDVBrQR1Zg==", + "dev": true, + "requires": { + "html-minifier-terser": "^7.0.0", + "parse5": "^7.0.0" + }, + "dependencies": { + "parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dev": true, + "requires": { + "entities": "^4.4.0" + } + } + } + }, + "html-minifier-terser": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-7.2.0.tgz", + "integrity": "sha512-tXgn3QfqPIpGl9o+K5tpcj3/MN4SfLtsx2GWwBC3SSd0tXQGyF3gsSqad8loJgKZGM3ZxbYDd5yhiBIdWpmvLA==", + "dev": true, + "requires": { + "camel-case": "^4.1.2", + "clean-css": "~5.3.2", + "commander": "^10.0.0", + "entities": "^4.4.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.15.1" + }, + "dependencies": { + "commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true + } + } + }, "http-deceiver": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", @@ -17964,6 +18302,23 @@ "integrity": "sha512-G6A/nJLRgWOuuwdNuA6koovfEV1YpqqAG4pRUlFaz3jj2QNZ8M4vBqnVA+HBTmU/AMNUtlOsMmSpF6NyOjztbA==", "dev": true }, + "lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dev": true, + "requires": { + "tslib": "^2.0.3" + }, + "dependencies": { + "tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + } + } + }, "lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -18342,6 +18697,24 @@ "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", "dev": true }, + "no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dev": true, + "requires": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + }, + "dependencies": { + "tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + } + } + }, "node-forge": { "version": "0.10.0", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", @@ -18645,6 +19018,24 @@ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true }, + "param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "dev": true, + "requires": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + }, + "dependencies": { + "tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + } + } + }, "parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -18681,6 +19072,24 @@ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", "dev": true }, + "pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "dev": true, + "requires": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + }, + "dependencies": { + "tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + } + } + }, "pascalcase": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", @@ -19348,6 +19757,12 @@ "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", "dev": true }, + "relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", + "dev": true + }, "remove-trailing-separator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", @@ -19947,9 +20362,9 @@ } }, "source-map-support": { - "version": "0.5.19", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", - "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "requires": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -20293,19 +20708,20 @@ } }, "terser": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.7.1.tgz", - "integrity": "sha512-b3e+d5JbHAe/JSjwsC3Zn55wsBIM7AsHLjKxT31kGCldgbpFePaFo+PiddtO6uwRZWRw7sPXmAN8dTW61xmnSg==", + "version": "5.30.3", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.30.3.tgz", + "integrity": "sha512-STdUgOUx8rLbMGO9IOwHLpCqolkDITFFQSMYYwKE1N2lY6MVSaeoi10z/EhWxRc6ybqoVmKSkhKYH/XUpl7vSA==", "requires": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", "commander": "^2.20.0", - "source-map": "~0.7.2", - "source-map-support": "~0.5.19" + "source-map-support": "~0.5.20" }, "dependencies": { - "source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==" + "acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==" } } }, diff --git a/package.json b/package.json index a8c84774..0b5d944f 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "eslint-plugin-import": "^2.23.4", "eslint-plugin-node": "^11.1.0", "eslint-plugin-promise": "^5.1.0", + "html-loader": "^4.2.0", "jest": "^27.5.1", "lodash": "^4.17.21", "prettier": "^3.2.5", diff --git a/src/content/colosseum/js/mobs/JalZek.ts b/src/content/colosseum/js/mobs/JalZek.ts index b73d992c..2f24f4a4 100644 --- a/src/content/colosseum/js/mobs/JalZek.ts +++ b/src/content/colosseum/js/mobs/JalZek.ts @@ -9,8 +9,6 @@ import { UnitBonuses } from "../../../../sdk/Unit"; import { Collision } from "../../../../sdk/Collision"; import { EntityName } from "../../../../sdk/EntityName"; import { Projectile } from "../../../../sdk/weapons/Projectile"; -import { InfernoRegion } from "../InfernoRegion"; -import { Random } from "../../../../sdk/Random"; import { Sound } from "../../../../sdk/utils/SoundCache"; import HitSound from "../../../../assets/sounds/dragon_hit_410.ogg"; @@ -39,9 +37,6 @@ export class JalZek extends Mob { } setStats() { - const region = this.region as InfernoRegion; - this.shouldRespawnMobs = region.wave >= 69; - this.stunned = 1; this.weapons = { diff --git a/src/content/inferno/js/InfernoRegion.ts b/src/content/inferno/js/InfernoRegion.ts index b66f8bb2..41ef1660 100644 --- a/src/content/inferno/js/InfernoRegion.ts +++ b/src/content/inferno/js/InfernoRegion.ts @@ -17,7 +17,7 @@ import { InfernoWaves } from "./InfernoWaves"; import { InfernoLoadout } from "./InfernoLoadout"; import { InfernoPillar } from "./InfernoPillar"; import { EntityName } from "../../../sdk/EntityName"; -import { shuffle } from "lodash"; +import { filter, shuffle } from "lodash"; import { TileMarker } from "../../TileMarker"; import { TzKalZuk } from "./mobs/TzKalZuk"; import { ZukShield } from "./ZukShield"; @@ -25,6 +25,11 @@ import { JalTokJad } from "./mobs/JalTokJad"; import { Wall } from "../../Wall"; import { Location } from "../../../sdk/Location"; import { InfernoScene } from "../../InfernoScene"; +import { InvisibleMovementBlocker } from "../../MovementBlocker"; + +import SidebarContent from "../sidebar.html"; +import { Mob } from "../../../sdk/Mob"; +import { ControlPanelController } from "../../../sdk/ControlPanelController"; /* eslint-disable @typescript-eslint/no-explicit-any */ @@ -194,6 +199,85 @@ export class InfernoRegion extends Region { } initialiseRegion() { + const waveInput: HTMLInputElement = document.getElementById("waveinput") as HTMLInputElement; + + + const exportWaveInput: HTMLButtonElement = document.getElementById("exportCustomWave") as HTMLButtonElement; + const editWaveInput: HTMLButtonElement = document.getElementById("editWave") as HTMLButtonElement; + + editWaveInput.addEventListener("click", () => { + const magers = filter(this.mobs, (mob: Mob) => { + return mob.mobName() === EntityName.JAL_ZEK; + }).map((mob: Mob) => { + return [mob.location.x - 11, mob.location.y - 14]; + }); + + const rangers = filter(this.mobs, (mob: Mob) => { + return mob.mobName() === EntityName.JAL_XIL; + }).map((mob: Mob) => { + return [mob.location.x - 11, mob.location.y - 14]; + }); + + const meleers = filter(this.mobs, (mob: Mob) => { + return mob.mobName() === EntityName.JAL_IM_KOT; + }).map((mob: Mob) => { + return [mob.location.x - 11, mob.location.y - 14]; + }); + + const blobs = filter(this.mobs, (mob: Mob) => { + return mob.mobName() === EntityName.JAL_AK; + }).map((mob: Mob) => { + return [mob.location.x - 11, mob.location.y - 14]; + }); + + const bats = filter(this.mobs, (mob: Mob) => { + return mob.mobName() === EntityName.JAL_MEJ_RAJ; + }).map((mob: Mob) => { + return [mob.location.x - 11, mob.location.y - 14]; + }); + + const url = `/?wave=0&mager=${JSON.stringify(magers)}&ranger=${JSON.stringify( + rangers, + )}&melee=${JSON.stringify(meleers)}&blob=${JSON.stringify(blobs)}&bat=${JSON.stringify(bats)}©able`; + window.location.href = url; + }); + exportWaveInput.addEventListener("click", () => { + const magers = filter(this.mobs, (mob: Mob) => { + return mob.mobName() === EntityName.JAL_ZEK; + }).map((mob: Mob) => { + return [mob.location.x - 11, mob.location.y - 14]; + }); + + const rangers = filter(this.mobs, (mob: Mob) => { + return mob.mobName() === EntityName.JAL_XIL; + }).map((mob: Mob) => { + return [mob.location.x - 11, mob.location.y - 14]; + }); + + const meleers = filter(this.mobs, (mob: Mob) => { + return mob.mobName() === EntityName.JAL_IM_KOT; + }).map((mob: Mob) => { + return [mob.location.x - 11, mob.location.y - 14]; + }); + + const blobs = filter(this.mobs, (mob: Mob) => { + return mob.mobName() === EntityName.JAL_AK; + }).map((mob: Mob) => { + return [mob.location.x - 11, mob.location.y - 14]; + }); + + const bats = filter(this.mobs, (mob: Mob) => { + return mob.mobName() === EntityName.JAL_MEJ_RAJ; + }).map((mob: Mob) => { + return [mob.location.x - 11, mob.location.y - 14]; + }); + + const url = `/?wave=74&mager=${JSON.stringify(magers)}&ranger=${JSON.stringify(rangers)}&melee=${JSON.stringify( + meleers, + )}&blob=${JSON.stringify(blobs)}&bat=${JSON.stringify(bats)}©able`; + window.location.href = url; + }); + // create player const player = new Player(this, { x: parseInt(BrowserUtils.getQueryVar("x")) || 25, @@ -234,6 +318,15 @@ export class InfernoRegion extends Region { null, ])[0]; // Since we've only added pillars this is safe. Do not move to after movement blockers. + for (let x = 10; x < 41; x++) { + this.addEntity(new InvisibleMovementBlocker(this, { x, y: 13 })); + this.addEntity(new InvisibleMovementBlocker(this, { x, y: 44 })); + } + for (let y = 14; y < 44; y++) { + this.addEntity(new InvisibleMovementBlocker(this, { x: 10, y })); + this.addEntity(new InvisibleMovementBlocker(this, { x: 40, y })); + } + const bat = BrowserUtils.getQueryVar("bat") || "[]"; const blob = BrowserUtils.getQueryVar("blob") || "[]"; const melee = BrowserUtils.getQueryVar("melee") || "[]"; @@ -378,6 +471,19 @@ export class InfernoRegion extends Region { importSpawn(); } + + + document.getElementById("playWaveNum").addEventListener("click", () => { + window.location.href = `/?wave=${waveInput.value || this.wave}`; + }); + + document + .getElementById("pauseResumeLink") + .addEventListener("click", () => (this.world.isPaused ? this.world.startTicking() : this.world.stopTicking())); + + waveInput.addEventListener("focus", () => (ControlPanelController.controller.isUsingExternalUI = true)); + waveInput.addEventListener("focusout", () => (ControlPanelController.controller.isUsingExternalUI = false)); + // Add 3d scene if (Settings.use3dView) { this.addEntity(new InfernoScene(this, { x: 0, y: 48 })); @@ -409,4 +515,9 @@ export class InfernoRegion extends Region { // replaced by an Entity in 3d view return !Settings.use3dView; } + + getSidebarContent() { + console.log('getting sidebar content'); + return SidebarContent; + } } diff --git a/src/content/inferno/sidebar.html b/src/content/inferno/sidebar.html new file mode 100644 index 00000000..54a66256 --- /dev/null +++ b/src/content/inferno/sidebar.html @@ -0,0 +1,104 @@ + +
+
3:30
+ +
+ + + + Replay Wave + + + +
+ + +
+
+ + + + + + + +
+ Custom Mob Mode + + +
+ + Explore Source on GitHub + Join Our Discord + Mob Explanations + + + \ No newline at end of file diff --git a/src/index.html b/src/index.html index b1492985..f746480e 100644 --- a/src/index.html +++ b/src/index.html @@ -2107,63 +2107,7 @@ oncontextmenu="return false" >
-
-
3:30
- -
- - - - Replay Wave - - - -
- - -
-
- - - - - - - -
- Custom Mob Mode - - -
- - Explore Source on GitHub - Join Our Discord - Mob Explanations + Configure key bindings in the settings tab.
Use 3D View (Experimental)
- - - - \ No newline at end of file diff --git a/src/content/items/BastionPotion.ts b/src/content/items/BastionPotion.ts deleted file mode 100644 index ec4cc834..00000000 --- a/src/content/items/BastionPotion.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { ItemName } from "../../sdk/ItemName"; -import { ImageLoader } from "../../sdk/utils/ImageLoader"; -import OneDose from "../../assets/images/potions/Bastion_potion_1.png"; -import TwoDose from "../../assets/images/potions/Bastion_potion_2.png"; -import ThreeDose from "../../assets/images/potions/Bastion_potion_3.png"; -import FourDose from "../../assets/images/potions/Bastion_potion_4.png"; -import Vial from "../../assets/images/potions/Vial.png"; -import { Player } from "../../sdk/Player"; -import { Potion } from "../../sdk/gear/Potion"; - -export class BastionPotion extends Potion { - oneDose: HTMLImageElement = ImageLoader.createImage(OneDose); - twoDose: HTMLImageElement = ImageLoader.createImage(TwoDose); - threeDose: HTMLImageElement = ImageLoader.createImage(ThreeDose); - fourDose: HTMLImageElement = ImageLoader.createImage(FourDose); - - constructor(doses = 4) { - super(); - this.doses = doses; - this.updateInventorySprite(); - } - - get inventoryImage() { - if (this.doses === 4) { - return FourDose; - } else if (this.doses === 3) { - return ThreeDose; - } else if (this.doses === 2) { - return TwoDose; - } else if (this.doses === 1) { - return OneDose; - } - return Vial; - } - get itemName(): ItemName { - return ItemName.BASTION_POTION; - } - - drink(player: Player) { - super.drink(player); - - const rangedBoost = Math.floor(player.stats.range * 0.1) + 4; - player.currentStats.range += rangedBoost; - player.currentStats.range = Math.min(player.currentStats.range, player.stats.range + rangedBoost); - - const defenceBoost = Math.floor(player.stats.defence * 0.15) + 5; - player.currentStats.defence += defenceBoost; - player.currentStats.defence = Math.min(player.currentStats.defence, player.stats.defence + defenceBoost); - } - - updateInventorySprite() { - if (this.doses === 4) { - this.inventorySprite = this.fourDose; - } else if (this.doses === 3) { - this.inventorySprite = this.threeDose; - } else if (this.doses === 2) { - this.inventorySprite = this.twoDose; - } else if (this.doses === 1) { - this.inventorySprite = this.oneDose; - } else { - this.inventorySprite = this.vial; - } - } -} diff --git a/src/content/items/Karambwan.ts b/src/content/items/Karambwan.ts deleted file mode 100644 index d9927fac..00000000 --- a/src/content/items/Karambwan.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { ItemName } from "../../sdk/ItemName"; -import { ImageLoader } from "../../sdk/utils/ImageLoader"; -import KarambwanImage from "../../assets/images/potions/Cooked_karambwan.png"; -import { Food } from "../../sdk/gear/Food"; -import { Player } from "../../sdk/Player"; - -export class Karambwan extends Food { - healAmount = 18; - inventorySprite: HTMLImageElement = ImageLoader.createImage(KarambwanImage); - get inventoryImage() { - return KarambwanImage; - } - get itemName(): ItemName { - return ItemName.KARAMBWAN; - } - inventoryLeftClick(player: Player) { - player.eats.eatComboFood(this); - } -} diff --git a/src/content/items/SaradominBrew.ts b/src/content/items/SaradominBrew.ts deleted file mode 100644 index 510916e8..00000000 --- a/src/content/items/SaradominBrew.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { ItemName } from "../../sdk/ItemName"; -import { ImageLoader } from "../../sdk/utils/ImageLoader"; -import OneDose from "../../assets/images/potions/Saradomin_brew_1.png"; -import TwoDose from "../../assets/images/potions/Saradomin_brew_2.png"; -import ThreeDose from "../../assets/images/potions/Saradomin_brew_3.png"; -import FourDose from "../../assets/images/potions/Saradomin_brew_4.png"; -import Vial from "../../assets/images/potions/Vial.png"; -import { Player } from "../../sdk/Player"; -import { Potion } from "../../sdk/gear/Potion"; - -export class SaradominBrew extends Potion { - oneDose: HTMLImageElement = ImageLoader.createImage(OneDose); - twoDose: HTMLImageElement = ImageLoader.createImage(TwoDose); - threeDose: HTMLImageElement = ImageLoader.createImage(ThreeDose); - fourDose: HTMLImageElement = ImageLoader.createImage(FourDose); - - constructor(doses = 4) { - super(); - this.doses = doses; - this.updateInventorySprite(); - } - get inventoryImage() { - if (this.doses === 4) { - return FourDose; - } else if (this.doses === 3) { - return ThreeDose; - } else if (this.doses === 2) { - return TwoDose; - } else if (this.doses === 1) { - return OneDose; - } - return Vial; - } - get itemName(): ItemName { - return ItemName.SARADOMIN_BREW; - } - - drink(player: Player) { - super.drink(player); - - const healAmount = Math.floor(player.stats.hitpoint * 0.15) + 2; - player.currentStats.hitpoint += healAmount; - player.currentStats.hitpoint = Math.max( - 1, - Math.min(player.currentStats.hitpoint, player.stats.hitpoint + healAmount), - ); - - const defenceBoost = Math.floor(player.currentStats.defence * 0.2) + 2; - const maxDefenceBoost = Math.floor(player.stats.defence * 0.2) + 2; - player.currentStats.defence += defenceBoost; - player.currentStats.defence = Math.max( - 1, - Math.min(player.currentStats.defence, player.stats.defence + maxDefenceBoost), - ); - - const attackNerf = Math.floor(player.currentStats.attack * 0.1) + 2; - player.currentStats.attack -= attackNerf; - player.currentStats.attack = Math.max(1, Math.min(player.currentStats.attack, player.stats.attack + attackNerf)); - - const strengthNerf = Math.floor(player.currentStats.strength * 0.1) + 2; - player.currentStats.strength -= strengthNerf; - player.currentStats.strength = Math.max( - 1, - Math.min(player.currentStats.strength, player.stats.strength + strengthNerf), - ); - - const rangeNerf = Math.floor(player.currentStats.range * 0.1) + 2; - player.currentStats.range -= rangeNerf; - player.currentStats.range = Math.max(1, Math.min(player.currentStats.range, player.stats.range + rangeNerf)); - - const magicNerf = Math.floor(player.currentStats.magic * 0.1) + 2; - player.currentStats.magic -= magicNerf; - player.currentStats.magic = Math.max(1, Math.min(player.currentStats.magic, player.stats.magic + magicNerf)); - } - - updateInventorySprite() { - if (this.doses === 4) { - this.inventorySprite = this.fourDose; - } else if (this.doses === 3) { - this.inventorySprite = this.threeDose; - } else if (this.doses === 2) { - this.inventorySprite = this.twoDose; - } else if (this.doses === 1) { - this.inventorySprite = this.oneDose; - } else { - this.inventorySprite = this.vial; - } - } -} diff --git a/src/content/items/Shark.ts b/src/content/items/Shark.ts deleted file mode 100644 index 78c2cf55..00000000 --- a/src/content/items/Shark.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { ItemName } from "../../sdk/ItemName"; -import { ImageLoader } from "../../sdk/utils/ImageLoader"; -import SharkImage from "../../assets/images/potions/Shark.png"; -import { Food } from "../../sdk/gear/Food"; - -export class Shark extends Food { - healAmount = 20; - inventorySprite: HTMLImageElement = ImageLoader.createImage(SharkImage); - get inventoryImage() { - return SharkImage; - } - get itemName(): ItemName { - return ItemName.SHARK; - } -} diff --git a/src/content/items/StaminaPotion.ts b/src/content/items/StaminaPotion.ts deleted file mode 100644 index e09b99c1..00000000 --- a/src/content/items/StaminaPotion.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { ItemName } from "../../sdk/ItemName"; -import { ImageLoader } from "../../sdk/utils/ImageLoader"; -import OneDose from "../../assets/images/potions/Stamina_potion_1.png"; -import TwoDose from "../../assets/images/potions/Stamina_potion_2.png"; -import ThreeDose from "../../assets/images/potions/Stamina_potion_3.png"; -import FourDose from "../../assets/images/potions/Stamina_potion_4.png"; -import Vial from "../../assets/images/potions/Vial.png"; -import { Player } from "../../sdk/Player"; -import { Potion } from "../../sdk/gear/Potion"; - -export class StaminaPotion extends Potion { - oneDose: HTMLImageElement = ImageLoader.createImage(OneDose); - twoDose: HTMLImageElement = ImageLoader.createImage(TwoDose); - threeDose: HTMLImageElement = ImageLoader.createImage(ThreeDose); - fourDose: HTMLImageElement = ImageLoader.createImage(FourDose); - - constructor(doses = 4) { - super(); - this.doses = doses; - this.updateInventorySprite(); - } - - get inventoryImage() { - if (this.doses === 4) { - return FourDose; - } else if (this.doses === 3) { - return ThreeDose; - } else if (this.doses === 2) { - return TwoDose; - } else if (this.doses === 1) { - return OneDose; - } - return Vial; - } - get itemName(): ItemName { - return ItemName.STAMINA_POTION; - } - - drink(player: Player) { - super.drink(player); - - player.effects.stamina = 200; // 2 minutes = 200 ticks - player.currentStats.run += 2000; - player.currentStats.run = Math.min(Math.max(player.currentStats.run, 0), 10000); - } - - updateInventorySprite() { - if (this.doses === 4) { - this.inventorySprite = this.fourDose; - } else if (this.doses === 3) { - this.inventorySprite = this.threeDose; - } else if (this.doses === 2) { - this.inventorySprite = this.twoDose; - } else if (this.doses === 1) { - this.inventorySprite = this.oneDose; - } else { - this.inventorySprite = this.vial; - } - } -} diff --git a/src/content/items/SuperCombatPotion.ts b/src/content/items/SuperCombatPotion.ts deleted file mode 100644 index feee0d4a..00000000 --- a/src/content/items/SuperCombatPotion.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { ItemName } from "../../sdk/ItemName"; -import { ImageLoader } from "../../sdk/utils/ImageLoader"; -import OneDose from "../../assets/images/potions/Super_combat_potion_1.png"; -import TwoDose from "../../assets/images/potions/Super_combat_potion_2.png"; -import ThreeDose from "../../assets/images/potions/Super_combat_potion_3.png"; -import FourDose from "../../assets/images/potions/Super_combat_potion_4.png"; -import Vial from "../../assets/images/potions/Vial.png"; -import { Player } from "../../sdk/Player"; -import { Potion } from "../../sdk/gear/Potion"; - -export class SuperCombatPotion extends Potion { - oneDose: HTMLImageElement = ImageLoader.createImage(OneDose); - twoDose: HTMLImageElement = ImageLoader.createImage(TwoDose); - threeDose: HTMLImageElement = ImageLoader.createImage(ThreeDose); - fourDose: HTMLImageElement = ImageLoader.createImage(FourDose); - - constructor(doses = 4) { - super(); - this.doses = doses; - this.updateInventorySprite(); - } - - get inventoryImage() { - if (this.doses === 4) { - return FourDose; - } else if (this.doses === 3) { - return ThreeDose; - } else if (this.doses === 2) { - return TwoDose; - } else if (this.doses === 1) { - return OneDose; - } - return Vial; - } - get itemName(): ItemName { - return ItemName.SUPER_COMBAT_POTION; - } - - drink(player: Player) { - super.drink(player); - - const boost = (stat: keyof Player["stats"]) => { - const boost = Math.floor(player.stats[stat] * 0.15) + 5; - player.currentStats[stat] += boost; - player.currentStats[stat] = Math.min(player.currentStats[stat], player.stats[stat] + boost); - } - boost('strength'); - boost('attack'); - boost('defence'); - } - - updateInventorySprite() { - if (this.doses === 4) { - this.inventorySprite = this.fourDose; - } else if (this.doses === 3) { - this.inventorySprite = this.threeDose; - } else if (this.doses === 2) { - this.inventorySprite = this.twoDose; - } else if (this.doses === 1) { - this.inventorySprite = this.oneDose; - } else { - this.inventorySprite = this.vial; - } - } -} diff --git a/src/content/items/SuperRestore.ts b/src/content/items/SuperRestore.ts deleted file mode 100644 index 11021ebf..00000000 --- a/src/content/items/SuperRestore.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { ItemName } from "../../sdk/ItemName"; -import { ImageLoader } from "../../sdk/utils/ImageLoader"; -import OneDose from "../../assets/images/potions/Super_restore_1.png"; -import TwoDose from "../../assets/images/potions/Super_restore_2.png"; -import ThreeDose from "../../assets/images/potions/Super_restore_3.png"; -import FourDose from "../../assets/images/potions/Super_restore_4.png"; -import Vial from "../../assets/images/potions/Vial.png"; -import { Player } from "../../sdk/Player"; -import { Potion } from "../../sdk/gear/Potion"; - -export class SuperRestore extends Potion { - oneDose: HTMLImageElement = ImageLoader.createImage(OneDose); - twoDose: HTMLImageElement = ImageLoader.createImage(TwoDose); - threeDose: HTMLImageElement = ImageLoader.createImage(ThreeDose); - fourDose: HTMLImageElement = ImageLoader.createImage(FourDose); - - constructor(doses = 4) { - super(); - this.doses = doses; - this.updateInventorySprite(); - } - - get inventoryImage() { - if (this.doses === 4) { - return FourDose; - } else if (this.doses === 3) { - return ThreeDose; - } else if (this.doses === 2) { - return TwoDose; - } else if (this.doses === 1) { - return OneDose; - } - return Vial; - } - get itemName(): ItemName { - return ItemName.SUPER_RESTORE; - } - - drink(player: Player) { - super.drink(player); - - const prayerBonus = Math.floor(player.stats.prayer * 0.27) + 8; - player.currentStats.prayer += prayerBonus; - player.currentStats.prayer = Math.min(player.currentStats.prayer, player.stats.prayer); - - if (player.currentStats.attack < player.stats.attack) { - const attackBonus = Math.floor(player.stats.attack * 0.25) + 8; - player.currentStats.attack += attackBonus; - player.currentStats.attack = Math.min(player.currentStats.attack, player.stats.attack); - } - - if (player.currentStats.strength < player.stats.strength) { - const strengthBonus = Math.floor(player.stats.strength * 0.25) + 8; - player.currentStats.strength += strengthBonus; - player.currentStats.strength = Math.min(player.currentStats.strength, player.stats.strength); - } - - if (player.currentStats.range < player.stats.range) { - const rangeBonus = Math.floor(player.stats.range * 0.25) + 8; - player.currentStats.range += rangeBonus; - player.currentStats.range = Math.min(player.currentStats.range, player.stats.range); - } - if (player.currentStats.magic < player.stats.magic) { - const magicBonus = Math.floor(player.stats.magic * 0.25) + 8; - player.currentStats.magic += magicBonus; - player.currentStats.magic = Math.min(player.currentStats.magic, player.stats.magic); - } - } - - updateInventorySprite() { - if (this.doses === 4) { - this.inventorySprite = this.fourDose; - } else if (this.doses === 3) { - this.inventorySprite = this.threeDose; - } else if (this.doses === 2) { - this.inventorySprite = this.twoDose; - } else if (this.doses === 1) { - this.inventorySprite = this.oneDose; - } else { - this.inventorySprite = this.vial; - } - } -} diff --git a/src/content/prayers/Augury.ts b/src/content/prayers/Augury.ts deleted file mode 100644 index 47ed0060..00000000 --- a/src/content/prayers/Augury.ts +++ /dev/null @@ -1,37 +0,0 @@ -"use strict"; - -import { BasePrayer, PrayerGroups } from "../../sdk/BasePrayer"; -import { Settings } from "../../sdk/Settings"; - -export class Augury extends BasePrayer { - get name() { - return "Augury"; - } - - get groups() { - return [PrayerGroups.ACCURACY, PrayerGroups.STRENGTH, PrayerGroups.DEFENCE]; - } - - levelRequirement(): number { - return 77; - } - isOverhead() { - return false; - } - - drainRate(): number { - return 24; - } - - playOnSound() { - if (Settings.playsAudio) { - // new Audio(OnSound).play(); - } - } - - playOffSound() { - if (Settings.playsAudio) { - // new Audio(OffSound).play(); - } - } -} diff --git a/src/content/prayers/BurstOfStrength.ts b/src/content/prayers/BurstOfStrength.ts deleted file mode 100644 index 43842687..00000000 --- a/src/content/prayers/BurstOfStrength.ts +++ /dev/null @@ -1,37 +0,0 @@ -"use strict"; - -import { BasePrayer, PrayerGroups } from "../../sdk/BasePrayer"; -import { Settings } from "../../sdk/Settings"; - -export class BurstOfStrength extends BasePrayer { - get name() { - return "Burst of Strength"; - } - - get groups() { - return [PrayerGroups.STRENGTH]; - } - levelRequirement(): number { - return 4; - } - - drainRate(): number { - return 3; - } - - isOverhead() { - return false; - } - - playOnSound() { - if (Settings.playsAudio) { - // new Audio(OnSound).play(); - } - } - - playOffSound() { - if (Settings.playsAudio) { - // new Audio(OffSound).play(); - } - } -} diff --git a/src/content/prayers/Chivalry.ts b/src/content/prayers/Chivalry.ts deleted file mode 100644 index 8643540e..00000000 --- a/src/content/prayers/Chivalry.ts +++ /dev/null @@ -1,37 +0,0 @@ -"use strict"; - -import { BasePrayer, PrayerGroups } from "../../sdk/BasePrayer"; -import { Settings } from "../../sdk/Settings"; - -export class Chivalry extends BasePrayer { - get name() { - return "Chivalry"; - } - - get groups() { - return [PrayerGroups.ACCURACY, PrayerGroups.STRENGTH, PrayerGroups.DEFENCE]; - } - - levelRequirement(): number { - return 60; - } - drainRate(): number { - return 24; - } - - isOverhead() { - return false; - } - - playOnSound() { - if (Settings.playsAudio) { - // new Audio(OnSound).play(); - } - } - - playOffSound() { - if (Settings.playsAudio) { - // new Audio(OffSound).play(); - } - } -} diff --git a/src/content/prayers/ClarityOfThought.ts b/src/content/prayers/ClarityOfThought.ts deleted file mode 100644 index 843d4999..00000000 --- a/src/content/prayers/ClarityOfThought.ts +++ /dev/null @@ -1,37 +0,0 @@ -"use strict"; - -import { BasePrayer, PrayerGroups } from "../../sdk/BasePrayer"; -import { Settings } from "../../sdk/Settings"; - -export class ClarityOfThought extends BasePrayer { - get name() { - return "Clarity of Thought"; - } - - get groups() { - return [PrayerGroups.ACCURACY]; - } - - levelRequirement(): number { - return 7; - } - drainRate(): number { - return 3; - } - - isOverhead() { - return false; - } - - playOnSound() { - if (Settings.playsAudio) { - // new Audio(OnSound).play(); - } - } - - playOffSound() { - if (Settings.playsAudio) { - // new Audio(OffSound).play(); - } - } -} diff --git a/src/content/prayers/EagleEye.ts b/src/content/prayers/EagleEye.ts deleted file mode 100644 index 84e47bcb..00000000 --- a/src/content/prayers/EagleEye.ts +++ /dev/null @@ -1,37 +0,0 @@ -"use strict"; - -import { BasePrayer, PrayerGroups } from "../../sdk/BasePrayer"; -import { Settings } from "../../sdk/Settings"; - -export class EagleEye extends BasePrayer { - get name() { - return "Eagle Eye"; - } - - get groups() { - return [PrayerGroups.ACCURACY, PrayerGroups.STRENGTH]; - } - levelRequirement(): number { - return 44; - } - - drainRate(): number { - return 12; - } - - isOverhead() { - return false; - } - - playOnSound() { - if (Settings.playsAudio) { - // new Audio(OnSound).play(); - } - } - - playOffSound() { - if (Settings.playsAudio) { - // new Audio(OffSound).play(); - } - } -} diff --git a/src/content/prayers/HawkEye.ts b/src/content/prayers/HawkEye.ts deleted file mode 100644 index 971ec2f4..00000000 --- a/src/content/prayers/HawkEye.ts +++ /dev/null @@ -1,37 +0,0 @@ -"use strict"; - -import { BasePrayer, PrayerGroups } from "../../sdk/BasePrayer"; -import { Settings } from "../../sdk/Settings"; - -export class HawkEye extends BasePrayer { - get name() { - return "Hawk Eye"; - } - - get groups() { - return [PrayerGroups.ACCURACY, PrayerGroups.STRENGTH]; - } - - levelRequirement(): number { - return 26; - } - drainRate(): number { - return 6; - } - - isOverhead() { - return false; - } - - playOnSound() { - if (Settings.playsAudio) { - // new Audio(OnSound).play(); - } - } - - playOffSound() { - if (Settings.playsAudio) { - // new Audio(OffSound).play(); - } - } -} diff --git a/src/content/prayers/ImprovedReflexes.ts b/src/content/prayers/ImprovedReflexes.ts deleted file mode 100644 index 6be2d753..00000000 --- a/src/content/prayers/ImprovedReflexes.ts +++ /dev/null @@ -1,37 +0,0 @@ -"use strict"; - -import { BasePrayer, PrayerGroups } from "../../sdk/BasePrayer"; -import { Settings } from "../../sdk/Settings"; - -export class ImprovedReflexes extends BasePrayer { - get name() { - return "Improved Reflexes"; - } - - get groups() { - return [PrayerGroups.ACCURACY]; - } - - levelRequirement(): number { - return 16; - } - drainRate(): number { - return 6; - } - - isOverhead() { - return false; - } - - playOnSound() { - if (Settings.playsAudio) { - // new Audio(OnSound).play(); - } - } - - playOffSound() { - if (Settings.playsAudio) { - // new Audio(OffSound).play(); - } - } -} diff --git a/src/content/prayers/IncredibleReflexes.ts b/src/content/prayers/IncredibleReflexes.ts deleted file mode 100644 index ffc5f33d..00000000 --- a/src/content/prayers/IncredibleReflexes.ts +++ /dev/null @@ -1,37 +0,0 @@ -"use strict"; - -import { BasePrayer, PrayerGroups } from "../../sdk/BasePrayer"; -import { Settings } from "../../sdk/Settings"; - -export class IncredibleReflexes extends BasePrayer { - get name() { - return "Incredible Reflexes"; - } - - get groups(): PrayerGroups[] { - return [PrayerGroups.ACCURACY]; - } - - levelRequirement(): number { - return 34; - } - drainRate(): number { - return 12; - } - - isOverhead() { - return false; - } - - playOnSound() { - if (Settings.playsAudio) { - // new Audio(OnSound).play(); - } - } - - playOffSound() { - if (Settings.playsAudio) { - // new Audio(OffSound).play(); - } - } -} diff --git a/src/content/prayers/MysticLore.ts b/src/content/prayers/MysticLore.ts deleted file mode 100644 index 7d9214c9..00000000 --- a/src/content/prayers/MysticLore.ts +++ /dev/null @@ -1,37 +0,0 @@ -"use strict"; - -import { BasePrayer, PrayerGroups } from "../../sdk/BasePrayer"; -import { Settings } from "../../sdk/Settings"; - -export class MysticLore extends BasePrayer { - get name() { - return "Mystic Lore"; - } - - get groups(): PrayerGroups[] { - return [PrayerGroups.ACCURACY, PrayerGroups.STRENGTH]; - } - levelRequirement(): number { - return 27; - } - - drainRate(): number { - return 6; - } - - isOverhead() { - return false; - } - - playOnSound() { - if (Settings.playsAudio) { - // new Audio(OnSound).play(); - } - } - - playOffSound() { - if (Settings.playsAudio) { - // new Audio(OffSound).play(); - } - } -} diff --git a/src/content/prayers/MysticMight.ts b/src/content/prayers/MysticMight.ts deleted file mode 100644 index 8540e16c..00000000 --- a/src/content/prayers/MysticMight.ts +++ /dev/null @@ -1,37 +0,0 @@ -"use strict"; - -import { BasePrayer, PrayerGroups } from "../../sdk/BasePrayer"; -import { Settings } from "../../sdk/Settings"; - -export class MysticMight extends BasePrayer { - get name() { - return "Mystic Might"; - } - - get groups() { - return [PrayerGroups.ACCURACY, PrayerGroups.STRENGTH]; - } - - levelRequirement(): number { - return 45; - } - drainRate(): number { - return 12; - } - - isOverhead() { - return false; - } - - playOnSound() { - if (Settings.playsAudio) { - // new Audio(OnSound).play(); - } - } - - playOffSound() { - if (Settings.playsAudio) { - // new Audio(OffSound).play(); - } - } -} diff --git a/src/content/prayers/MysticWill.ts b/src/content/prayers/MysticWill.ts deleted file mode 100644 index c1eb2233..00000000 --- a/src/content/prayers/MysticWill.ts +++ /dev/null @@ -1,36 +0,0 @@ -"use strict"; - -import { BasePrayer, PrayerGroups } from "../../sdk/BasePrayer"; -import { Settings } from "../../sdk/Settings"; - -export class MysticWill extends BasePrayer { - get name() { - return "Mystic Will"; - } - - get groups(): PrayerGroups[] { - return [PrayerGroups.ACCURACY, PrayerGroups.STRENGTH]; - } - levelRequirement(): number { - return 9; - } - drainRate(): number { - return 3; - } - - isOverhead() { - return false; - } - - playOnSound() { - if (Settings.playsAudio) { - // new Audio(OnSound).play(); - } - } - - playOffSound() { - if (Settings.playsAudio) { - // new Audio(OffSound).play(); - } - } -} diff --git a/src/content/prayers/Piety.ts b/src/content/prayers/Piety.ts deleted file mode 100644 index e5756778..00000000 --- a/src/content/prayers/Piety.ts +++ /dev/null @@ -1,38 +0,0 @@ -"use strict"; - -import { BasePrayer, PrayerGroups } from "../../sdk/BasePrayer"; -import { Settings } from "../../sdk/Settings"; - -export class Piety extends BasePrayer { - get name() { - return "Piety"; - } - - get groups() { - return [PrayerGroups.ACCURACY, PrayerGroups.STRENGTH, PrayerGroups.DEFENCE]; - } - - levelRequirement(): number { - return 70; - } - - drainRate(): number { - return 24; - } - - isOverhead() { - return false; - } - - playOnSound() { - if (Settings.playsAudio) { - // new Audio(OnSound).play(); - } - } - - playOffSound() { - if (Settings.playsAudio) { - // new Audio(OffSound).play(); - } - } -} diff --git a/src/content/prayers/Preserve.ts b/src/content/prayers/Preserve.ts deleted file mode 100644 index eca8aaf2..00000000 --- a/src/content/prayers/Preserve.ts +++ /dev/null @@ -1,37 +0,0 @@ -"use strict"; - -import { BasePrayer, PrayerGroups } from "../../sdk/BasePrayer"; -import { Settings } from "../../sdk/Settings"; - -export class Preserve extends BasePrayer { - get name() { - return "Preserve"; - } - - get groups(): PrayerGroups[] { - return [PrayerGroups.PRESERVE]; // TODO: Incorrect - } - - levelRequirement(): number { - return 100; - } - drainRate(): number { - return 2; - } - - isOverhead() { - return false; - } - - playOnSound() { - if (Settings.playsAudio) { - // new Audio(OnSound).play(); - } - } - - playOffSound() { - if (Settings.playsAudio) { - // new Audio(OffSound).play(); - } - } -} diff --git a/src/content/prayers/ProtectItem.ts b/src/content/prayers/ProtectItem.ts deleted file mode 100644 index 6d5a3bd0..00000000 --- a/src/content/prayers/ProtectItem.ts +++ /dev/null @@ -1,37 +0,0 @@ -"use strict"; - -import { BasePrayer, PrayerGroups } from "../../sdk/BasePrayer"; -import { Settings } from "../../sdk/Settings"; - -export class ProtectItem extends BasePrayer { - get name() { - return "Protect Item"; - } - - get groups(): PrayerGroups[] { - return [PrayerGroups.PROTECTITEM]; // TODO: Incorrect - } - - levelRequirement(): number { - return 100; - } - drainRate(): number { - return 2; - } - - isOverhead() { - return false; - } - - playOnSound() { - if (Settings.playsAudio) { - // new Audio(OnSound).play(); - } - } - - playOffSound() { - if (Settings.playsAudio) { - // new Audio(OffSound).play(); - } - } -} diff --git a/src/content/prayers/ProtectMage.ts b/src/content/prayers/ProtectMage.ts deleted file mode 100644 index 530d8568..00000000 --- a/src/content/prayers/ProtectMage.ts +++ /dev/null @@ -1,49 +0,0 @@ -"use strict"; - -import { BasePrayer, PrayerGroups } from "../../sdk/BasePrayer"; -import OverheadImg from "../../assets/images/prayers/mageOver.png"; -import OnSound from "../../assets/sounds/mageOn.ogg"; -import OffSound from "../../assets/sounds/mageOff.ogg"; -import { Settings } from "../../sdk/Settings"; -import { Sound, SoundCache } from "../../sdk/utils/SoundCache"; - -export class ProtectMage extends BasePrayer { - get name() { - return "Protect from Magic"; - } - - get groups(): PrayerGroups[] { - return [PrayerGroups.OVERHEADS]; - } - levelRequirement(): number { - return 37; - } - - drainRate(): number { - return 12; - } - - isOverhead() { - return true; - } - - overheadImageReference() { - return OverheadImg; - } - - feature() { - return "magic"; - } - - playOnSound() { - if (Settings.playsAudio) { - SoundCache.play(new Sound(OnSound, 0.35)); - } - } - - playOffSound() { - if (Settings.playsAudio) { - SoundCache.play(new Sound(OffSound, 0.35)); - } - } -} diff --git a/src/content/prayers/ProtectMelee.ts b/src/content/prayers/ProtectMelee.ts deleted file mode 100644 index 4201ba74..00000000 --- a/src/content/prayers/ProtectMelee.ts +++ /dev/null @@ -1,50 +0,0 @@ -"use strict"; - -import { BasePrayer, PrayerGroups } from "../../sdk/BasePrayer"; -import OverheadImg from "../../assets/images/prayers/meleeOver.png"; - -import OnSound from "../../assets/sounds/meleeOn.ogg"; -import OffSound from "../../assets/sounds/meleeOff.ogg"; -import { Settings } from "../../sdk/Settings"; -import { Sound, SoundCache } from "../../sdk/utils/SoundCache"; - -export class ProtectMelee extends BasePrayer { - get name() { - return "Protect from Melee"; - } - - get groups(): PrayerGroups[] { - return [PrayerGroups.OVERHEADS]; - } - - levelRequirement(): number { - return 43; - } - drainRate(): number { - return 12; - } - - isOverhead() { - return true; - } - - overheadImageReference() { - return OverheadImg; - } - - feature() { - return "melee"; - } - - playOnSound() { - if (Settings.playsAudio) { - SoundCache.play(new Sound(OnSound, 0.35)); - } - } - - playOffSound() { - if (Settings.playsAudio) { - SoundCache.play(new Sound(OffSound, 0.35)); - } - } -} diff --git a/src/content/prayers/ProtectRange.ts b/src/content/prayers/ProtectRange.ts deleted file mode 100644 index 6713b0aa..00000000 --- a/src/content/prayers/ProtectRange.ts +++ /dev/null @@ -1,50 +0,0 @@ -"use strict"; - -import { BasePrayer, PrayerGroups } from "../../sdk/BasePrayer"; -import OverheadImg from "../../assets/images/prayers/rangeOver.png"; - -import OnSound from "../../assets/sounds/rangeOn.ogg"; -import OffSound from "../../assets/sounds/rangeOff.ogg"; -import { Settings } from "../../sdk/Settings"; -import { Sound, SoundCache } from "../../sdk/utils/SoundCache"; - -export class ProtectRange extends BasePrayer { - get name() { - return "Protect from Range"; - } - - get groups(): PrayerGroups[] { - return [PrayerGroups.OVERHEADS]; - } - - levelRequirement(): number { - return 34; - } - drainRate(): number { - return 12; - } - - isOverhead() { - return true; - } - - overheadImageReference() { - return OverheadImg; - } - - feature() { - return "range"; - } - - playOnSound() { - if (Settings.playsAudio) { - SoundCache.play(new Sound(OnSound, 0.35)); - } - } - - playOffSound() { - if (Settings.playsAudio) { - SoundCache.play(new Sound(OffSound, 0.35)); - } - } -} diff --git a/src/content/prayers/RapidHeal.ts b/src/content/prayers/RapidHeal.ts deleted file mode 100644 index 0c68c68a..00000000 --- a/src/content/prayers/RapidHeal.ts +++ /dev/null @@ -1,37 +0,0 @@ -"use strict"; - -import { BasePrayer, PrayerGroups } from "../../sdk/BasePrayer"; -import { Settings } from "../../sdk/Settings"; - -export class RapidHeal extends BasePrayer { - get name() { - return "Rapid Heal"; - } - - get groups(): PrayerGroups[] { - return [PrayerGroups.HEARTS]; - } - - levelRequirement(): number { - return 100; - } - drainRate(): number { - return 2; - } - - isOverhead() { - return false; - } - - playOnSound() { - if (Settings.playsAudio) { - // new Audio(OnSound).play(); - } - } - - playOffSound() { - if (Settings.playsAudio) { - // new Audio(OffSound).play(); - } - } -} diff --git a/src/content/prayers/RapidRestore.ts b/src/content/prayers/RapidRestore.ts deleted file mode 100644 index 38691e9c..00000000 --- a/src/content/prayers/RapidRestore.ts +++ /dev/null @@ -1,37 +0,0 @@ -"use strict"; - -import { BasePrayer, PrayerGroups } from "../../sdk/BasePrayer"; -import { Settings } from "../../sdk/Settings"; - -export class RapidRestore extends BasePrayer { - get name() { - return "Rapid Restore"; - } - - get groups(): PrayerGroups[] { - return [PrayerGroups.HEARTS]; - } - - levelRequirement(): number { - return 100; - } - drainRate(): number { - return 1; - } - - isOverhead() { - return false; - } - - playOnSound() { - if (Settings.playsAudio) { - // new Audio(OnSound).play(); - } - } - - playOffSound() { - if (Settings.playsAudio) { - // new Audio(OffSound).play(); - } - } -} diff --git a/src/content/prayers/Redemption.ts b/src/content/prayers/Redemption.ts deleted file mode 100644 index 7e6d3f3f..00000000 --- a/src/content/prayers/Redemption.ts +++ /dev/null @@ -1,42 +0,0 @@ -"use strict"; - -import { BasePrayer, PrayerGroups } from "../../sdk/BasePrayer"; -import { Settings } from "../../sdk/Settings"; -import OverheadImg from "../../assets/images/prayers/redemptionOver.png"; - -export class Redemption extends BasePrayer { - get name() { - return "Redemption"; - } - - get groups(): PrayerGroups[] { - return [PrayerGroups.OVERHEADS]; - } - - levelRequirement(): number { - return 49; - } - drainRate(): number { - return 6; - } - - isOverhead() { - return true; - } - - overheadImageReference() { - return OverheadImg; - } - - playOnSound() { - if (Settings.playsAudio) { - // new Audio(OnSound).play(); - } - } - - playOffSound() { - if (Settings.playsAudio) { - // new Audio(OffSound).play(); - } - } -} diff --git a/src/content/prayers/Retribution.ts b/src/content/prayers/Retribution.ts deleted file mode 100644 index c693f19c..00000000 --- a/src/content/prayers/Retribution.ts +++ /dev/null @@ -1,37 +0,0 @@ -"use strict"; - -import { BasePrayer, PrayerGroups } from "../../sdk/BasePrayer"; -import { Settings } from "../../sdk/Settings"; - -export class Retribution extends BasePrayer { - get name() { - return "Retribution"; - } - - get groups(): PrayerGroups[] { - return [PrayerGroups.OVERHEADS]; // TODO: Incorrect - } - - levelRequirement(): number { - return 100; - } - drainRate(): number { - return 3; - } - - isOverhead() { - return false; - } - - playOnSound() { - if (Settings.playsAudio) { - // new Audio(OnSound).play(); - } - } - - playOffSound() { - if (Settings.playsAudio) { - // new Audio(OffSound).play(); - } - } -} diff --git a/src/content/prayers/Rigour.ts b/src/content/prayers/Rigour.ts deleted file mode 100644 index 3418e0ff..00000000 --- a/src/content/prayers/Rigour.ts +++ /dev/null @@ -1,37 +0,0 @@ -"use strict"; - -import { BasePrayer, PrayerGroups } from "../../sdk/BasePrayer"; -import { Settings } from "../../sdk/Settings"; - -export class Rigour extends BasePrayer { - get name() { - return "Rigour"; - } - - get groups(): PrayerGroups[] { - return [PrayerGroups.ACCURACY, PrayerGroups.STRENGTH, PrayerGroups.DEFENCE]; - } - - levelRequirement(): number { - return 74; - } - drainRate(): number { - return 24; - } - - isOverhead() { - return false; - } - - playOnSound() { - if (Settings.playsAudio) { - // new Audio(OnSound).play(); - } - } - - playOffSound() { - if (Settings.playsAudio) { - // new Audio(OffSound).play(); - } - } -} diff --git a/src/content/prayers/RockSkin.ts b/src/content/prayers/RockSkin.ts deleted file mode 100644 index 62949d0e..00000000 --- a/src/content/prayers/RockSkin.ts +++ /dev/null @@ -1,37 +0,0 @@ -"use strict"; - -import { BasePrayer, PrayerGroups } from "../../sdk/BasePrayer"; -import { Settings } from "../../sdk/Settings"; - -export class RockSkin extends BasePrayer { - get name() { - return "Rock Skin"; - } - - get groups(): PrayerGroups[] { - return [PrayerGroups.DEFENCE]; - } - - levelRequirement(): number { - return 10; - } - drainRate(): number { - return 6; - } - - isOverhead() { - return false; - } - - playOnSound() { - if (Settings.playsAudio) { - // new Audio(OnSound).play(); - } - } - - playOffSound() { - if (Settings.playsAudio) { - // new Audio(OffSound).play(); - } - } -} diff --git a/src/content/prayers/SharpEye.ts b/src/content/prayers/SharpEye.ts deleted file mode 100644 index d6ba8e14..00000000 --- a/src/content/prayers/SharpEye.ts +++ /dev/null @@ -1,37 +0,0 @@ -"use strict"; - -import { BasePrayer, PrayerGroups } from "../../sdk/BasePrayer"; -import { Settings } from "../../sdk/Settings"; - -export class SharpEye extends BasePrayer { - get name() { - return "Sharp Eye"; - } - - get groups(): PrayerGroups[] { - return [PrayerGroups.ACCURACY, PrayerGroups.STRENGTH]; - } - - levelRequirement(): number { - return 8; - } - drainRate(): number { - return 3; - } - - isOverhead() { - return false; - } - - playOnSound() { - if (Settings.playsAudio) { - // new Audio(OnSound).play(); - } - } - - playOffSound() { - if (Settings.playsAudio) { - // new Audio(OffSound).play(); - } - } -} diff --git a/src/content/prayers/Smite.ts b/src/content/prayers/Smite.ts deleted file mode 100644 index c2b9ac70..00000000 --- a/src/content/prayers/Smite.ts +++ /dev/null @@ -1,37 +0,0 @@ -"use strict"; - -import { BasePrayer, PrayerGroups } from "../../sdk/BasePrayer"; -import { Settings } from "../../sdk/Settings"; - -export class Smite extends BasePrayer { - get name() { - return "Smite"; - } - - get groups(): PrayerGroups[] { - return [PrayerGroups.OVERHEADS]; - } - - levelRequirement(): number { - return 100; - } - drainRate(): number { - return 18; - } - - isOverhead() { - return false; - } - - playOnSound() { - if (Settings.playsAudio) { - // new Audio(OnSound).play(); - } - } - - playOffSound() { - if (Settings.playsAudio) { - // new Audio(OffSound).play(); - } - } -} diff --git a/src/content/prayers/SteelSkin.ts b/src/content/prayers/SteelSkin.ts deleted file mode 100644 index 5fde6983..00000000 --- a/src/content/prayers/SteelSkin.ts +++ /dev/null @@ -1,37 +0,0 @@ -"use strict"; - -import { BasePrayer, PrayerGroups } from "../../sdk/BasePrayer"; -import { Settings } from "../../sdk/Settings"; - -export class SteelSkin extends BasePrayer { - get name() { - return "Steel Skin"; - } - - get groups(): PrayerGroups[] { - return [PrayerGroups.DEFENCE]; - } - - levelRequirement(): number { - return 28; - } - drainRate(): number { - return 12; - } - - isOverhead() { - return false; - } - - playOnSound() { - if (Settings.playsAudio) { - // new Audio(OnSound).play(); - } - } - - playOffSound() { - if (Settings.playsAudio) { - // new Audio(OffSound).play(); - } - } -} diff --git a/src/content/prayers/SuperhumanStrength.ts b/src/content/prayers/SuperhumanStrength.ts deleted file mode 100644 index 66887d10..00000000 --- a/src/content/prayers/SuperhumanStrength.ts +++ /dev/null @@ -1,37 +0,0 @@ -"use strict"; - -import { BasePrayer, PrayerGroups } from "../../sdk/BasePrayer"; -import { Settings } from "../../sdk/Settings"; - -export class SuperhumanStrength extends BasePrayer { - get name() { - return "Superhuman Strength"; - } - - get groups(): PrayerGroups[] { - return [PrayerGroups.STRENGTH]; - } - - levelRequirement(): number { - return 13; - } - drainRate(): number { - return 6; - } - - isOverhead() { - return false; - } - - playOnSound() { - if (Settings.playsAudio) { - // new Audio(OnSound).play(); - } - } - - playOffSound() { - if (Settings.playsAudio) { - // new Audio(OffSound).play(); - } - } -} diff --git a/src/content/prayers/ThickSkin.ts b/src/content/prayers/ThickSkin.ts deleted file mode 100644 index 12fcd2e6..00000000 --- a/src/content/prayers/ThickSkin.ts +++ /dev/null @@ -1,37 +0,0 @@ -"use strict"; - -import { BasePrayer, PrayerGroups } from "../../sdk/BasePrayer"; -import { Settings } from "../../sdk/Settings"; - -export class ThickSkin extends BasePrayer { - get name() { - return "Thick Skin"; - } - - get groups(): PrayerGroups[] { - return [PrayerGroups.DEFENCE]; - } - - levelRequirement(): number { - return 1; - } - drainRate(): number { - return 3; - } - - isOverhead() { - return false; - } - - playOnSound() { - if (Settings.playsAudio) { - // new Audio(OnSound).play(); - } - } - - playOffSound() { - if (Settings.playsAudio) { - // new Audio(OffSound).play(); - } - } -} diff --git a/src/content/prayers/UltimateStrength.ts b/src/content/prayers/UltimateStrength.ts deleted file mode 100644 index 529528fb..00000000 --- a/src/content/prayers/UltimateStrength.ts +++ /dev/null @@ -1,37 +0,0 @@ -"use strict"; - -import { BasePrayer, PrayerGroups } from "../../sdk/BasePrayer"; -import { Settings } from "../../sdk/Settings"; - -export class UltimateStrength extends BasePrayer { - get name() { - return "Ultimate Strength"; - } - - get groups() { - return [PrayerGroups.STRENGTH]; - } - - levelRequirement(): number { - return 31; - } - drainRate(): number { - return 12; - } - - isOverhead() { - return false; - } - - playOnSound() { - if (Settings.playsAudio) { - // new Audio(OnSound).play(); - } - } - - playOffSound() { - if (Settings.playsAudio) { - // new Audio(OffSound).play(); - } - } -} diff --git a/src/content/seteffects/JusticiarSetEffect.ts b/src/content/seteffects/JusticiarSetEffect.ts deleted file mode 100644 index c1d3dd20..00000000 --- a/src/content/seteffects/JusticiarSetEffect.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { SetEffect, SetEffectTypes } from "../../sdk/SetEffect"; -import { ItemName } from "../../sdk/ItemName"; - -export class JusticiarSetEffect extends SetEffect { - static effectName(): string { - return SetEffectTypes.JUSTICIAR; - } - static itemsInSet(): ItemName[] { - return [ItemName.JUSTICIAR_FACEGUARD, ItemName.JUSTICIAR_CHESTGUARD, ItemName.JUSTICIAR_LEGGUARDS]; - } -} diff --git a/src/content/weapons/AncientStaff.ts b/src/content/weapons/AncientStaff.ts deleted file mode 100644 index 50ba4ad3..00000000 --- a/src/content/weapons/AncientStaff.ts +++ /dev/null @@ -1,76 +0,0 @@ -"use strict"; - -import InventoryImage from "../../assets/images/equipment/Ancient_staff.png"; -import { MeleeWeapon } from "../../sdk/weapons/MeleeWeapon"; -import { ItemName } from "../../sdk/ItemName"; -import { AttackStyle, AttackStyleTypes } from "../../sdk/AttackStylesController"; - -export class AncientStaff extends MeleeWeapon { - constructor() { - super(); - - this.bonuses = { - attack: { - stab: 10, - slash: -1, - crush: 40, - magic: 15, - range: 0, - }, - defence: { - stab: 2, - slash: 3, - crush: 1, - magic: 15, - range: 0, - }, - other: { - meleeStrength: 50, - rangedStrength: 0, - magicDamage: 0, - prayer: -1, - }, - targetSpecific: { - undead: 0, - slayer: 0, - }, - }; - } - - attackStyles() { - return [AttackStyle.ACCURATE, AttackStyle.AGGRESSIVECRUSH, AttackStyle.DEFENSIVE]; - } - - attackStyleCategory(): AttackStyleTypes { - return AttackStyleTypes.STAFF; - } - - defaultStyle(): AttackStyle { - return AttackStyle.AGGRESSIVECRUSH; - } - - get itemName(): ItemName { - return ItemName.ANCIENT_STAFF; - } - - get isTwoHander(): boolean { - return false; - } - - hasSpecialAttack(): boolean { - return false; - } - - get attackRange() { - // TODO: Override with spell selection - return 1; - } - - get attackSpeed() { - return 4; - } - - get inventoryImage() { - return InventoryImage; - } -} diff --git a/src/content/weapons/BlackChinchompa.ts b/src/content/weapons/BlackChinchompa.ts deleted file mode 100644 index b24a7bee..00000000 --- a/src/content/weapons/BlackChinchompa.ts +++ /dev/null @@ -1,156 +0,0 @@ -"use strict"; - -import InventImage from "../../assets/images/equipment/Black_chinchompa.png"; -import { RangedWeapon } from "../../sdk/weapons/RangedWeapon"; -import { ItemName } from "../../sdk/ItemName"; -import { AttackStyle, AttackStyleTypes } from "../../sdk/AttackStylesController"; -import { Sound } from "../../sdk/utils/SoundCache"; - -import ChinThrowSound from "../../assets/sounds/thrown_axe_2706.ogg"; -import ChinLandSound from "../../assets/sounds/chinchompa_explode_360.ogg"; -import { ProjectileOptions } from "../../sdk/weapons/Projectile"; -import { AttackBonuses } from "../../sdk/gear/Weapon"; -import { Unit } from "../../sdk/Unit"; -import { Pathing } from "../../sdk/Pathing"; -import { Mob } from "../../sdk/Mob"; -import { Assets } from "../../sdk/utils/Assets"; -import { PlayerAnimationIndices } from "../../sdk/rendering/GLTFAnimationConstants"; - -export class BlackChinchompa extends RangedWeapon { - maxConcurrentHits = 9; - - constructor() { - super(); - this.bonuses = { - attack: { - stab: 0, - slash: 0, - crush: 0, - magic: 0, - range: 80, - }, - defence: { - stab: 0, - slash: 0, - crush: 0, - magic: 0, - range: 0, - }, - other: { - meleeStrength: 0, - rangedStrength: 30, - magicDamage: 0, - prayer: 0, - }, - targetSpecific: { - undead: 0, - slayer: 0, - }, - }; - } - - // same as toxic blowpipe and other thrown weapon - calculateHitDelay(distance: number) { - return Math.floor(distance / 6) + 1; - } - - attackStyles() { - return [AttackStyle.SHORT_FUSE, AttackStyle.MEDIUM_FUSE, AttackStyle.LONG_FUSE]; - } - - attackStyleCategory(): AttackStyleTypes { - return AttackStyleTypes.CHINCHOMPA; - } - - defaultStyle(): AttackStyle { - return AttackStyle.MEDIUM_FUSE; - } - - get attackSpeed() { - if (this.attackStyle() === AttackStyle.MEDIUM_FUSE) { - return 3; - } - return 4; - } - - get weight(): number { - return 0; - } - - get itemName(): ItemName { - return ItemName.BLACK_CHINCHOMPA; - } - - get isTwoHander(): boolean { - return false; - } - - get attackRange() { - if (this.attackStyle() === AttackStyle.LONG_FUSE) { - return 10; - } - return 9; - } - - get inventoryImage() { - return InventImage; - } - - get attackSound() { - return new Sound(ChinThrowSound, 0.1); - } - - get attackLandingSound() { - return new Sound(ChinLandSound, 0.1); - } - - get aoe() { - return [ - { x: 0, y: 0 }, - { x: -1, y: -1 }, - { x: -1, y: 0 }, - { x: -1, y: 1 }, - { x: 0, y: -1 }, - { x: 0, y: 1 }, - { x: 1, y: -1 }, - { x: 1, y: 0 }, - { x: 1, y: 1 }, - ]; - } - - attack(from: Unit, to: Unit, bonuses: AttackBonuses = {}, options: ProjectileOptions = {}) { - if (this.aoe.length) { - const alreadyCastedOn: Unit[] = [to]; - const initialResult = super.attack(from, to, bonuses, options); - if (initialResult) { - this.aoe.forEach((point) => { - Pathing.mobsAtAoeOffset(from.region, to, point).forEach((mob: Mob) => { - if (alreadyCastedOn.length > this.maxConcurrentHits) { - return; - } - if (alreadyCastedOn.indexOf(mob) > -1) { - return; - } - alreadyCastedOn.push(mob); - // HACK: chin gets massive accuracy bonus if main roll hits - from.bonuses.attack.range += 100000; - super.attack(from, mob, bonuses, { ...options, hidden: true }); - from.bonuses.attack.range -= 100000; - }); - }); - } - return initialResult; - } else { - return super.attack(from, to, bonuses, options); - } - } - - Model = Assets.getAssetUrl("models/player_black_chinchompa.glb"); - override get model() { - return this.Model; - } - - get attackAnimationId() { - return PlayerAnimationIndices.ThrowChinchompa; - } -} diff --git a/src/content/weapons/BladeOfSaeldor.ts b/src/content/weapons/BladeOfSaeldor.ts deleted file mode 100644 index f52d63c4..00000000 --- a/src/content/weapons/BladeOfSaeldor.ts +++ /dev/null @@ -1,95 +0,0 @@ -import BladeOfSaeldorImage from "../../assets/images/weapons/Blade_of_saeldor.png"; -import { MeleeWeapon } from "../../sdk/weapons/MeleeWeapon"; -import { ItemName } from "../../sdk/ItemName"; -import { AttackStyle, AttackStyleTypes } from "../../sdk/AttackStylesController"; -import { Assets } from "../../sdk/utils/Assets"; -import { PlayerAnimationIndices } from "../../sdk/rendering/GLTFAnimationConstants"; -import { Sound } from "../../sdk/utils/SoundCache"; - -import ScytheAttackSound from "../../assets/sounds/scythe_swing_2524.ogg"; - -export class BladeOfSaeldor extends MeleeWeapon { - constructor() { - super(); - - this.bonuses = { - attack: { - stab: 55, - slash: 94, - crush: 0, - magic: 0, - range: 0, - }, - defence: { - stab: 0, - slash: 0, - crush: 0, - magic: 0, - range: 0, - }, - other: { - meleeStrength: 89, - rangedStrength: 0, - magicDamage: 0, - prayer: 0, - }, - targetSpecific: { - undead: 0, - slayer: 0, - }, - }; - } - - attackStyles() { - return [AttackStyle.ACCURATE, AttackStyle.AGGRESSIVESLASH, AttackStyle.STAB, AttackStyle.DEFENSIVE]; - } - - attackStyleCategory(): AttackStyleTypes { - return AttackStyleTypes.SLASHSWORD; - } - - defaultStyle(): AttackStyle { - return AttackStyle.AGGRESSIVESLASH; - } - - get itemName(): ItemName { - return ItemName.BLADE_OF_SAELDOR; - } - - get isTwoHander(): boolean { - return false; - } - - hasSpecialAttack(): boolean { - return false; - } - - get attackRange() { - return 1; - } - - get attackSpeed() { - return 4; - } - - get inventoryImage() { - return BladeOfSaeldorImage; - } - - private Model = Assets.getAssetUrl("models/player_blade_of_saeldor.glb"); - override get model() { - return this.Model; - } - - override get attackAnimationId() { - return PlayerAnimationIndices.SwordSlash; - } - - override get idleAnimationId() { - return PlayerAnimationIndices.Idle; - } - - get attackSound() { - return new Sound(ScytheAttackSound, 0.1); - } -} diff --git a/src/content/weapons/Blowpipe.ts b/src/content/weapons/Blowpipe.ts deleted file mode 100644 index bb86a3c3..00000000 --- a/src/content/weapons/Blowpipe.ts +++ /dev/null @@ -1,156 +0,0 @@ -"use strict"; - -import BPInventImage from "../../assets/images/weapons/blowpipe.png"; -import { RangedWeapon } from "../../sdk/weapons/RangedWeapon"; -import { ItemName } from "../../sdk/ItemName"; -import { Unit } from "../../sdk/Unit"; -import { AttackBonuses } from "../../sdk/gear/Weapon"; -import { AttackStyle, AttackStyleTypes } from "../../sdk/AttackStylesController"; -import { ArcProjectileMotionInterpolator, Projectile, ProjectileOptions } from "../../sdk/weapons/Projectile"; - -import BPAttackSound from "../../assets/sounds/dart_2696.ogg"; -import BPSpecSound from "../../assets/sounds/snake_hit_800.ogg"; -import { Sound, SoundCache } from "../../sdk/utils/SoundCache"; - -import { PlayerAnimationIndices } from "../../sdk/rendering/GLTFAnimationConstants"; -import { Assets } from "../../sdk/utils/Assets"; - -export class Blowpipe extends RangedWeapon { - constructor() { - super({ - modelScale: 1 / 128, - visualDelayTicks: 1, - visualHitEarlyTicks: 0, - verticalOffset: -0.75, - motionInterpolator: new ArcProjectileMotionInterpolator(0.5), - }); - this.bonuses = { - attack: { - stab: 0, - slash: 0, - crush: 0, - magic: 0, - range: 30, - }, - defence: { - stab: 0, - slash: 0, - crush: 0, - magic: 0, - range: 0, - }, - other: { - meleeStrength: 0, - rangedStrength: 20 + 35, // simulating dragon darts atm - magicDamage: 0, - prayer: 0, - }, - targetSpecific: { - undead: 0, - slayer: 0, - }, - }; - SoundCache.preload(this.attackSound.src); - } - - calculateHitDelay(distance: number) { - return Math.floor(distance / 6) + 1; - } - - attackStyles() { - return [AttackStyle.ACCURATE, AttackStyle.RAPID, AttackStyle.LONGRANGE]; - } - - attackStyleCategory(): AttackStyleTypes { - return AttackStyleTypes.THROWN; - } - - defaultStyle(): AttackStyle { - return AttackStyle.RAPID; - } - - get attackRange() { - if (this.attackStyle() === AttackStyle.LONGRANGE) { - return 7; - } - return 5; - } - - get attackSpeed() { - if (this.attackStyle() === AttackStyle.LONGRANGE) { - return 3; - } - return 2; - } - - get weight(): number { - return 0.5; - } - - specialAttack(from: Unit, to: Unit, bonuses: AttackBonuses = {}, options: ProjectileOptions = {}) { - super.specialAttack(from, to, bonuses, options); - bonuses.isSpecialAttack = true; - // BP special attack takes an extra tick to land - super.attack(from, to, bonuses, { - ...options, - reduceDelay: -1, - visualHitEarlyTicks: 1, - visualDelayTicks: 1, - projectileSound: this.specialAttackSound, - }); - - const healAttackerBy = Math.floor(this.damageRoll / 2); - from.currentStats.hitpoint += healAttackerBy; - from.currentStats.hitpoint = Math.min(from.currentStats.hitpoint, from.stats.hitpoint); - } - - _damageMultiplier(from: Unit, to: Unit, bonuses: AttackBonuses) { - if (bonuses.isSpecialAttack) { - return 1.5; - } - return 1; - } - _accuracyMultiplier(from: Unit, to: Unit, bonuses: AttackBonuses) { - if (bonuses.isSpecialAttack) { - return 2; - } - return 1; - } - - get itemName(): ItemName { - return ItemName.TOXIC_BLOWPIPE; - } - - get isTwoHander(): boolean { - return true; - } - - hasSpecialAttack(): boolean { - return true; - } - get inventoryImage() { - return BPInventImage; - } - - get attackSound() { - return new Sound(BPAttackSound, 0.1); - } - - get specialAttackSound() { - return new Sound(BPSpecSound, 0.5); - } - - Model = Assets.getAssetUrl("models/player_toxic_blowpipe.glb"); - override get model() { - return this.Model; - } - - get attackAnimationId() { - return PlayerAnimationIndices.FireBlowpipe; - } - - ProjectileModel = Assets.getAssetUrl("models/dragon_dart.glb"); - get projectileModel() { - return this.ProjectileModel; - } -} diff --git a/src/content/weapons/BowOfFaerdhinen.ts b/src/content/weapons/BowOfFaerdhinen.ts deleted file mode 100644 index e2ac44ce..00000000 --- a/src/content/weapons/BowOfFaerdhinen.ts +++ /dev/null @@ -1,105 +0,0 @@ -"use strict"; - -import InventImage from "../../assets/images/equipment/Bow_of_faerdhinen.png"; -import { RangedWeapon } from "../../sdk/weapons/RangedWeapon"; -import { AttackBonuses } from "../../sdk/gear/Weapon"; -import { ItemName } from "../../sdk/ItemName"; -import { Unit } from "../../sdk/Unit"; -import { AttackStyle, AttackStyleTypes } from "../../sdk/AttackStylesController"; -import { PlayerAnimationIndices } from "../../sdk/rendering/GLTFAnimationConstants"; -import { Assets } from "../../sdk/utils/Assets"; -import { Sound } from "../../sdk/utils/SoundCache"; - -import BofaAttackSound from "../../assets/sounds/crystal_bow_1352.ogg"; - -export class BowOfFaerdhinen extends RangedWeapon { - constructor() { - super(); - this.bonuses = { - attack: { - stab: 0, - slash: 0, - crush: 0, - magic: 0, - range: 128, - }, - defence: { - stab: 0, - slash: 0, - crush: 0, - magic: 0, - range: 0, - }, - other: { - meleeStrength: 0, - rangedStrength: 106, // TODO: This will stack with dragon arrows if both equipped - magicDamage: 0, - prayer: 0, - }, - targetSpecific: { - undead: 0, - slayer: 0, - }, - }; - } - - attackStyles() { - return [AttackStyle.ACCURATE, AttackStyle.RAPID, AttackStyle.LONGRANGE]; - } - - attackStyleCategory(): AttackStyleTypes { - return AttackStyleTypes.BOW; - } - - defaultStyle(): AttackStyle { - return AttackStyle.RAPID; - } - - get attackSound() { - return new Sound(BofaAttackSound, 0.1); - } - - get attackSpeed() { - if (this.attackStyle() === AttackStyle.LONGRANGE) { - return 5; - } - return 4; - } - - get weight(): number { - return 1.5; - } - - get itemName(): ItemName { - return ItemName.BOWFA; - } - - get isTwoHander(): boolean { - return true; - } - - get attackRange() { - return 10; - } - - get inventoryImage() { - return InventImage; - } - - _accuracyMultiplier(from: Unit, to: Unit, bonuses: AttackBonuses) { - return from.bonuses.other.crystalAccuracy || 1; - } - - _damageMultiplier(from: Unit, to: Unit, bonuses: AttackBonuses) { - return from.bonuses.other.crystalDamage || 1; - } - - Model = Assets.getAssetUrl("models/player_bow_of_faerdhinen.glb"); - override get model() { - return this.Model; - } - - get attackAnimationId() { - return PlayerAnimationIndices.FireBow; - } -} diff --git a/src/content/weapons/KodaiWand.ts b/src/content/weapons/KodaiWand.ts deleted file mode 100644 index 94e9327d..00000000 --- a/src/content/weapons/KodaiWand.ts +++ /dev/null @@ -1,110 +0,0 @@ -"use strict"; - -import KodaiInventImage from "../../assets/images/equipment/Kodai_wand.png"; -import { MeleeWeapon } from "../../sdk/weapons/MeleeWeapon"; -import { ItemName } from "../../sdk/ItemName"; -import { AttackStyle, AttackStyleTypes } from "../../sdk/AttackStylesController"; -import { BarrageSpell } from "../../sdk/weapons/BarrageSpell"; -import { AttackBonuses } from "../../sdk/gear/Weapon"; -import { Unit } from "../../sdk/Unit"; -import { Player } from "../../sdk/Player"; -import { BloodBarrageSpell } from "../../sdk/weapons/BloodBarrageSpell"; - -export class KodaiWand extends MeleeWeapon { - autocastSpell: BarrageSpell = new BloodBarrageSpell(); - - constructor() { - super(); - - this.bonuses = { - attack: { - stab: 0, - slash: 0, - crush: 0, - magic: 28, - range: 0, - }, - defence: { - stab: 0, - slash: 3, - crush: 3, - magic: 20, - range: 0, - }, - other: { - meleeStrength: 0, - rangedStrength: 0, - magicDamage: 0.15, - prayer: 0, - }, - targetSpecific: { - undead: 0, - slayer: 0, - }, - }; - } - - attack(from: Unit, to: Unit, bonuses: AttackBonuses = {}): boolean { - if (this.attackStyle() === AttackStyle.AUTOCAST) { - if (from.isPlayer) { - const player: Player = from as Player; - if (player.autocastDelay === 0) { - this.autocastSpell.cast(from, to); - return true; - } - if (player.autocastDelay > 0) { - player.autocastDelay--; - } - return false; - } - } - - return super.attack(from, to, bonuses); - } - - attackStyles() { - return [AttackStyle.ACCURATE, AttackStyle.AGGRESSIVECRUSH, AttackStyle.DEFENSIVE, AttackStyle.AUTOCAST]; - } - - attackStyleCategory(): AttackStyleTypes { - return AttackStyleTypes.STAFF; - } - - defaultStyle(): AttackStyle { - return AttackStyle.AUTOCAST; - } - - get weight(): number { - return 0.198; - } - - get itemName(): ItemName { - return ItemName.KODAI_WAND; - } - - get isTwoHander(): boolean { - return false; - } - - hasSpecialAttack(): boolean { - return false; - } - - get attackRange() { - if (this.attackStyle() === AttackStyle.AUTOCAST) { - return 10; - } - return 1; - } - - get attackSpeed() { - if (this.attackStyle() === AttackStyle.AUTOCAST) { - return 5; - } - return 4; - } - - get inventoryImage() { - return KodaiInventImage; - } -} diff --git a/src/content/weapons/ScytheOfVitur.ts b/src/content/weapons/ScytheOfVitur.ts deleted file mode 100644 index e738293e..00000000 --- a/src/content/weapons/ScytheOfVitur.ts +++ /dev/null @@ -1,156 +0,0 @@ -import ScytheInventImage from "../../assets/images/weapons/scytheOfVitur.png"; -import { MeleeWeapon } from "../../sdk/weapons/MeleeWeapon"; -import { ItemName } from "../../sdk/ItemName"; -import { AttackStyle, AttackStyleTypes } from "../../sdk/AttackStylesController"; -import { Assets } from "../../sdk/utils/Assets"; -import { PlayerAnimationIndices } from "../../sdk/rendering/GLTFAnimationConstants"; -import { Sound } from "../../sdk/utils/SoundCache"; - -import ScytheAttackSound from "../../assets/sounds/scythe_swing_2524.ogg"; -import { AttackBonuses } from "../../sdk/gear/Weapon"; -import { Unit } from "../../sdk/Unit"; -import { Collision } from "../../sdk/Collision"; - -const EXTRA_HIT_LOCATIONS = [ - [ - [-1, -1], - [1, -1], - ], // North - [ - [1, 1], - [1, -1], - ], // East - [ - [-1, 1], - [1, 1], - ], // South - [ - [-1, 1], - [-1, -1], - ], // West -]; - -export class ScytheOfVitur extends MeleeWeapon { - constructor() { - super(); - - this.bonuses = { - attack: { - stab: 70, - slash: 125, - crush: 30, - magic: -6, - range: 0, - }, - defence: { - stab: -2, - slash: 8, - crush: 10, - magic: 0, - range: 0, - }, - other: { - meleeStrength: 75, - rangedStrength: 0, - magicDamage: 0, - prayer: 0, - }, - targetSpecific: { - undead: 0, - slayer: 0, - }, - }; - } - - attackStyles() { - return [AttackStyle.REAP, AttackStyle.AGGRESSIVESLASH, AttackStyle.AGGRESSIVECRUSH, AttackStyle.DEFENSIVE]; - } - - attackStyleCategory(): AttackStyleTypes { - return AttackStyleTypes.SCYTHE; - } - - defaultStyle(): AttackStyle { - return AttackStyle.AGGRESSIVESLASH; - } - - get itemName(): ItemName { - return ItemName.SCYTHE_OF_VITUR; - } - - get isTwoHander(): boolean { - return true; - } - - hasSpecialAttack(): boolean { - return false; - } - - get attackRange() { - return 1; - } - - get attackSpeed() { - return 5; - } - - get inventoryImage() { - return ScytheInventImage; - } - - override attack(from: Unit, to: Unit, bonuses: AttackBonuses) { - const region = from.region; - // As there is no concept of player direction yet, we dynamically calculate this based on the relative location of - // the attacker. - // Find the closest tile on the npc to us. - const targetTile = to.getClosestTileTo(from.location.x, from.location.y); - - const dx = from.location.x - targetTile[0]; - const dy = from.location.y - targetTile[1]; - let direction; - if (dx < 0) { - direction = 1; // East - } else if (dx > 0) { - direction = 3; // West - } else if (dy < 0) { - direction = 2; // South - } else { - direction = 0; // North - } - // Full damage attack, but each subsequent hit does half of the last. - let multiplier = 1.0; - super.attack(from, to, bonuses); - EXTRA_HIT_LOCATIONS[direction].forEach((hit) => { - const xx = from.location.x + hit[0]; - const yy = from.location.y + hit[1]; - const collision = Collision.collidesWithAnyMobs(region, xx, yy, from.size); - multiplier *= 0.5; - const extraHitBonuses: AttackBonuses = { - ...bonuses, - overallMultiplier: multiplier, - }; - if (collision) { - super.attack(from, collision, extraHitBonuses); - } else { - super.attack(from, to, extraHitBonuses); - } - }); - return true; - } - - override get model() { - return Assets.getAssetUrl("models/player_sanguine_scythe_of_vitur.glb"); - } - - override get attackAnimationId() { - return PlayerAnimationIndices.ScytheSwing; - } - - override get idleAnimationId() { - return PlayerAnimationIndices.ScytheIdle; - } - - get attackSound() { - return new Sound(ScytheAttackSound, 0.1); - } -} diff --git a/src/content/weapons/TwistedBow.ts b/src/content/weapons/TwistedBow.ts deleted file mode 100644 index bf29c966..00000000 --- a/src/content/weapons/TwistedBow.ts +++ /dev/null @@ -1,126 +0,0 @@ -"use strict"; - -import { Unit } from "../../sdk/Unit"; -import { RangedWeapon } from "../../sdk/weapons/RangedWeapon"; -import { ItemName } from "../../sdk/ItemName"; -import { AttackStyle, AttackStyleTypes } from "../../sdk/AttackStylesController"; -import { AttackBonuses } from "../../sdk/gear/Weapon"; -import { Sound, SoundCache } from "../../sdk/utils/SoundCache"; -import { PlayerAnimationIndices } from "../../sdk/rendering/GLTFAnimationConstants"; -import { Assets } from "../../sdk/utils/Assets"; - -import TbowInventImage from "../../assets/images/weapons/twistedBow.png"; -import TwistedBowAttackSound from "../../assets/sounds/shortbow_2702.ogg"; -import { ArcProjectileMotionInterpolator } from "../../sdk/weapons/Projectile"; - -export class TwistedBow extends RangedWeapon { - constructor(geno = false) { - super({ - modelScale: 1 / 128, - visualDelayTicks: 1, - visualHitEarlyTicks: 1, - verticalOffset: -0.75, - motionInterpolator: new ArcProjectileMotionInterpolator(1), - }); - this.bonuses = { - attack: { - stab: 0, - slash: 0, - crush: 0, - magic: 0, - range: geno ? 10000 : 70, - }, - defence: { - stab: 0, - slash: 0, - crush: 0, - magic: 0, - range: 0, - }, - other: { - meleeStrength: 0, - rangedStrength: geno ? 80 : 20, - magicDamage: 0, - prayer: 0, - }, - targetSpecific: { - undead: 0, - slayer: 0, - }, - }; - SoundCache.preload(this.attackSound.src); - } - - compatibleAmmo(): ItemName[] { - return [ItemName.DRAGON_ARROWS]; - } - - attackStyles() { - return [AttackStyle.ACCURATE, AttackStyle.RAPID, AttackStyle.LONGRANGE]; - } - - attackStyleCategory(): AttackStyleTypes { - return AttackStyleTypes.BOW; - } - - defaultStyle(): AttackStyle { - return AttackStyle.RAPID; - } - - get attackSpeed() { - if (this.attackStyle() === AttackStyle.LONGRANGE) { - return 6; - } - return 5; - } - - get attackSound() { - return new Sound(TwistedBowAttackSound, 0.1); - } - - get weight(): number { - return 1.814; - } - - get itemName(): ItemName { - return ItemName.TWISTED_BOW; - } - - get isTwoHander(): boolean { - return true; - } - - get attackRange() { - return 10; - } - - get inventoryImage() { - return TbowInventImage; - } - - _accuracyMultiplier(from: Unit, to: Unit, bonuses: AttackBonuses) { - const magic = Math.min(Math.max(to.currentStats.magic, to.bonuses.attack.magic), 250); - const multiplier = (140 + ((10 * 3 * magic) / 10 - 10) / 100 - Math.pow((3 * magic) / 10 - 100, 2) / 100) / 100; - return Math.min(1.4, Math.max(0, multiplier)); - } - - _damageMultiplier(from: Unit, to: Unit, bonuses: AttackBonuses) { - const magic = Math.min(Math.max(to.currentStats.magic, to.bonuses.attack.magic), 250); - const multiplier = (250 + ((10 * 3 * magic) / 10 - 14) / 100 - Math.pow((3 * magic) / 10 - 140, 2) / 100) / 100; - return Math.min(2.5, Math.max(0, multiplier)); - } - - Model = Assets.getAssetUrl("models/player_twisted_bow.glb"); - override get model() { - return this.Model; - } - - get attackAnimationId() { - return PlayerAnimationIndices.FireBow; - } - - ProjectileModel = Assets.getAssetUrl("models/dragon_arrow.glb"); - get projectileModel() { - return this.ProjectileModel; - } -} diff --git a/src/index.ts b/src/index.ts index 32909b7c..ecb3b749 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,26 +1,10 @@ "use strict"; -import { World as World } from "./sdk/World"; -import { Settings } from "./sdk/Settings"; -import { ImageLoader } from "./sdk/utils/ImageLoader"; -import NewRelicBrowser from "new-relic-browser"; -import { Viewport } from "./sdk/Viewport"; -import { TileMarker } from "./content/TileMarker"; -import { Location } from "./sdk/Location"; -import { MapController } from "./sdk/MapController"; -import { Assets } from "./sdk/utils/Assets"; -import { Chrome } from "./sdk/Chrome"; -import { Region } from "./sdk/Region"; +import { World, Settings, ImageLoader, Viewport, TileMarker, Location, MapController, Assets, Chrome, Region } from "@supalosa/oldschool-trainer-sdk"; import { ColosseumRegion } from "./content/colosseum/js/ColosseumRegion"; import SpecialAttackBarBackground from "./assets/images/attackstyles/interface/special_attack_background.png"; -declare global { - interface Window { - newrelic: typeof NewRelicBrowser; - } -} - Settings.readFromStorage(); // Choose the region based on the URL. @@ -151,8 +135,6 @@ function checkStart() { /// ///////////////////////////////////////////////////////// -window.newrelic.addRelease("inferno-trainer", process.env.COMMIT_REF); - // UI disclaimer const topHeaderContainer = document.getElementById("disclaimer_panel"); topHeaderContainer.innerHTML = diff --git a/src/sdk/AttackStylesController.ts b/src/sdk/AttackStylesController.ts deleted file mode 100644 index b307419d..00000000 --- a/src/sdk/AttackStylesController.ts +++ /dev/null @@ -1,210 +0,0 @@ -"use strict"; - -import { Weapon } from "./gear/Weapon"; -import { ImageLoader } from "./utils/ImageLoader"; - -import BowAccurateImage from "../assets/images/attackstyles/bow/accurate.png"; -import BowRapidImage from "../assets/images/attackstyles/bow/rapid.png"; -import BowLongrangeImage from "../assets/images/attackstyles/bow/longrange.png"; - -import CrossbowAccurateImage from "../assets/images/attackstyles/crossbows/accurate.png"; -import CrossbowRapidImage from "../assets/images/attackstyles/crossbows/rapid.png"; -import CrossbowLongrangeImage from "../assets/images/attackstyles/crossbows/longrange.png"; - -import ThrownAccurateImage from "../assets/images/attackstyles/thrown/accurate.png"; -import ThrownRapidImage from "../assets/images/attackstyles/thrown/rapid.png"; -import ThrownLongrangeImage from "../assets/images/attackstyles/thrown/longrange.png"; - -import StaffAccurateImage from "../assets/images/attackstyles/staff/accurate.png"; -import StaffAggressiveImage from "../assets/images/attackstyles/staff/aggressive.png"; -import StaffDefensiveImage from "../assets/images/attackstyles/staff/defensive.png"; - -import ScytheAccurateImage from "../assets/images/attackstyles/scythe/accurate.png"; -import ScytheAggressiveSlashImage from "../assets/images/attackstyles/scythe/aggressiveslash.png"; -import ScytheAggressiveCrushImage from "../assets/images/attackstyles/scythe/aggressivecrush.png"; -import ScytheDefensiveImage from "../assets/images/attackstyles/scythe/defensive.png"; - -import ChinchompaShortFuseImage from "../assets/images/attackstyles/chinchompas/short.png"; -import ChinchompaMediumFuseImage from "../assets/images/attackstyles/chinchompas/medium.png"; -import ChinchompaLongFuseImage from "../assets/images/attackstyles/chinchompas/long.png"; - -import SwordChopImage from "../assets/images/attackstyles/swords/chop.png"; -import SwordSlashImage from "../assets/images/attackstyles/swords/slash.png"; -import SwordLungeImage from "../assets/images/attackstyles/swords/lunge.png"; -import SwordBlockImage from "../assets/images/attackstyles/swords/block.png"; - -//https://oldschool.runescape.wiki/w/Weapons/Types -export enum AttackStyleTypes { - CROSSBOW = "CROSSBOW", - BOW = "BOW", - CHINCHOMPA = "CHINCOMPA", - GUN = "GUN", - THROWN = "THROWN", - BLADEDSTAFF = "BLADEDSTAFF", - POWEREDSTAFF = "POWEREDSTAFF", - STAFF = "STAFF", - SALAMANDER = "SALAMANDER", - TWOHANDSWORD = "TWOHANDSWORD", - AXE = "AXE", - BANNER = "BANNER", - BLUNT = "BLUNT", - BLUDGEON = "BLUDGEON", - BULWARK = "BULWARK", - CLAW = "CLAW", - PICKAXE = "PICKAXE", - POLEARM = "POLEARM", - POLESTAFF = "POLESTAFF", - SCYTHE = "SCYTHE", - SLASHSWORD = "SLASHSWORD", - SPEAR = "SPEAR", - SPIKEDWEAPON = "SPIKEDWEAPON", - STABSWORD = "STABSWORD", - UNARMED = "UNARMED", - WHIP = "WHIP", -} - -export enum AttackStyle { - ACCURATE = "ACCURATE", - RAPID = "RAPID", - LONGRANGE = "LONGRANGE", - REAP = "REAP", - AGGRESSIVECRUSH = "AGGRESSIVE (CRUSH)", - AGGRESSIVESLASH = "AGGRESSIVE (SLASH)", - STAB = "STAB", - DEFENSIVE = "DEFENSIVE", - CONTROLLED = "CONTROLLED", - AUTOCAST = "AUTOCAST", - SHORT_FUSE = "SHORT_FUSE", - MEDIUM_FUSE = "MEDIUM_FUSE", - LONG_FUSE = "LONG_FUSE", -} - -interface AttackStyleStorage { - [key: string]: AttackStyle; -} - -interface AttackStyleImageMap { - [type: string]: IAttackStyleImageMap; -} - -interface IAttackStyleImageMap { - [style: string]: HTMLImageElement; -} - -// xp multiplier constants -const DEFENCE_2 = { skill: "defence", multiplier: 2 }; -const HITPOINTS_133 = { skill: "hitpoint", multiplier: 1.33 }; - -const MELEE_ACCURATE = [{ skill: "attack", multiplier: 4 }, HITPOINTS_133]; -const MELEE_AGGRESSIVE = [{ skill: "strength", multiplier: 4 }, HITPOINTS_133]; -const MELEE_DEFENSIVE = [{ skill: "defence", multiplier: 4 }, HITPOINTS_133]; -const MELEE_CONTROLLED = [ - { skill: "attack", multiplier: 1.33 }, - { skill: "strength", multiplier: 1.33 }, - { skill: "defence", multiplier: 1.33 }, - HITPOINTS_133, -]; - -const RANGE_ACCURATE = [{ skill: "range", multiplier: 4 }, HITPOINTS_133]; -const RANGE_RAPID = [{ skill: "range", multiplier: 4 }, HITPOINTS_133]; -const RANGE_LONGRANGE = [{ skill: "range", multiplier: 2 }, DEFENCE_2, HITPOINTS_133]; - -// This badly needs a refactor to classify each styles by parent style -export class AttackStylesController { - static attackStyleImageMap: AttackStyleImageMap = { - [AttackStyleTypes.CROSSBOW]: { - [AttackStyle.ACCURATE]: ImageLoader.createImage(CrossbowAccurateImage), - [AttackStyle.RAPID]: ImageLoader.createImage(CrossbowRapidImage), - [AttackStyle.LONGRANGE]: ImageLoader.createImage(CrossbowLongrangeImage), - }, - [AttackStyleTypes.BOW]: { - [AttackStyle.ACCURATE]: ImageLoader.createImage(BowAccurateImage), - [AttackStyle.RAPID]: ImageLoader.createImage(BowRapidImage), - [AttackStyle.LONGRANGE]: ImageLoader.createImage(BowLongrangeImage), - }, - [AttackStyleTypes.STAFF]: { - [AttackStyle.ACCURATE]: ImageLoader.createImage(StaffAccurateImage), - [AttackStyle.AGGRESSIVECRUSH]: ImageLoader.createImage(StaffAggressiveImage), - [AttackStyle.DEFENSIVE]: ImageLoader.createImage(StaffDefensiveImage), - [AttackStyle.AUTOCAST]: ImageLoader.createImage(StaffDefensiveImage), - }, - [AttackStyleTypes.THROWN]: { - [AttackStyle.ACCURATE]: ImageLoader.createImage(ThrownAccurateImage), - [AttackStyle.RAPID]: ImageLoader.createImage(ThrownRapidImage), - [AttackStyle.LONGRANGE]: ImageLoader.createImage(ThrownLongrangeImage), - }, - [AttackStyleTypes.SCYTHE]: { - [AttackStyle.REAP]: ImageLoader.createImage(ScytheAccurateImage), - [AttackStyle.AGGRESSIVESLASH]: ImageLoader.createImage(ScytheAggressiveSlashImage), - [AttackStyle.AGGRESSIVECRUSH]: ImageLoader.createImage(ScytheAggressiveCrushImage), - [AttackStyle.DEFENSIVE]: ImageLoader.createImage(ScytheDefensiveImage), - }, - [AttackStyleTypes.SLASHSWORD]: { - [AttackStyle.ACCURATE]: ImageLoader.createImage(SwordChopImage), - [AttackStyle.AGGRESSIVESLASH]: ImageLoader.createImage(SwordSlashImage), - [AttackStyle.STAB]: ImageLoader.createImage(SwordLungeImage), - [AttackStyle.DEFENSIVE]: ImageLoader.createImage(SwordBlockImage), - }, - [AttackStyleTypes.CHINCHOMPA]: { - [AttackStyle.SHORT_FUSE]: ImageLoader.createImage(ChinchompaShortFuseImage), - [AttackStyle.MEDIUM_FUSE]: ImageLoader.createImage(ChinchompaMediumFuseImage), - [AttackStyle.LONG_FUSE]: ImageLoader.createImage(ChinchompaLongFuseImage), - }, - }; - - static attackStyleXpType: Record = { - [AttackStyle.ACCURATE]: RANGE_ACCURATE, - [AttackStyle.RAPID]: RANGE_RAPID, - [AttackStyle.LONGRANGE]: RANGE_LONGRANGE, - [AttackStyle.REAP]: MELEE_ACCURATE, - [AttackStyle.AGGRESSIVECRUSH]: MELEE_AGGRESSIVE, - [AttackStyle.AGGRESSIVESLASH]: MELEE_AGGRESSIVE, - // TODO: add different defensives for different weapons - [AttackStyle.DEFENSIVE]: MELEE_DEFENSIVE, - [AttackStyle.STAB]: MELEE_CONTROLLED, - [AttackStyle.CONTROLLED]: MELEE_CONTROLLED, - [AttackStyle.AUTOCAST]: [{ skill: "magic", multiplier: 2 }, HITPOINTS_133], - // TODO: AUTOCAST_DEFENSIVE - [AttackStyle.SHORT_FUSE]: RANGE_ACCURATE, - [AttackStyle.MEDIUM_FUSE]: RANGE_RAPID, - [AttackStyle.LONG_FUSE]: RANGE_LONGRANGE, - }; - - static attackStyleStrengthBonus: {[style in AttackStyle]?: number} = { - // aggressive = 3 - [AttackStyle.AGGRESSIVECRUSH]: 3, - [AttackStyle.AGGRESSIVESLASH]: 3, - // controlled = 1 - [AttackStyle.CONTROLLED]: 1, - [AttackStyle.STAB]: 1, - } - - static controller: AttackStylesController = new AttackStylesController(); - stylesMap: AttackStyleStorage = {}; - - getAttackStyleForType(type: AttackStyleTypes, weapon: Weapon) { - if (!this.stylesMap[type]) { - this.stylesMap[type] = weapon.defaultStyle(); - } - return this.stylesMap[type]; - } - - setWeaponAttackStyle(weapon: Weapon, newStyle: AttackStyle) { - this.stylesMap[weapon.attackStyleCategory()] = newStyle; - } - - getWeaponAttackStyle(weapon: Weapon): AttackStyle { - return this.stylesMap[weapon.attackStyleCategory()]; - } - - getWeaponXpDrops(style: AttackStyle, damage: number, npcMultiplier: number): { xp: number; skill: string }[] { - return AttackStylesController.attackStyleXpType[style].map(({ skill, multiplier: skillMultiplier }) => ({ - xp: damage * skillMultiplier * npcMultiplier, - skill, - })); - } - - getWeaponStrengthBonus(style: AttackStyle): number { - return AttackStylesController.attackStyleStrengthBonus[style] ?? 0; - } -} diff --git a/src/sdk/BasePrayer.ts b/src/sdk/BasePrayer.ts deleted file mode 100644 index 24f62c3e..00000000 --- a/src/sdk/BasePrayer.ts +++ /dev/null @@ -1,103 +0,0 @@ -"use strict"; - -import { Player } from "./Player"; -import { ImageLoader } from "./utils/ImageLoader"; - -export enum PrayerGroups { - OVERHEADS = "overheads", - DEFENCE = "defence", - STRENGTH = "strength", - ACCURACY = "accuracy", - RANGE = "range", - HEARTS = "hearts", - PROTECTITEM = "protectitem", - PRESERVE = "preserve", -} - -export class BasePrayer { - lastActivated = 0; - isActive = false; - isLit = false; - cachedImage: HTMLImageElement; - - constructor() { - this.deactivate(); - } - - levelRequirement(): number { - return 99; - } - - tick() { - if (this.isLit && !this.isActive) { - this.isActive = true; - this.isLit = true; - } else if (!this.isLit && this.isActive) { - this.isActive = false; - this.isLit = false; - } - } - - drainRate(): number { - throw new Error("prayer does not have proper drain rate"); - } - - // currently only used for overheads - feature(): string { - return ""; - } - - get name() { - return "Protect from Magic"; - } - - get groups(): PrayerGroups[] { - return []; - } - - activate(player: Player) { - if (player.stats.prayer < this.levelRequirement()) { - return; - } - this.lastActivated = Date.now(); - this.isLit = true; - } - - toggle(player: Player) { - if (player.stats.prayer < this.levelRequirement()) { - return; - } - this.isLit = !this.isLit; - if (this.isLit) { - this.lastActivated = Date.now(); - } - } - - deactivate() { - this.isLit = false; - } - - isOverhead() { - return false; - } - - overheadImageReference(): string { - return ""; - } - - overheadImage() { - if (!this.cachedImage && this.overheadImageReference()) { - this.cachedImage = ImageLoader.createImage(this.overheadImageReference()); - return null; - } - - return this.cachedImage; - } - - playOffSound() { - // Override me - } - playOnSound() { - // Override me - } -} diff --git a/src/sdk/BoostPanel.ts b/src/sdk/BoostPanel.ts deleted file mode 100644 index 4c99bebb..00000000 --- a/src/sdk/BoostPanel.ts +++ /dev/null @@ -1,78 +0,0 @@ -"use strict"; - -import { PlayerStats } from "./PlayerStats"; -import { Viewport } from "./Viewport"; - -import AttackXpDropImage from "../assets/images/xpdrops/attack.png"; -import StrengthXpDropImage from "../assets/images/xpdrops/strength.png"; -import DefenceXpDropImage from "../assets/images/xpdrops/defence.png"; -import RangeXpDropImage from "../assets/images/xpdrops/range.png"; -import MagicXpDropImage from "../assets/images/xpdrops/magic.png"; -import { ImageLoader } from "./utils/ImageLoader"; - -const BOOST_VISIBLE_STATS: (keyof PlayerStats)[] = [ - "attack", - "strength", - "defence", - "range", - "magic", -]; - -const BOOST_IMAGE_SRC: {[type in keyof PlayerStats]?: string} = { - "attack": AttackXpDropImage, - "strength": StrengthXpDropImage, - "defence": DefenceXpDropImage, - "range": RangeXpDropImage, - "magic": MagicXpDropImage, -}; - -const BOOST_IMAGES = {}; - -Object.entries(BOOST_IMAGE_SRC).forEach(([skill, src]) => { - BOOST_IMAGES[skill] = ImageLoader.createImage(src); -}); - -export class BoostPanel { - - - draw(context: CanvasRenderingContext2D, scale: number, xLeft: number, yBottom: number) { - const player = Viewport.viewport.player; - if (!player) { - return; - } - context.save(); - const boostedStats = BOOST_VISIBLE_STATS.filter((stat) => player.currentStats[stat] !== player.stats[stat]); - context.globalAlpha = 0.5; - context.fillStyle = "black"; - const CELL_SIZE = 24; - const width = scale * CELL_SIZE; - const height = scale * CELL_SIZE * boostedStats.length; - context.fillRect(xLeft, yBottom - height, width, height) - context.globalAlpha = 1; - let y = yBottom - scale * CELL_SIZE; - context.font = `${scale * 12}px OSRS`; - context.textAlign = "center"; - context.textBaseline = "middle"; - for (const boostedStat of boostedStats) { - const current = player.currentStats[boostedStat]; - const target = player.stats[boostedStat]; - context.drawImage( - BOOST_IMAGES[boostedStat], - xLeft, - y, - scale * CELL_SIZE, - scale * CELL_SIZE, - ); - context.fillStyle = "black"; - context.fillText(`${current}`, xLeft + (scale * CELL_SIZE) / 2 + 1, y + (scale * CELL_SIZE) / 2 + 1); - if (current < target) { - context.fillStyle = "red"; - } else { - context.fillStyle = "lime"; - } - context.fillText(`${current}`, xLeft + (scale * CELL_SIZE) / 2, y + (scale * CELL_SIZE) / 2); - y -= scale * CELL_SIZE; - } - context.restore(); - } -} diff --git a/src/sdk/Chrome.ts b/src/sdk/Chrome.ts deleted file mode 100644 index 50e8a98e..00000000 --- a/src/sdk/Chrome.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Settings } from "./Settings"; - -export class Chrome { - static size() { - const width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth; - const height = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight; - return { width, height }; - } -} diff --git a/src/sdk/ClickAnimation.ts b/src/sdk/ClickAnimation.ts deleted file mode 100644 index 4d128403..00000000 --- a/src/sdk/ClickAnimation.ts +++ /dev/null @@ -1,57 +0,0 @@ -import YellowX1 from "../assets/images/interface/yellow_x_1.png"; -import YellowX2 from "../assets/images/interface/yellow_x_2.png"; -import YellowX3 from "../assets/images/interface/yellow_x_3.png"; -import YellowX4 from "../assets/images/interface/yellow_x_4.png"; - -import RedX1 from "../assets/images/interface/red_x_1.png"; -import RedX2 from "../assets/images/interface/red_x_2.png"; -import RedX3 from "../assets/images/interface/red_x_3.png"; -import RedX4 from "../assets/images/interface/red_x_4.png"; -import { Settings } from "./Settings"; -import { ImageLoader } from "./utils/ImageLoader"; -import { Viewport } from "./Viewport"; - -interface ClickAnimationFrames { - red: HTMLImageElement[]; - yellow: HTMLImageElement[]; -} - -export class ClickAnimation { - color: string; - x: number; - y: number; - ttl: number; - - constructor(color: string, x: number, y: number) { - this.color = color; - this.x = x; - this.y = y; - this.ttl = 1; - } - - static frames: ClickAnimationFrames = { - red: [ - ImageLoader.createImage(RedX1), - ImageLoader.createImage(RedX2), - ImageLoader.createImage(RedX3), - ImageLoader.createImage(RedX4), - ], - yellow: [ - ImageLoader.createImage(YellowX1), - ImageLoader.createImage(YellowX2), - ImageLoader.createImage(YellowX3), - ImageLoader.createImage(YellowX4), - ], - }; - - draw() { - if (this.ttl <= 0) { - return; - } - const frameNumber = Math.floor((1 - this.ttl) * 4); - const frames = this.color === "red" ? ClickAnimation.frames.red : ClickAnimation.frames.yellow; - Viewport.viewport.context.drawImage(frames[frameNumber], this.x - 9, this.y - 9); - - this.ttl -= 1.65 / Settings.fps; - } -} diff --git a/src/sdk/ClickController.ts b/src/sdk/ClickController.ts deleted file mode 100644 index 810b63c8..00000000 --- a/src/sdk/ClickController.ts +++ /dev/null @@ -1,312 +0,0 @@ -import { filter } from "lodash"; -import { TileMarker } from "../content/TileMarker"; -import { ClickAnimation } from "./ClickAnimation"; -import { MenuOption } from "./ContextMenu"; -import { Entity } from "./Entity"; -import { EntityName } from "./EntityName"; -import { Item } from "./Item"; -import { Pathing } from "./Pathing"; -import { Settings } from "./Settings"; -import { Unit } from "./Unit"; -import { Viewport } from "./Viewport"; -import { MapController } from "./MapController"; -import { ControlPanelController } from "./ControlPanelController"; -import { Player } from "./Player"; -import { Mob } from "./Mob"; -import { World } from "./World"; -import { Region } from "./Region"; -import { InputController } from "./Input"; - -export class ClickController { - clickAnimation?: ClickAnimation = null; - viewport: Viewport; - - constructor(viewport: Viewport) { - this.viewport = viewport; - } - - eventListeners: ((e: MouseEvent) => void)[] = []; - - unload() { - this.viewport.canvas.removeEventListener("mousedown", this.eventListeners[0]); - this.viewport.canvas.removeEventListener("mouseup", this.eventListeners[1]); - this.viewport.canvas.removeEventListener("mousemove", this.eventListeners[2]); - this.viewport.canvas.removeEventListener("mousemove", this.eventListeners[3]); - this.viewport.canvas.removeEventListener("mousemove", this.eventListeners[4]); - this.viewport.canvas.removeEventListener("mousemove", this.eventListeners[5]); - this.viewport.canvas.removeEventListener("wheel", this.eventListeners[6]); - } - - registerClickActions() { - this.viewport.canvas.addEventListener("mousedown", (this.eventListeners[0] = this.clickDown.bind(this))); - this.viewport.canvas.addEventListener("mouseup", (this.eventListeners[1] = this.leftClickUp.bind(this))); - this.viewport.canvas.addEventListener( - "mousemove", - (this.eventListeners[2] = (e: MouseEvent) => ControlPanelController.controller.cursorMovedTo(e)), - ); - this.viewport.canvas.addEventListener( - "mousemove", - (this.eventListeners[3] = (e: MouseEvent) => MapController.controller.cursorMovedTo(e)), - ); - this.viewport.canvas.addEventListener( - "mousemove", - (this.eventListeners[4] = (e) => Viewport.viewport.contextMenu.cursorMovedTo(e.clientX, e.clientY)), - ); - this.viewport.canvas.addEventListener("mousemove", (this.eventListeners[5] = this.mouseMoved.bind(this))); - this.viewport.canvas.addEventListener("wheel", (this.eventListeners[6] = this.wheel.bind(this))); - } - - wheel(e: WheelEvent) { - Settings.zoomScale -= e.deltaY / 500; - - if (Settings.zoomScale < 0.5) { - Settings.zoomScale = 0.5; - } - - if (Settings.zoomScale > 2) { - Settings.zoomScale = 2; - } - - Settings.persistToStorage(); - } - - leftClickUp(e: MouseEvent) { - if (e.button !== 0) { - return; - } - - if (Settings.mobileCheck()) { - if (e.offsetX > 20 && e.offsetX < 60) { - if (e.offsetY > 20 && e.offsetY < 60) { - // reset button - location.reload(); - } - } - } - - const intercepted = ControlPanelController.controller.controlPanelClickUp(e); - if (intercepted) { - return; - } - } - - private recentlySelectedMobs: Mob[] = []; - - hasSelectedMob() { - return this.recentlySelectedMobs.length > 0; - } - - mouseMoved(e: MouseEvent) { - const world = Viewport.viewport.player.region.world; - const hoveredOn = Viewport.viewport.translateClick(e.offsetX, e.offsetY, world); - this.recentlySelectedMobs.forEach((mob) => { - mob.selected = false; - }); - this.recentlySelectedMobs = []; - if (hoveredOn && hoveredOn.type === "entities") { - const firstMob = hoveredOn.mobs.find(() => true); - if (firstMob) { - firstMob.selected = true; - this.recentlySelectedMobs.push(firstMob); - } - } - } - - private getClickedOn(e: MouseEvent, world: World, region: Region) { - const xAlign = - Viewport.viewport.contextMenu.location.x - Viewport.viewport.contextMenu.width / 2 < e.offsetX && - e.offsetX < Viewport.viewport.contextMenu.location.x + Viewport.viewport.contextMenu.width / 2; - const yAlign = - Viewport.viewport.contextMenu.location.y < e.offsetY && - e.offsetY < Viewport.viewport.contextMenu.location.y + Viewport.viewport.contextMenu.height; - - if (Viewport.viewport.contextMenu.isActive && xAlign && yAlign) { - Viewport.viewport.contextMenu.clicked(e.offsetX, e.offsetY); - Viewport.viewport.contextMenu.setInactive(); - return; - } - - const intercepted = MapController.controller.leftClickDown(e); - if (intercepted) { - return; - } - - const controlPanelIntercepted = ControlPanelController.controller.controlPanelClickDown(e); - if (controlPanelIntercepted) { - return; - } - const clickedOn = Viewport.viewport.translateClick(e.offsetX, e.offsetY, world); - if (!clickedOn) { - return null; - } - const { x, y } = clickedOn.location; - - const mobs: Mob[] = []; - const players: Player[] = []; - const groundItems: Item[] = []; - if (clickedOn.type === "entities") { - mobs.push(...clickedOn.mobs); - players.push(...clickedOn.players); - groundItems.push(...clickedOn.groundItems); - } - return { mobs, players, groundItems, x, y }; - } - - clickDown(e: MouseEvent) { - if (e.button === 2) { - this.rightClickDown(e); - } - - if (e.button !== 0) { - return; - } - const region = Viewport.viewport.player.region; // TODO: does this ned to go back? : as InfernoRegion; - const world = Viewport.viewport.player.region.world; - const player = Viewport.viewport.player; - - Viewport.viewport.contextMenu.cursorMovedTo(e.clientX, e.clientY); - const clickedOn = this.getClickedOn(e, world, region); - - if (!clickedOn) { - return; - } - - const { mobs, players, groundItems, x, y } = clickedOn; - - Viewport.viewport.player.interruptCombat(); - - const inputController = InputController.controller; - if (mobs.length && mobs[0].canBeAttacked()) { - this.redClick(); - inputController.queueAction(() => this.playerAttackClick(mobs[0])); - } else if (players.length) { - this.redClick(); - inputController.queueAction(() => this.playerAttackClick(players[0])); - } else if (groundItems.length) { - this.redClick(); - - inputController.queueAction(() => player.setSeekingItem(groundItems[0])); - } else if (x !== null && y !== null) { - this.yellowClick(); - inputController.queueAction(() => this.playerWalkClick(x, y)); - } - Viewport.viewport.contextMenu.setInactive(); - } - - rightClickDown(e: MouseEvent) { - const region = Viewport.viewport.player.region; // TODO: Redo as InfernoRegion; - const world = Viewport.viewport.player.region.world; - - Viewport.viewport.contextMenu.setPosition({ x: e.offsetX, y: e.offsetY }); - - if (ControlPanelController.controller.controlPanelRightClick(e)) { - return; - } - - if (MapController.controller.rightClick(e)) { - return; - } - - const clickedOn = this.getClickedOn(e, world, region); - - if (!clickedOn) { - return; - } - - const { mobs, players, groundItems, x, y } = clickedOn; - - Viewport.viewport.contextMenu.destinationLocation = { - x: Math.floor(x), - y: Math.floor(y), - }; - - /* gather options */ - let menuOptions: MenuOption[] = []; - - mobs.forEach((mob) => { - menuOptions = menuOptions.concat(mob.contextActions(region, x, y)); - }); - players.forEach((player) => { - if (player !== Viewport.viewport.player) { - menuOptions = menuOptions.concat(player.contextActions(region, x, y)); - } - }); - groundItems.forEach((item: Item) => { - menuOptions.push({ - text: [ - { text: "Take ", fillStyle: "white" }, - { text: item.itemName, fillStyle: "#FF911F" }, - ], - action: () => InputController.controller.queueAction(() => Viewport.viewport.player.setSeekingItem(item)), - }); - }); - - menuOptions.push( - { - text: [{ text: `Walk Here`, fillStyle: "white" }], - action: () => { - this.yellowClick(); - const x = Viewport.viewport.contextMenu.destinationLocation.x; - const y = Viewport.viewport.contextMenu.destinationLocation.y; - InputController.controller.queueAction(() => this.playerWalkClick(x, y)); - }, - }, - { - text: [{ text: "Mark / Unmark Tile", fillStyle: "white" }], - action: () => { - this.yellowClick(); - const x = Viewport.viewport.contextMenu.destinationLocation.x; - const y = Viewport.viewport.contextMenu.destinationLocation.y; - - let removed = false; - const entitiesAtPoint = Pathing.entitiesAtPoint(region, x, y, 1); - entitiesAtPoint.forEach((entity: TileMarker) => { - if (entity.entityName() === EntityName.TILE_MARKER && entity.saveable) { - region.removeEntity(entity); - removed = true; - } - }); - - if (!removed) { - region.addEntity(new TileMarker(Viewport.viewport.player.region, { x, y }, "#FF0000")); - } - - Settings.tile_markers = filter( - filter(region.entities, (entity: Entity) => entity.entityName() === EntityName.TILE_MARKER), - (tileMarker: TileMarker) => tileMarker.saveable, - ).map((entity: Entity) => entity.location); - - Settings.persistToStorage(); - }, - }, - ); - - menuOptions = menuOptions.concat(region.rightClickActions()); - - Viewport.viewport.contextMenu.setMenuOptions(menuOptions); - Viewport.viewport.contextMenu.setActive(); - } - - playerAttackClick(mob: Unit) { - Viewport.viewport.player.setAggro(mob); - } - - playerWalkClick(x: number, y: number) { - Viewport.viewport.player.moveTo(Math.floor(x), Math.floor(y)); - } - - redClick() { - this.clickAnimation = new ClickAnimation( - "red", - Viewport.viewport.contextMenu.cursorPosition.x, - Viewport.viewport.contextMenu.cursorPosition.y, - ); - } - yellowClick() { - this.clickAnimation = new ClickAnimation( - "yellow", - Viewport.viewport.contextMenu.cursorPosition.x, - Viewport.viewport.contextMenu.cursorPosition.y, - ); - } -} diff --git a/src/sdk/Collision.ts b/src/sdk/Collision.ts deleted file mode 100644 index 36ec207c..00000000 --- a/src/sdk/Collision.ts +++ /dev/null @@ -1,127 +0,0 @@ -import { filter } from "lodash"; -import { Entity } from "./Entity"; -import { LineOfSightMask } from "./LineOfSight"; -import { Mob } from "./Mob"; -import { Pathing } from "./Pathing"; -import { Player } from "./Player"; -import { Region } from "./Region"; -import { Settings } from "./Settings"; -import { Unit } from "./Unit"; - -export enum CollisionType { - NONE = 0, - BLOCK_MOVEMENT = 1, -} - -export class Collision { - static collisionMath(x: number, y: number, s: number, x2: number, y2: number, s2: number) { - return !(x > x2 + s2 - 1 || x + s - 1 < x2 || y - s + 1 > y2 || y < y2 - s2 + 1); - } - - // include the outer boundary - used for precision checks with perceivedLocation - static collisionMathInclusive(x: number, y: number, s: number, x2: number, y2: number, s2: number) { - return !(x > x2 + s2 || x + s - 1 < x2 || y - s > y2 || y < y2 - s2 + 1); - } - - // Mob collision - - static collidesWithMob(region: Region, x: number, y: number, s: number, mob: Unit) { - return Collision.collisionMath(x, y, s, mob.location.x, mob.location.y, mob.size); - } - - static collidesWithAnyMobs(region: Region, x: number, y: number, s: number, mobToAvoid: Unit = null) { - for (let i = 0; i < region.mobs.length; i++) { - if (region.mobs[i] === mobToAvoid) { - continue; - } - - const collidedWithSpecificMob = Collision.collidesWithMob(region, x, y, s, region.mobs[i]); - - if (collidedWithSpecificMob && region.mobs[i].consumesSpace) { - return region.mobs[i]; - } - } - return null; - } - - // Entity collision - - // Same as above but only returns entities with collision enabled. - static collideableEntitiesAtPoint(region: Region, x: number, y: number, s: number) { - return filter( - Pathing.entitiesAtPoint(region, x, y, s), - (entity: Entity) => entity.collisionType != CollisionType.NONE, - ); - } - - static collidesWithAnyEntities(region: Region, x: number, y: number, s: number) { - for (let i = 0; i < region.entities.length; i++) { - const entity = region.entities[i]; - if ( - entity.collisionType != CollisionType.NONE && - Collision.collisionMath(x, y, s, entity.location.x, entity.location.y, entity.size) - ) { - return true; - } - } - return false; - } - - static collidesWithAnyLoSBlockingEntities(region: Region, x: number, y: number, s: number): LineOfSightMask { - for (let i = 0; i < region.entities.length; i++) { - const entity = region.entities[i]; - if (Collision.collisionMath(x, y, s, entity.location.x, entity.location.y, entity.size)) { - return entity.lineOfSight; - } - } - return null; - } - - static collidesWithAnyMobsAtPerceivedDisplayLocation( - region: Region, - x: number, - y: number, - tickPercent: number, - ): Mob[] { - const mobs = []; - for (let i = 0; i < region.mobs.length; i++) { - const collidedWithSpecificMob = Collision.collidesWithUnitAtPerceivedDisplayLocation( - x, - y, - tickPercent, - region.mobs[i], - ); - if (collidedWithSpecificMob) { - mobs.push(region.mobs[i]); - } - } - return mobs; - } - - static collidesWithUnitAtPerceivedDisplayLocation(x: number, y: number, tickPercent: number, unit: Unit) { - const { x: perceivedX, y: perceivedY } = unit.getPerceivedLocation(tickPercent); - // WTF - return Collision.collisionMathInclusive(x, y, 1.0, perceivedX, perceivedY, unit.size); - } - - static collidesWithAnyPlayersAtPerceivedDisplayLocation( - region: Region, - x: number, - y: number, - tickPercent: number, - ): Player[] { - const players = []; - for (let i = 0; i < region.players.length; i++) { - const collidedWithSpecificPlayer = Collision.collidesWithUnitAtPerceivedDisplayLocation( - x, - y, - tickPercent, - region.players[i], - ); - if (collidedWithSpecificPlayer) { - players.push(region.players[i]); - } - } - return players; - } -} diff --git a/src/sdk/ContextMenu.ts b/src/sdk/ContextMenu.ts deleted file mode 100644 index 30f37a63..00000000 --- a/src/sdk/ContextMenu.ts +++ /dev/null @@ -1,164 +0,0 @@ -import { Location } from "./Location"; -import { Viewport } from "./Viewport"; - -export interface MultiColorTextBlock { - text: string; - fillStyle?: string; - font?: string; -} - -export interface MenuOption { - text: MultiColorTextBlock[]; - action: () => void; -} - -export class ContextMenu { - isActive = false; - location: Location = { x: 0, y: 0 }; - cursorPosition: Location = { x: 0, y: 0 }; - activatedPosition: Location = { x: 0, y: 0 }; - width = 0; - height = 0; - menuOptions: MenuOption[] = []; - linesOfText: MenuOption[] = []; - destinationLocation: Location; - - setPosition(position: Location) { - this.location = position; - } - - setActive() { - this.isActive = true; - } - - setInactive() { - this.isActive = false; - } - - setMenuOptions(menuOptions: MenuOption[]) { - this.menuOptions = menuOptions; - } - - cursorMovedTo(x: number, y: number) { - const cRect = Viewport.viewport.canvas.getBoundingClientRect(); // Gets CSS pos, and width/height - const canvasX = Math.round(x - cRect.left); // Subtract the 'left' of the canvas - const canvasY = Math.round(y - cRect.top); // from the X/Y positions to make - - this.cursorPosition.x = canvasX; - this.cursorPosition.y = canvasY; - - // cursor veering too far away, make inactive again - if (Math.abs(canvasX - this.location.x) > this.width * 0.6) { - this.setInactive(); - } - if (canvasY - this.location.y < -10 || canvasY - this.location.y > this.height * 1.2) { - this.setInactive(); - } - } - - draw() { - if (this.isActive) { - this.linesOfText = [ - { - text: [{ text: "Choose Option", fillStyle: "#5f5445" }], - action: () => { - Viewport.viewport.clickController.yellowClick(); - }, - }, - ...this.menuOptions, - { - text: [{ text: "Cancel", fillStyle: "white" }], - action: () => { - Viewport.viewport.clickController.yellowClick(); - }, - }, - ]; - Viewport.viewport.context.textAlign = "left"; - - Viewport.viewport.context.font = "17px OSRS"; - - this.width = 0; - this.linesOfText.forEach((line) => { - this.width = Math.max(this.width, this.fillMixedTextWidth(Viewport.viewport.context, line.text) + 10); - }); - - this.height = 22 + (this.linesOfText.length - 1) * 20; - - Viewport.viewport.context.fillStyle = "#5f5445"; - Viewport.viewport.context.fillRect(this.location.x - this.width / 2, this.location.y, this.width, this.height); - - Viewport.viewport.context.fillStyle = "black"; - Viewport.viewport.context.fillRect(this.location.x - this.width / 2 + 1, this.location.y + 1, this.width - 2, 17); - - Viewport.viewport.context.lineWidth = 1; - Viewport.viewport.context.strokeStyle = "black"; - Viewport.viewport.context.strokeRect( - this.location.x - this.width / 2 + 2, - this.location.y + 20, - this.width - 4, - this.height - 22, - ); - - for (let i = 0; i < this.linesOfText.length; i++) { - this.drawLineOfText(Viewport.viewport.context, this.linesOfText[i].text, this.width, i * 20); - } - } - Viewport.viewport.context.restore(); - } - - fillMixedText(ctx: CanvasRenderingContext2D, text: MultiColorTextBlock[], x: number, y: number, inputColor: string) { - const defaultFillStyle = ctx.fillStyle; - const defaultFont = ctx.font; - - ctx.save(); - text.forEach(({ text, fillStyle, font }: { text: string; fillStyle: string; font: string }) => { - ctx.font = font || defaultFont; - - ctx.fillStyle = "black"; - ctx.fillText(text, x + 1, y + 1); - - if (fillStyle === "white") { - ctx.fillStyle = inputColor; - } else { - ctx.fillStyle = fillStyle || defaultFillStyle; - } - ctx.fillText(text, x, y); - x += ctx.measureText(text).width; - }); - ctx.restore(); - } - - fillMixedTextWidth(ctx: CanvasRenderingContext2D, text: MultiColorTextBlock[]) { - const defaultFillStyle = ctx.fillStyle; - const defaultFont = ctx.font; - - let x = 0; - text.forEach(({ text, fillStyle, font }: { text: string; fillStyle: string; font: string }) => { - ctx.fillStyle = fillStyle || defaultFillStyle; - ctx.font = font || defaultFont; - x += ctx.measureText(text).width; - }); - return x; - } - - drawLineOfText(ctx: CanvasRenderingContext2D, text: MultiColorTextBlock[], width: number, y: number) { - const isXAligned = - this.cursorPosition.x > this.location.x - width / 2 && this.cursorPosition.x < this.location.x + width / 2; - const isYAligned = - this.cursorPosition.y > this.location.y + y + 2 && this.cursorPosition.y < this.location.y + 21 + y; - const isHovered = isXAligned && isYAligned; - - this.fillMixedText( - ctx, - text, - this.location.x - width / 2 + 4, - this.location.y + 15 + y, - isHovered ? "yellow" : "white", - ); - } - - clicked(x: number, y: number) { - const index = Math.floor((y - this.location.y) / 20); - this.linesOfText[index].action(); - } -} diff --git a/src/sdk/ControlPanelController.ts b/src/sdk/ControlPanelController.ts deleted file mode 100644 index c0e433f8..00000000 --- a/src/sdk/ControlPanelController.ts +++ /dev/null @@ -1,369 +0,0 @@ -"use strict"; -import { AccountControls } from "./controlpanels/AccountControls"; -import { AncientsSpellbookControls } from "./controlpanels/AncientsSpellbookControls"; -import { BaseControls } from "./controlpanels/BaseControls"; -import { ClanChatControls } from "./controlpanels/ClanChatControls"; -import { CombatControls } from "./controlpanels/CombatControls"; -import { EmotesControls } from "./controlpanels/EmotesControls"; -import { EmptyControls } from "./controlpanels/EmptyControls"; -import { EquipmentControls } from "./controlpanels/EquipmentControls"; -import { FriendsControls } from "./controlpanels/FriendsControls"; -import { InventoryControls } from "./controlpanels/InventoryControls"; -import { MusicControls } from "./controlpanels/MusicControls"; -import { PrayerControls } from "./controlpanels/PrayerControls"; -import { QuestsControls } from "./controlpanels/QuestsControls"; -import { SettingsControls } from "./controlpanels/SettingsControls"; -import { StatsControls } from "./controlpanels/StatsControls"; -import { Settings } from "./Settings"; -import { Location } from "./Location"; -import { Chrome } from "./Chrome"; -import { MapController } from "./MapController"; -import { Viewport } from "./Viewport"; -import { BoostPanel } from "./BoostPanel"; - -interface TabPosition { - x: number; - y: number; -} - -const BASE_WIDTH = 33 * 7; -const BASE_HEIGHT = 36 * 2 + 275; - -export class ControlPanelController { - static controls = Object.freeze({ - COMBAT: new CombatControls(), - INVENTORY: new InventoryControls(), - PRAYER: new PrayerControls(), - EQUIPMENT: new EquipmentControls(), - STATS: new StatsControls(), - ANCIENTSSPELLBOOK: new AncientsSpellbookControls(), - }); - - static controller = new ControlPanelController(); - - desktopControls: BaseControls[]; - mobileControls: BaseControls[]; - controls: BaseControls[]; - selectedControl: BaseControls; - - public width: number; - public height: number; - - private boostPanel = new BoostPanel(); - - isUsingExternalUI = false; - - constructor() { - this.width = BASE_WIDTH; - this.height = BASE_HEIGHT; - - this.desktopControls = [ - ControlPanelController.controls.COMBAT, - ControlPanelController.controls.STATS, - new QuestsControls(), - ControlPanelController.controls.INVENTORY, - ControlPanelController.controls.EQUIPMENT, - ControlPanelController.controls.PRAYER, - ControlPanelController.controls.ANCIENTSSPELLBOOK, - new EmptyControls(), - new FriendsControls(), - new AccountControls(), - new ClanChatControls(), - new SettingsControls(), - new EmotesControls(), - new MusicControls(), - ]; - - this.mobileControls = [ - ControlPanelController.controls.COMBAT, - ControlPanelController.controls.PRAYER, - ControlPanelController.controls.ANCIENTSSPELLBOOK, - new EmotesControls(), - new ClanChatControls(), - new FriendsControls(), - new AccountControls(), - - // break - ControlPanelController.controls.INVENTORY, - ControlPanelController.controls.EQUIPMENT, - ControlPanelController.controls.STATS, - new QuestsControls(), - new MusicControls(), - new SettingsControls(), - new EmptyControls(), - ]; - this.controls = Settings.mobileCheck() ? this.mobileControls : this.desktopControls; - - this.selectedControl = ControlPanelController.controls.PRAYER; - document.addEventListener("keydown", (event) => { - if (Settings.is_keybinding) { - return; - } - - if (this.isUsingExternalUI) { - return; - } - - this.controls.forEach((control) => { - if (control.keyBinding === event.key) { - this.selectedControl = control; - event.preventDefault(); - } - }); - }); - } - - getTabScale() { - const { width, height } = Chrome.size(); - - const controlAreaHeight = height - MapController.controller.height; - let scaleRatio = controlAreaHeight / 7 / 36; - - let maxScaleRatio = Settings.maxUiScale; - if (Settings.mobileCheck() && width > 600) { - maxScaleRatio = Settings.maxUiScale * 1.1; - } - - if (scaleRatio > maxScaleRatio) { - scaleRatio = maxScaleRatio; - } - - // not the best place for these setters... - Settings.controlPanelScale = scaleRatio * 0.915; - this.width = BASE_WIDTH * scaleRatio; - this.height = BASE_HEIGHT * scaleRatio; - - return scaleRatio; - } - - boostPosition() { - const { width, height } = Chrome.size(); - const scale = this.getTabScale(); - if (Settings.mobileCheck()) { - const mapHeight = 170 * Settings.minimapScale; - const spacer = (height - mapHeight - 36 * scale * 7) / 2; - return { x: 15, y: mapHeight + spacer }; - } else { - return { - x: width - 231 * scale - (Settings.menuVisible ? 232 : 0) + 28, - y: height - 72 * scale, - }; - } - } - - tabPosition(i: number): TabPosition { - // let scale = Settings.controlPanelScale - const { width, height } = Chrome.size(); - const scale = this.getTabScale(); - - if (Settings.mobileCheck()) { - const mapHeight = 170 * Settings.minimapScale; - const spacer = (height - mapHeight - 36 * scale * 7) / 2; - if (i < 7) { - return { x: 15, y: mapHeight + spacer + i * 36 * scale }; - } else { - return { - x: width - 33 * scale - 15 - (Settings.menuVisible ? 232 : 0), - y: mapHeight + spacer + (i - 7) * 36 * scale, - }; - } - } else { - const x = i % 7; - const y = Math.floor(i / 7); - return { - x: width - 231 * scale + x * 33 * scale - (Settings.menuVisible ? 232 : 0), - y: height - 72 * scale + y * 36 * scale, - }; - } - } - cursorMovedTo(e: MouseEvent) { - const scale = Settings.controlPanelScale; - if (this.selectedControl) { - const x = e.offsetX; - const y = e.offsetY; - - const panelWidth = 204 * scale; - const panelHeight = 275 * scale; - const panelPosition = this.controlPosition(this.selectedControl); - const panelX = panelPosition.x; - const panelY = panelPosition.y; - if (panelX < x && x < panelX + panelWidth) { - if (panelY < y && y < panelY + panelHeight) { - const relativeX = x - panelX; - const relativeY = y - panelY; - this.selectedControl.cursorMovedto(relativeX, relativeY); - } - } - } - } - controlPanelRightClick(e: MouseEvent): boolean { - let intercepted = false; - - const scale = Settings.controlPanelScale; - const x = e.offsetX; - const y = e.offsetY; - - const panelWidth = 204 * scale; - const panelHeight = 275 * scale; - const panelPosition = this.controlPosition(this.selectedControl); - const panelX = panelPosition.x; - const panelY = panelPosition.y; - if (panelX < x && x < panelX + panelWidth) { - if (panelY < y && y < panelY + panelHeight) { - const relativeX = x - panelX; - const relativeY = y - panelY; - intercepted = true; - this.selectedControl.panelRightClick(relativeX, relativeY); - } - } - - return intercepted; - } - - controlPanelClickUp(e: MouseEvent): boolean { - const scale = Settings.controlPanelScale; - if (!this.selectedControl) { - return false; - } - - let intercepted = false; - - const x = e.offsetX; - const y = e.offsetY; - - const panelWidth = 204 * scale; - const panelHeight = 275 * scale; - const panelPosition = this.controlPosition(this.selectedControl); - const panelX = panelPosition.x; - const panelY = panelPosition.y; - if (panelX < x && x < panelX + panelWidth) { - if (panelY < y && y < panelY + panelHeight) { - const relativeX = x - panelX; - const relativeY = y - panelY; - intercepted = true; - this.selectedControl.panelClickUp(relativeX, relativeY); - } - } - - return intercepted; - } - - controlPanelClickDown(e: MouseEvent): boolean { - let intercepted = false; - - const scale = Settings.controlPanelScale; - - const x = e.offsetX; - const y = e.offsetY; - - this.controls.forEach((control: BaseControls, index: number) => { - const tabPosition = this.tabPosition(index); - if (tabPosition.x <= x && x < tabPosition.x + 33 * scale) { - if (tabPosition.y <= y && y < tabPosition.y + 36 * scale) { - intercepted = true; - if (this.controls[index] === this.selectedControl) { - this.selectedControl = null; - return; - } - this.selectedControl = this.controls[index]; - } - } - }); - - if (!this.selectedControl) { - return intercepted; - } - - const panelWidth = 204 * scale; - const panelHeight = 275 * scale; - const panelPosition = this.controlPosition(this.selectedControl); - const panelX = panelPosition.x; - const panelY = panelPosition.y; - if (panelX < x && x < panelX + panelWidth) { - if (panelY < y && y < panelY + panelHeight) { - const relativeX = x - panelX; - const relativeY = y - panelY; - intercepted = true; - this.selectedControl.panelClickDown(relativeX, relativeY); - } - } - - return intercepted; - } - - controlPosition(control: BaseControls): Location { - const scale = this.getTabScale(); - const { width, height } = Chrome.size(); - - if (Settings.mobileCheck()) { - const mapHeight = 170 * Settings.minimapScale; - const spacer = (height - mapHeight - 36 * scale * 7) / 2; - if (this.selectedControl.appearsOnLeftInMobile) { - // left side mobile - return { x: 33 * scale + 15, y: mapHeight + spacer }; - } else { - // right side mobile - return { - x: width - 33 * scale - 15 - 200 * Settings.controlPanelScale - (Settings.menuVisible ? 232 : 0), - y: mapHeight + spacer, - }; - } - } else { - // desktop compact - return { - x: width - 188 * scale - (Settings.menuVisible ? 232 : 0), - y: height - 72 * scale - 251 * scale, - }; - } - } - - onWorldTick() { - this.controls.forEach((control) => { - control.onWorldTick(); - }); - } - - draw(context: CanvasRenderingContext2D) { - Viewport.viewport.context.fillStyle = "#000"; - const scale = this.getTabScale(); - - if (this.selectedControl && this.selectedControl.draw) { - const position = this.controlPosition(this.selectedControl); - this.selectedControl.draw(context, this, position.x, position.y); - } - - // TODO: make this rendering configurable - const boostPosition = this.boostPosition(); - this.boostPanel.draw(context, scale, boostPosition.x, boostPosition.y); - - let selectedPosition: TabPosition = null; - - this.controls.forEach((control, index) => { - const tabPosition = this.tabPosition(index); - if (control.tabImage) { - context.drawImage( - control.tabImage, - tabPosition.x, - tabPosition.y, - control.tabImage.width * scale, - control.tabImage.height * scale, - ); - } - - if (control.isAvailable === false) { - context.fillStyle = "#00000099"; - context.fillRect(tabPosition.x, tabPosition.y, 33 * scale, 36 * scale); - } - - if (control === this.selectedControl) { - selectedPosition = tabPosition; - } - }); - - if (selectedPosition) { - context.strokeStyle = "#00FF0073"; - context.lineWidth = 3; - context.strokeRect(selectedPosition.x, selectedPosition.y, 33 * scale, 36 * scale); - } - } -} diff --git a/src/sdk/DelayedAction.ts b/src/sdk/DelayedAction.ts deleted file mode 100644 index ffc6c58c..00000000 --- a/src/sdk/DelayedAction.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { remove } from "lodash"; - -export class DelayedAction { - // actions to be played after npc action (before players) - static delayedNpcActions: DelayedAction[] = []; - // actions to be played after player action - static delayedActions: DelayedAction[] = []; - action: () => void; - delay: number; - identifier: number; - constructor(action: () => void, delay: number) { - this.action = action; - this.delay = delay + 1; - this.identifier = Math.random() * 1000000; - } - - static reset() { - this.delayedActions = []; - this.delayedNpcActions = []; - } - - /** - * Register a delayed action to be called in the middle of a tick (after npc actions, before player actions). - * Use this if you need an action that reads from an NPC and writes to a player in the same tick. - */ - static registerDelayedNpcAction(delayedAction: DelayedAction): number { - DelayedAction.delayedNpcActions.push(delayedAction); - return delayedAction.identifier; - } - - /** - * Register a delayed action to be called at the end of the tick (after player action) - */ - static registerDelayedAction(delayedAction: DelayedAction): number { - DelayedAction.delayedActions.push(delayedAction); - return delayedAction.identifier; - } - - static afterNpcTick() { - const executedActions: DelayedAction[] = []; - DelayedAction.delayedNpcActions.forEach((delayedAction) => { - delayedAction.delay--; - if (delayedAction.delay === 0) { - delayedAction.action(); - executedActions.push(delayedAction); - } - }); - - executedActions.forEach((executedActions: DelayedAction) => { - remove(DelayedAction.delayedNpcActions, executedActions); - }); - } - - static tick() { - const executedActions: DelayedAction[] = []; - DelayedAction.delayedActions.forEach((delayedAction) => { - delayedAction.delay--; - if (delayedAction.delay === 0) { - delayedAction.action(); - executedActions.push(delayedAction); - } - }); - - executedActions.forEach((executedActions: DelayedAction) => { - remove(DelayedAction.delayedActions, executedActions); - }); - } -} diff --git a/src/sdk/Eating.ts b/src/sdk/Eating.ts deleted file mode 100644 index 3e2994e4..00000000 --- a/src/sdk/Eating.ts +++ /dev/null @@ -1,95 +0,0 @@ -"use strict"; -import { Potion } from "./gear/Potion"; -import { Food } from "./gear/Food"; -import { Karambwan } from "../content/items/Karambwan"; -import { Player } from "./Player"; - -export class Eating { - player: Player; - foodDelay = 0; - potionDelay = 0; - comboDelay = 0; - - currentFood: Food; - currentPotion: Potion; - currentComboFood: Karambwan; - redemptioned = false; - - tickFood(player: Player) { - this.foodDelay--; - this.potionDelay--; - this.comboDelay--; - if (this.currentFood) { - this.currentFood.eat(player); - player.attackDelay += 3; - this.currentFood = null; - } - if (this.currentPotion) { - this.currentPotion.drink(player); - this.currentPotion = null; - } - if (this.currentComboFood) { - this.currentComboFood.eat(player); - player.attackDelay += 3; - this.currentComboFood = null; - } - } - - checkRedemption(player: Player) { - if (this.redemptioned) { - player.currentStats.prayer = 0; - player.currentStats.hitpoint += Math.floor(player.stats.prayer / 4); - this.redemptioned = false; - } - } - - canEatFood(): boolean { - return this.foodDelay <= 0; - } - - canDrinkPotion(): boolean { - return this.potionDelay <= 0; - } - - canEatComboFood(): boolean { - return this.comboDelay <= 0; - } - - // The weird way that the lower tiers also eat the higher tiers forces the behavior of food -> potion -> karambwan - eatFood(food: Food) { - if (!this.canEatFood()) { - return; - } - this.currentFood = food || null; - this.foodDelay = 3; - if (this.currentFood) { - this.currentFood.consumeItem(this.player); - } - } - - drinkPotion(potion: Potion) { - if (!this.canDrinkPotion()) { - return false; - } - this.currentPotion = potion || null; - this.foodDelay = 3; - this.potionDelay = 3; - if (this.currentPotion) { - this.currentPotion.doses--; - } - return true; - } - - eatComboFood(karambwan: Karambwan) { - if (!this.canEatComboFood()) { - return; - } - this.foodDelay = 3; - this.potionDelay = 3; - this.currentComboFood = karambwan || null; - this.comboDelay = 3; - if (this.currentComboFood) { - this.currentComboFood.consumeItem(this.player); - } - } -} diff --git a/src/sdk/Entity.ts b/src/sdk/Entity.ts deleted file mode 100644 index de5427f4..00000000 --- a/src/sdk/Entity.ts +++ /dev/null @@ -1,128 +0,0 @@ -"use strict"; -import { Location } from "./Location"; -import { Settings } from "./Settings"; -import { UnitTypes } from "./Unit"; -import { EntityName } from "./EntityName"; -import { Region } from "./Region"; -import { clamp } from "lodash"; -import { CollisionType } from "./Collision"; -import { LineOfSightMask } from "./LineOfSight"; -import { Renderable } from "./Renderable"; - -export class Entity extends Renderable { - region: Region; - location: Location; - dying = -1; - _serialNumber: string; - get serialNumber(): string { - if (!this._serialNumber) { - this._serialNumber = String(Math.random()); - } - return this._serialNumber; - } - - // entities are not selectable by default - get selectable() { - return false; - } - - shouldDestroy() { - return this.dying === 0; - } - - get size() { - return 1; - } - - isDying() { - return this.dying > 0; - } - - get collisionType() { - return CollisionType.BLOCK_MOVEMENT; - } - - get lineOfSight(): LineOfSightMask { - return LineOfSightMask.FULL_MASK; - } - - // Returns true if this game object is on the specified tile. - isOnTile(x: number, y: number) { - return ( - x >= this.location.x && - x <= this.location.x + this.size && - y <= this.location.y && - y >= this.location.y - this.size - ); - } - - // Returns the closest tile on this mob to the specified point. - getClosestTileTo(x: number, y: number) { - // We simply clamp the target point to our own boundary box. - return [ - clamp(x, this.location.x, this.location.x + this.size - 1), - clamp(y, this.location.y - this.size + 1, this.location.y), - ]; - } - - entityName(): EntityName { - return null; - } - - constructor(region: Region, location: Location) { - super(); - this.location = location; - this.region = region; - } - - getPerceivedLocation(tickPercent: number) { - return { - ...this.location, - z: 0, - }; - } - - getPerceivedRotation() { - return 0; - } - - getTrueLocation() { - return this.location; - } - - get color() { - return "#000073"; - } - - get type() { - // Kind of odd that Units live inside the unit class, but this isn't a unit - return UnitTypes.ENTITY; - } - - tick() { - // Override me - } - - drawUILayer( - tickPercent: number, - screenPosition: Location, - context: OffscreenCanvasRenderingContext2D, - scale: number, - hitsplatAbove = true) { - // Override me - } - - draw(tickPercent: number, context: OffscreenCanvasRenderingContext2D) { - context.fillStyle = "#000073"; - context.fillRect( - this.location.x * Settings.tileSize, - (this.location.y - this.size + 1) * Settings.tileSize, - this.size * Settings.tileSize, - this.size * Settings.tileSize, - ); - } - - get animationIndex() { - return -1; - } -} diff --git a/src/sdk/EntityName.ts b/src/sdk/EntityName.ts deleted file mode 100644 index b6203595..00000000 --- a/src/sdk/EntityName.ts +++ /dev/null @@ -1,21 +0,0 @@ -"use strict"; - -export enum EntityName { - TILE_MARKER = "Tile Marker", - INFERNO_SHIELD = "Inferno Shield", - TZ_KAL_ZUK = "TzKal-Zuk", - JAL_XIL = "Jal-Xil", - JAL_ZEK = "Jal-Zek", - YT_HUR_KOT = "Yt-HurKot", - JAL_TOK_JAD = "JalTok-Jad", - JAL_NIB = "Jal-Nib", - JAL_MEJ_RAJ = "Jal-MejRah", - JAL_MEJ_JAK = "Jal-MejJak", - JAL_IM_KOT = "Jal-ImKot", - JAL_AK_REK_XIL = "Jal-AkRek-Xil", - JAL_AK_REK_MEJ = "Jal-AkRek-Mej", - JAL_AK_REK_KET = "Jal-AkRek-Ket", - JAL_AK = "Jal-Ak", - PILLAR = "Pillar", - SOL_HEREDIT = "Sol Heredit", -} diff --git a/src/sdk/Equipment.ts b/src/sdk/Equipment.ts deleted file mode 100644 index c9f9d9ae..00000000 --- a/src/sdk/Equipment.ts +++ /dev/null @@ -1,108 +0,0 @@ -import { Item } from "./Item"; -import { UnitBonuses, UnitEquipment } from "./Unit"; -import { SetEffect } from "./SetEffect"; -import { Player } from "./Player"; - -export enum EquipmentTypes { - HELMET = "helmet", - CHEST = "chest", - LEGS = "legs", - FEET = "feet", - GLOVES = "gloves", - WEAPON = "weapon", - OFFHAND = "offhand", - AMMO = "ammo", - BACK = "back", - NECK = "neck", - RING = "ring", -} - -// maybe we ought to rename the values instead? -export const EQUIPMENT_TYPE_TO_SLOT: {[equipmentType in EquipmentTypes]: keyof UnitEquipment} = { - [EquipmentTypes.HELMET]: 'helmet', - [EquipmentTypes.CHEST]: "chest", - [EquipmentTypes.LEGS]: "legs", - [EquipmentTypes.FEET]: "feet", - [EquipmentTypes.GLOVES]: "gloves", - [EquipmentTypes.WEAPON]: "weapon", - [EquipmentTypes.OFFHAND]: "offhand", - [EquipmentTypes.AMMO]: "ammo", - [EquipmentTypes.BACK]: "cape", - [EquipmentTypes.NECK]: "necklace", - [EquipmentTypes.RING]: "ring" -}; - -export class Equipment extends Item { - bonuses: UnitBonuses; - - constructor() { - super(); - this.defaultAction = "Equip"; - this.setStats(); - } - - get hasInventoryLeftClick(): boolean { - return true; - } - - inventoryLeftClick(player: Player) { - const currentItem = this.currentEquipment(player) || null; - const openInventorySlots = player.openInventorySlots(); - openInventorySlots.unshift(player.inventory.indexOf(this)); - this.assignToPlayer(player); - player.inventory[openInventorySlots.shift()] = currentItem; - player.equipmentChanged(); - } - - get equipmentSetEffect(): typeof SetEffect { - return null; - } - - setStats() { - // throw new Error('stats must be set, none were found') - } - - currentEquipment(player: Player): Equipment { - return null; - } - - assignToPlayer(player: Player) { - throw new Error("not able to assign to unit equipment"); - } - - unassignToPlayer(player: Player) { - throw new Error("not able to unassign to unit equipment"); - } - - unequip(player: Player) { - const openInventorySlots = player.openInventorySlots(); - if (openInventorySlots.length === 0) { - return; - } - this.unassignToPlayer(player); - player.equipmentChanged(); - player.inventory[openInventorySlots.shift()] = this; - } - - get type(): EquipmentTypes { - throw new Error("equipment must have a type"); - } - - updateBonuses(gear: Item[]) { - // update bonuses based on other items that have been equipped - } - - /** - * name of the model to render for this item - */ - get model(): string | null { - return null; - } - - /** - * index of animation to use for attacks if possible - */ - get attackAnimationId(): number | null { - return null; - } -} diff --git a/src/sdk/Input.ts b/src/sdk/Input.ts deleted file mode 100644 index 040956d1..00000000 --- a/src/sdk/Input.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { Settings } from "./Settings"; - -const MAX_QUEUED_ACTIONS = 8; - -/** - * Controller to manage delayed inputs (due to input lag and/or tick timers) - */ -export class InputController { - inputDelay?: ReturnType = null; - - queuedActions: (() => void)[] = []; - - static controller = new InputController(); - - queueAction(fn: () => void) { - /*if (this.inputDelay) { - clearTimeout(this.inputDelay); - }*/ - if (this.queuedActions.length >= MAX_QUEUED_ACTIONS) { - return; - } - this.inputDelay = setTimeout(() => { - this.queuedActions.push(fn); - }, Settings.inputDelay); - } - - onWorldTick() { - const actions = this.flushQueuedActions(); - actions.forEach((action) => action()); - } - - private flushQueuedActions() { - const actions = this.queuedActions; - this.queuedActions = []; - return actions; - } -} diff --git a/src/sdk/Item.ts b/src/sdk/Item.ts deleted file mode 100644 index 18387230..00000000 --- a/src/sdk/Item.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { Location } from "./Location"; -import { ItemName } from "./ItemName"; -import { Player } from "./Player"; - -export class Item { - groundLocation: Location; - inventorySprite: HTMLImageElement; - selected: boolean; - defaultAction = "Use"; - _serialNumber: string; - - get serialNumber(): string { - if (!this._serialNumber) { - this._serialNumber = String(Math.random()); - } - return this._serialNumber; - } - - get hasInventoryLeftClick(): boolean { - return false; - } - - inventoryLeftClick(player: Player) { - // Override me - } - - contextActions(player: Player) { - // use - // drop - // examine - const options = [ - { - text: [ - { text: "Drop ", fillStyle: "white" }, - { text: this.itemName, fillStyle: "#FF911F" }, - ], - action: () => { - player.region.addGroundItem(player, this, player.location.x, player.location.y); - this.consumeItem(player); - }, - }, - { - text: [ - { text: "Examine ", fillStyle: "white" }, - { text: this.itemName, fillStyle: "#FF911F" }, - ], - action: () => { - // TODO: Examine feature - }, - }, - ]; - - if (this.defaultAction) { - options.unshift({ - text: [ - { text: this.defaultAction + " ", fillStyle: "white" }, - { text: this.itemName, fillStyle: "#FF911F" }, - ], - action: () => { - this.inventoryLeftClick(player); - }, - }); - } - - return options; - } - - get itemName(): ItemName { - return null; - } - - get weight(): number { - return 0; - } - - inventoryPosition(player: Player): number { - return player.inventory - .map((item: Item) => { - if (!item) { - return null; - } - return item.serialNumber; - }) - .indexOf(this.serialNumber); - } - - consumeItem(player: Player) { - player.inventory[this.inventoryPosition(player)] = null; - } - - get inventoryImage(): string { - return ""; - } -} diff --git a/src/sdk/ItemName.ts b/src/sdk/ItemName.ts deleted file mode 100644 index a27ac5c7..00000000 --- a/src/sdk/ItemName.ts +++ /dev/null @@ -1,74 +0,0 @@ -export enum ItemName { - BLOOD_BARRAGE = "Blood Barrage", - ICE_BARRAGE = "Ice Barrage", - AHRIMS_ROBETOP = "Ahrim's robetop", - AHRIMS_ROBESKIRT = "Ahrim's robeskirt", - ANCESTRAL_ROBEBOTTOM = "Ancestral Robe bottom", - ANCESTRAL_ROBETOP = "Ancestral Robe top", - ANCIENT_STAFF = "Ancient staff", - ARMADYL_CHAINSKIRT = "Armadyl Chainskirt", - ARMADYL_CHESTPLATE = "Armadyl Chestplate", - AVAS_ACCUMULATOR = "Ava's accumulator", - AVAS_ASSEMBLER = "Avas Assembler", - BARROWS_GLOVES = "Barrows Gloves", - BASTION_POTION = "Bastion Potion", - BLACK_D_HIDE_BODY = "Black d'hide body", - BLACK_D_HIDE_CHAPS = "Black d'hide chaps", - BLACK_D_HIDE_VAMBRACES = "Black d'hide vambraces", - BLACK_CHINCHOMPA = "Black chinchompa", - BOWFA = "Bow of faerdhinen", - CRYSTAL_BODY = "Crystal Body", - CRYSTAL_HELM = "Crystal Helm", - CRYSTAL_LEGS = "Crystal Legs", - CRYSTAL_SHIELD = "Crystal Shield", - DAGON_HAI_ROBE_TOP = "Dagon'hai robe top", - DEVOUT_BOOTS = "Devout Boots", - DIAMOND_BOLTS_E = "Diamond bolts (e)", - DRAGON_ARROWS = "Dragon arrow", - GUTHIX_ROBE_TOP = "Guthix robe top", - HOLY_BLESSING = "Holy Blessing", - JUSTICIAR_CHESTGUARD = "Justiciar Chestguard", - JUSTICIAR_FACEGUARD = "Justiciar Faceguard", - JUSTICIAR_LEGGUARDS = "Justiciar Legguards", - KARAMBWAN = "Karambwan", - KODAI_WAND = "Kodai Wand", - MAGES_BOOK = "Mage's Book", - NECKLACE_OF_ANGUISH = "Necklace of Anguish", - OCCULT_NECKLACE = "Occult necklace", - PEGASIAN_BOOTS = "Pegasian Boots", - RANGER_BOOTS = "Ranger boots", - RING_OF_ENDURANCE = "Ring of Endurance", - RING_OF_SUFFERING_I = "Ring of Suffering (i)", - ROBIN_HOOD_HAT = "Robin hood hat", - RUBY_BOLTS_E = "Ruby bolts (e)", - RUNE_CROSSBOW = "Rune Crossbow", - RUNE_KITESHIELD = "Rune kiteshield", - SARADOMIN_BREW = "Saradomin Brew", - SARADOMIN_COIF = "Saradomin coif", - SARADOMIN_D_HIDE_BODY = "Saradomin d'hide body", - SARADOMIN_D_HIDE_BOOTS = "Saradomin d'hide boots", - SARADOMIN_D_HIDE_CHAPS = "Saradomin chaps", - SCYTHE_OF_VITUR = "Scythe of Vitur", - SHARK = "Shark", - SLAYER_HELMET_I = "Slayer helm (i)", - STAMINA_POTION = "Stamina Potion", - SUPER_RESTORE = "Super Restore", - TOXIC_BLOWPIPE = "Toxic Blowpipe", - TWISTED_BOW = "Twisted Bow", - ZARYTE_VAMBRACES = "Zaryte Vambraces", - MASORI_CHAPS_F = "Masori chaps (f)", - MASORI_BODY_F = "Masori body (f)", - MASORI_MASK_F = "Masori mask (f)", - DIZANAS_QUIVER = "Dizana's Quiver", - TORVA_PLATEBODY = "Torva platebody", - TORVA_PLATELEGS = "Torva platelegs", - TORVA_FULL_HELM = "Torva full helm", - AMULET_OF_TORTURE = "Amulet of torture", - PRIMORDIAL_BOOTS = "Primordial boots", - FEROCIOUS_GLOVES = "Ferocious gloves", - INFERNAL_CAPE = "Infernal cape", - SUPER_COMBAT_POTION = "Super combat potion", - BLADE_OF_SAELDOR = "Blade of saeldor", - AVERNIC_DEFENDER = "Avernic defender", - ULTOR_RING = "Ultor ring", -} diff --git a/src/sdk/LineOfSight.ts b/src/sdk/LineOfSight.ts deleted file mode 100644 index e37a9931..00000000 --- a/src/sdk/LineOfSight.ts +++ /dev/null @@ -1,179 +0,0 @@ -"use strict"; - -import { Settings } from "./Settings"; -import { Pathing } from "./Pathing"; -import { Collision } from "./Collision"; -import { Region } from "./Region"; -import { Player } from "./Player"; -import { Unit } from "./Unit"; - -/* - Basically, this entire file is lifted and modified to be as coherent as possible. - This algorithm makes no sense and is copy pasta'd between basically every trainer. - I have no clue how it works. I think Woox made a video that helps people understand it. - https://www.youtube.com/watch?v=vnyNLXTwjCE -*/ - -export enum LineOfSightMask { - NONE = 0x0, - FULL_MASK = 0x20000, - EAST_MASK = 0x1000, - WEST_MASK = 0x10000, - NORTH_MASK = 0x400, - SOUTH_MASK = 0x4000, -} - -export class LineOfSight { - static drawLOS(region: Region, x: number, y: number, s: number, r: number, c: string, isNPC: boolean) { - region.context.globalAlpha = 0.4; - region.context.fillStyle = c; - - for (let x2 = -r; x2 < r + 1; x2++) { - for (let y2 = -r; y2 < r + 1; y2++) { - if (LineOfSight.hasLineOfSight(region, x, y, x + x2, y + y2, s, r, isNPC)) { - region.context.fillRect( - (x + x2) * Settings.tileSize, - (y + y2) * Settings.tileSize, - Settings.tileSize, - Settings.tileSize, - ); - } - } - } - region.context.globalAlpha = 1; - } - - static mobHasLineOfSightOfPlayer( - region: Region, - player: Player, - x: number, - y: number, - s: number, - r = 1, - isNPC = true, - ) { - return LineOfSight.hasLineOfSight(region, x, y, player.location.x, player.location.y, s, r, isNPC); - } - - static playerHasLineOfSightOfMob(region: Region, x: number, y: number, mob: Unit, r = 1) { - const mobPoint = Pathing.closestPointTo(x, y, mob); - return LineOfSight.hasLineOfSight(region, x, y, mobPoint.x, mobPoint.y, 1, r, false); - } - static mobHasLineOfSightToMob(region: Region, mob1: Unit, mob2: Unit, r = 1) { - const mob1Point = Pathing.closestPointTo(mob1.location.x, mob1.location.y, mob2); - const mob2Point = Pathing.closestPointTo(mob2.location.x, mob2.location.y, mob1); - return LineOfSight.hasLineOfSight(region, mob1Point.x, mob1Point.y, mob2Point.x, mob2Point.y, 1, r, false); - } - - static hasLineOfSight( - region: Region, - x1: number, - y1: number, - x2: number, - y2: number, - s = 1, - r = 1, - isNPC = false, - ): boolean { - const dx = x2 - x1; - const dy = y2 - y1; - if ( - Collision.collidesWithAnyLoSBlockingEntities(region, x1, y1, 1) || - Collision.collidesWithAnyLoSBlockingEntities(region, x2, y2, 1) || - Collision.collisionMath(x1, y1, s, x2, y2, 1) - ) { - return false; - } - // assume range 1 is melee - if (r === 1) { - return (dx < s && dx >= 0 && (dy === 1 || dy === -s)) || (dy > -s && dy <= 0 && (dx === -1 || dx === s)); - } - if (isNPC) { - const tx = Math.max(x1, Math.min(x1 + s - 1, x2)); - const ty = Math.max(y1 - s + 1, Math.min(y1, y2)); - return LineOfSight.hasLineOfSight(region, x2, y2, tx, ty, 1, r, false); - } - const dxAbs = Math.abs(dx); - const dyAbs = Math.abs(dy); - if (dxAbs > r || dyAbs > r) { - return false; - } - if (dxAbs > dyAbs) { - let xTile = x1; - let y = (y1 << 16) + 0x8000; - const slope = Math.trunc((dy << 16) / dxAbs); // Integer division - - let xInc: number; - let xMask: number; - let yMask: number; - - if (dx > 0) { - xInc = 1; - xMask = LineOfSightMask.WEST_MASK | LineOfSightMask.FULL_MASK; - } else { - xInc = -1; - xMask = LineOfSightMask.EAST_MASK | LineOfSightMask.FULL_MASK; - } - if (dy < 0) { - y -= 1; // For correct rounding - yMask = LineOfSightMask.NORTH_MASK | LineOfSightMask.FULL_MASK; - } else { - yMask = LineOfSightMask.SOUTH_MASK | LineOfSightMask.FULL_MASK; - } - - while (xTile !== x2) { - xTile += xInc; - const yTile = y >>> 16; - if ((Collision.collidesWithAnyLoSBlockingEntities(region, xTile, yTile, 1) & xMask) !== 0) { - return false; - } - y += slope; - const newYTile = y >>> 16; - if ( - newYTile !== yTile && - (Collision.collidesWithAnyLoSBlockingEntities(region, xTile, newYTile, 1) & yMask) !== 0 - ) { - return false; - } - } - } else { - let yTile = y1; - let x = (x1 << 16) + 0x8000; - const slope = Math.trunc((dx << 16) / dyAbs); // Integer division - - let yInc; - let yMask; - if (dy > 0) { - yInc = 1; - yMask = LineOfSightMask.SOUTH_MASK | LineOfSightMask.FULL_MASK; - } else { - yInc = -1; - yMask = LineOfSightMask.NORTH_MASK | LineOfSightMask.FULL_MASK; - } - - let xMask; - if (dx < 0) { - x -= 1; // For correct rounding - xMask = LineOfSightMask.EAST_MASK | LineOfSightMask.FULL_MASK; - } else { - xMask = LineOfSightMask.WEST_MASK | LineOfSightMask.FULL_MASK; - } - while (yTile !== y2) { - yTile += yInc; - const xTile = x >>> 16; - if ((Collision.collidesWithAnyLoSBlockingEntities(region, xTile, yTile, 1) & yMask) !== 0) { - return false; - } - x += slope; - const newXTile = x >>> 16; - if ( - newXTile !== xTile && - (Collision.collidesWithAnyLoSBlockingEntities(region, newXTile, yTile, 1) & xMask) !== 0 - ) { - return false; - } - } - } - return true; - } -} diff --git a/src/sdk/Location.ts b/src/sdk/Location.ts deleted file mode 100644 index 8aa4d3c7..00000000 --- a/src/sdk/Location.ts +++ /dev/null @@ -1,11 +0,0 @@ -export interface Location { - x: number; - y: number; -} - -// Note: this coordinate system differs from THREE.js - x,y is same as the 2d x,y, and z is the plane. -export interface Location3 { - x: number; - y: number; - z: number; -} diff --git a/src/sdk/MapController.ts b/src/sdk/MapController.ts deleted file mode 100644 index 36e43b22..00000000 --- a/src/sdk/MapController.ts +++ /dev/null @@ -1,519 +0,0 @@ -import MapBoarder from "../assets/images/interface/map_border.png"; -import MapSelectedNumberOrb from "../assets/images/interface/map_selected_num_orb.png"; -import MapNumberOrb from "../assets/images/interface/map_num_orb.png"; -import MapBorderMask from "../assets/images/interface/map_border_mask.png"; -import CompassIcon from "../assets/images/interface/compass.png"; -import MapHitpointOrb from "../assets/images/interface/map_hitpoint_orb.png"; -import MapPrayerOrb from "../assets/images/interface/map_prayer_orb.png"; -import MapPrayerSelectedOrb from "../assets/images/interface/map_prayer_on_orb.png"; - -import MapRunOrb from "../assets/images/interface/map_run_orb.png"; -import MapNoSpecOrb from "../assets/images/interface/map_no_spec_orb.png"; -import MapSpecOrb from "../assets/images/interface/map_spec_orb.png"; -import MapSpecOnOrb from "../assets/images/interface/map_spec_on_orb.png"; - -import MapXpButton from "../assets/images/interface/map_xp_button.png"; -import MapXpHoverButton from "../assets/images/interface/map_xp_hover_button.png"; - -import MapHitpointIcon from "../assets/images/interface/map_hitpoint_icon.png"; -import MapPrayerIcon from "../assets/images/interface/map_prayer_icon.png"; -import MapWalkIcon from "../assets/images/interface/map_walk_icon.png"; -import MapRunIcon from "../assets/images/interface/map_run_icon.png"; -import MapStamIcon from "../assets/images/interface/map_stam_icon.png"; -import MapSpecIcon from "../assets/images/interface/map_spec_icon.png"; - -import ColorScale from "color-scales"; -import { PlayerStats } from "./PlayerStats"; -import { ImageLoader } from "./utils/ImageLoader"; -import { Settings } from "./Settings"; -import { ControlPanelController } from "./ControlPanelController"; -import { MenuOption } from "./ContextMenu"; -import { Chrome } from "./Chrome"; -import { Viewport } from "./Viewport"; - -/* eslint-disable @typescript-eslint/no-explicit-any */ - -enum MapHover { - NONE = 0, - HITPOINT = 1, - PRAYER = 2, - RUN = 3, - SPEC = 4, - XP = 5, -} - -const INITIAL_WIDTH = 210; -const INITIAL_HEIGHT = 180; - -export class MapController { - static controller = new MapController(); - - colorScale: ColorScale = new ColorScale(0, 1, ["#FF0000", "#FF7300", "#00FF00"], 1); - - outlineImage: HTMLImageElement = ImageLoader.createImage(MapBoarder); - mapAlphaImage: HTMLImageElement = ImageLoader.createImage(MapBorderMask); - mapNumberOrb = ImageLoader.createImage(MapNumberOrb); - mapSelectedNumberOrb = ImageLoader.createImage(MapSelectedNumberOrb); - mapHitpointOrb = ImageLoader.createImage(MapHitpointOrb); - mapPrayerOrb = ImageLoader.createImage(MapPrayerOrb); - mapPrayerSelectedOrb = ImageLoader.createImage(MapPrayerSelectedOrb); - mapRunOrb = ImageLoader.createImage(MapRunOrb); - mapNoSpecOrb = ImageLoader.createImage(MapNoSpecOrb); - mapSpecOrb = ImageLoader.createImage(MapSpecOrb); - mapSpecOnOrb = ImageLoader.createImage(MapSpecOnOrb); - mapHitpointIcon = ImageLoader.createImage(MapHitpointIcon); - mapPrayerIcon = ImageLoader.createImage(MapPrayerIcon); - mapWalkIcon = ImageLoader.createImage(MapWalkIcon); - mapRunIcon = ImageLoader.createImage(MapRunIcon); - mapStamIcon = ImageLoader.createImage(MapStamIcon); - mapSpecIcon = ImageLoader.createImage(MapSpecIcon); - mapXpButton = ImageLoader.createImage(MapXpButton); - mapXpHoverButton = ImageLoader.createImage(MapXpHoverButton); - - mapCanvas: OffscreenCanvas; - - compassImage: OffscreenCanvas; - mapHitpointOrbMasked: OffscreenCanvas; - mapPrayerOrbMasked: OffscreenCanvas; - mapRunOrbMasked: OffscreenCanvas; - mapSpecOrbMasked: OffscreenCanvas; - - currentStats: PlayerStats; - stats: PlayerStats; - - hovering: MapHover = null; - - width: number; - height: number; - constructor() { - this.width = INITIAL_WIDTH; - this.height = INITIAL_HEIGHT; - - this.hovering = MapHover.NONE; - this.loadImages(); - } - - updateOrbsMask(currentStats: PlayerStats, stats: PlayerStats) { - if (currentStats) { - this.currentStats = currentStats; - } - if (stats) { - this.stats = stats; - } - - if (!this.mapHitpointOrb || !this.mapPrayerOrb || !this.mapRunOrb || !this.mapSpecOrb) { - return; - } - const hitpointPercentage = this.currentStats.hitpoint / this.stats.hitpoint; - - this.mapHitpointOrbMasked = new OffscreenCanvas(this.mapHitpointOrb.width, this.mapHitpointOrb.height); - let ctx = this.mapHitpointOrbMasked.getContext("2d"); - - ctx.fillStyle = "white"; - ctx.drawImage(this.mapHitpointOrb, 0, 0); - ctx.globalCompositeOperation = "destination-in"; - ctx.fillRect( - 0, - this.mapHitpointOrb.height * (1 - hitpointPercentage), - this.mapHitpointOrb.width, - this.mapHitpointOrb.height * hitpointPercentage, - ); - ctx.globalCompositeOperation = "source-over"; - - const prayerPercentage = this.currentStats.prayer / this.stats.prayer; - this.mapPrayerOrbMasked = new OffscreenCanvas(this.mapPrayerOrb.width, this.mapPrayerOrb.height); - ctx = this.mapPrayerOrbMasked.getContext("2d"); - ctx.fillStyle = "white"; - ctx.drawImage( - ControlPanelController.controls.PRAYER.hasQuickPrayersActivated ? this.mapPrayerSelectedOrb : this.mapPrayerOrb, - 0, - 0, - ); - ctx.globalCompositeOperation = "destination-in"; - ctx.fillRect( - 0, - this.mapPrayerOrb.height * (1 - prayerPercentage), - this.mapPrayerOrb.width, - this.mapPrayerOrb.height * prayerPercentage, - ); - ctx.globalCompositeOperation = "source-over"; - - const runPercentage = this.currentStats.run / 10000; - this.mapRunOrbMasked = new OffscreenCanvas(this.mapRunOrb.width, this.mapRunOrb.height); - ctx = this.mapRunOrbMasked.getContext("2d"); - ctx.fillStyle = "white"; - ctx.drawImage(Viewport.viewport.player.running ? this.mapRunOrb : this.mapNoSpecOrb, 0, 0); - ctx.globalCompositeOperation = "destination-in"; - ctx.fillRect( - 0, - this.mapRunOrb.height * (1 - runPercentage), - this.mapRunOrb.width, - this.mapRunOrb.height * runPercentage, - ); - ctx.globalCompositeOperation = "source-over"; - - const specPercentage = this.currentStats.specialAttack / 100; - this.mapSpecOrbMasked = new OffscreenCanvas(this.mapSpecOrb.width, this.mapSpecOrb.height); - ctx = this.mapSpecOrbMasked.getContext("2d"); - ctx.fillStyle = "white"; - let specOrb = this.mapNoSpecOrb; - if (Viewport.viewport.player.equipment.weapon && Viewport.viewport.player.equipment.weapon.hasSpecialAttack()) { - if (Viewport.viewport.player.useSpecialAttack) { - specOrb = this.mapSpecOnOrb; - } else { - specOrb = this.mapSpecOrb; - } - } - ctx.drawImage(specOrb, 0, 0); - ctx.globalCompositeOperation = "destination-in"; - ctx.fillRect( - 0, - this.mapSpecOrb.height * (1 - specPercentage), - this.mapRunOrb.width, - this.mapRunOrb.height * specPercentage, - ); - ctx.globalCompositeOperation = "source-over"; - } - - loadImages() { - const compassImage = ImageLoader.createImage(CompassIcon); - - compassImage.addEventListener("load", () => { - this.compassImage = new OffscreenCanvas(51, 51); - - const context = this.compassImage.getContext("2d"); - - context.drawImage(compassImage, 0, 0); - - // only draw image where mask is - context.globalCompositeOperation = "destination-in"; - - // draw our circle mask - context.fillStyle = "#000"; - context.beginPath(); - const size = 38; - context.arc( - (51 - size) * 0.5 + size * 0.5, // x - (51 - size) * 0.5 + size * 0.5, // y - size * 0.5, // radius - 0, // start angle - 2 * Math.PI, // end angle - ); - context.fill(); - - // restore to default composite operation (is draw over current image) - context.globalCompositeOperation = "source-over"; - }); - } - - generateMaskedMap() { - this.mapCanvas = new OffscreenCanvas(152, 152); - const mapContext = this.mapCanvas.getContext("2d"); - - mapContext.save(); - mapContext.translate(76, 76); - mapContext.rotate(Viewport.viewport.getMapRotation()); - mapContext.translate(-76, -76); - - if (Viewport.viewport.player.region.mapImage) { - const compatCtx = mapContext as any; - compatCtx.webkitImageSmoothingEnabled = false; - compatCtx.mozImageSmoothingEnabled = false; - compatCtx.imageSmoothingEnabled = false; - mapContext.drawImage(Viewport.viewport.player.region.mapImage, 0, 0, 152, 152); - compatCtx.webkitImageSmoothingEnabled = true; - compatCtx.mozImageSmoothingEnabled = true; - compatCtx.imageSmoothingEnabled = true; - } - - mapContext.globalCompositeOperation = "destination-out"; - mapContext.drawImage(this.mapAlphaImage, 0, 0); - mapContext.globalCompositeOperation = "source-over"; - mapContext.restore(); - } - - cursorMovedTo(event: MouseEvent) { - const { width } = Chrome.size(); - const scale = Settings.minimapScale; - const offset = width - this.width - (Settings.menuVisible ? 232 : 0); - const x = (event.offsetX - offset) / scale; - const y = event.offsetY / scale; - - this.hovering = MapHover.NONE; - if (x > 4 && x < 28 && y > 31 && y < 56) { - this.hovering = MapHover.XP; - } else if (x > 4 && x < 53 && y > 53 && y < 81) { - this.hovering = MapHover.HITPOINT; - } else if (x > 4 && x < 53 && y > 90 && y < 113) { - this.hovering = MapHover.PRAYER; - } else if (x > 15 && x < 67 && y > 122 && y < 149) { - this.hovering = MapHover.RUN; - } else if (x > 38 && x < 90 && y > 148 && y < 173) { - this.hovering = MapHover.SPEC; - } - } - - rightClick(event: MouseEvent): boolean { - let menuOptions: MenuOption[] = []; - - let intercepted = false; - - const { width } = Chrome.size(); - const scale = Settings.minimapScale; - const offset = width - this.width - (Settings.menuVisible ? 232 : 0); - const x = (event.offsetX - offset) / scale; - const y = event.offsetY / scale; - - if (x > 4 && x < 20 && y > 31 && y < 48) { - intercepted = true; - if (Settings.displayXpDrops === true) { - menuOptions = [ - { - text: [ - { text: "Hide ", fillStyle: "white" }, - { text: "XP drops", fillStyle: "#FF911F" }, - ], - action: () => { - Settings.displayXpDrops = false; - }, - }, - ]; - } else { - menuOptions = [ - { - text: [ - { text: "Show ", fillStyle: "white" }, - { text: "XP drops", fillStyle: "#FF911F" }, - ], - action: () => { - Settings.displayXpDrops = true; - }, - }, - ]; - } - } else if (x > 33 && x < 64 && y > 5 && y < 36) { - intercepted = true; - menuOptions = [ - { - text: [{ text: "Look North", fillStyle: "white" }], - action: () => { - Viewport.viewport.rotateNorth(); - }, - }, - { - text: [{ text: "Look South", fillStyle: "white" }], - action: () => { - Viewport.viewport.rotateSouth(); - }, - }, - ]; - } else if (x > 4 && x < 52 && y > 53 && y < 73) { - // intercepted = true; - // hitpoint - } else if (x > 4 && x < 53 && y > 90 && y < 113) { - intercepted = true; - // prayer - menuOptions = [ - { - text: [{ text: "Activate Quick-prayers", fillStyle: "white" }], - action: () => { - this.toggleQuickprayers(); - }, - }, - ]; - } else if (x > 15 && x < 67 && y > 122 && y < 149) { - intercepted = true; - // run - menuOptions = [ - { - text: [{ text: "Toggle Run", fillStyle: "white" }], - action: () => { - Viewport.viewport.player.running = !Viewport.viewport.player.running; - }, - }, - ]; - } else if (x > 38 && x < 90 && y > 148 && y < 175) { - if (this.canSpecialAttack()) { - intercepted = true; - // special attack - menuOptions = [ - { - text: [ - { text: "Use ", fillStyle: "white" }, - { text: "Special Attack", fillStyle: "#FF911F" }, - ], - action: () => { - this.toggleSpecialAttack(); - }, - }, - ]; - } - } - - Viewport.viewport.contextMenu.setMenuOptions(menuOptions); - Viewport.viewport.contextMenu.setActive(); - - return intercepted; - } - - leftClickDown(event: MouseEvent): boolean { - let intercepted = false; - const { width } = Chrome.size(); - const scale = Settings.minimapScale; - const offset = width - this.width - (Settings.menuVisible ? 232 : 0); - const x = (event.offsetX - offset) / scale; - const y = event.offsetY / scale; - - if (x > 4 && x < 20 && y > 31 && y < 48) { - Settings.displayXpDrops = !Settings.displayXpDrops; - intercepted = true; - Settings.persistToStorage(); - } else if (x > 33 && x < 64 && y > 5 && y < 36) { - intercepted = true; - if (Viewport.viewport.getMapRotation() === 0) { - Viewport.viewport.rotateSouth(); - } else { - Viewport.viewport.rotateNorth(); - } - Settings.persistToStorage(); - } else if (x > 4 && x < 52 && y > 53 && y < 73) { - intercepted = true; - // this.hovering = MapHover.HITPOINT; - } else if (x > 4 && x < 53 && y > 90 && y < 113) { - intercepted = true; - this.toggleQuickprayers(); - } else if (x > 15 && x < 67 && y > 122 && y < 149) { - intercepted = true; - Viewport.viewport.player.running = !Viewport.viewport.player.running; - } else if (x > 38 && x < 90 && y > 148 && y < 175) { - intercepted = true; - this.toggleSpecialAttack(); - } - this.updateOrbsMask(this.currentStats, this.stats); - return intercepted; - } - - canSpecialAttack() { - return Viewport.viewport.player.equipment.weapon && Viewport.viewport.player.equipment.weapon.hasSpecialAttack(); - } - - toggleSpecialAttack() { - if (this.canSpecialAttack()) { - Viewport.viewport.player.useSpecialAttack = !Viewport.viewport.player.useSpecialAttack; - } - } - - toggleQuickprayers() { - if (ControlPanelController.controls.PRAYER.hasQuickPrayersActivated) { - ControlPanelController.controls.PRAYER.deactivateAllPrayers(); - Viewport.viewport.player.prayerController.drainCounter = 0; - } else { - ControlPanelController.controls.PRAYER.activateQuickPrayers(); - } - } - - draw(ctx: CanvasRenderingContext2D) { - const { width } = Chrome.size(); - - const gameHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight; - Settings.minimapScale = (gameHeight / 500 > 1 ? 1 : gameHeight / 500) * Settings.maxUiScale; - - const scale = Settings.minimapScale; - this.width = INITIAL_WIDTH * scale; - this.height = INITIAL_HEIGHT * scale; - const offset = width - this.width - (Settings.menuVisible ? 232 : 0); - - ctx.font = 16 * scale + "px Stats_11"; - ctx.textAlign = "center"; - - this.generateMaskedMap(); - ctx.drawImage(this.mapCanvas, offset + 52 * scale, 8, 152 * scale, 152 * scale); - - // draw compass - ctx.save(); - ctx.translate(offset + 50.5 * scale, 23.5 * scale); - ctx.rotate(Viewport.viewport.getMapRotation()); - ctx.translate(-50.5 * scale, -23.5 * scale); - if (this.compassImage) { - ctx.drawImage(this.compassImage, 25 * scale, -2, 51 * scale, 51 * scale); - } - ctx.restore(); - - ctx.drawImage(this.outlineImage, offset + 28 * scale, 0, 182 * scale, 166 * scale); - ctx.drawImage( - this.hovering == MapHover.XP ? this.mapXpHoverButton : this.mapXpButton, - offset, - 26, - 27 * scale, - 27 * scale, - ); - - ctx.drawImage( - this.hovering == MapHover.HITPOINT ? this.mapSelectedNumberOrb : this.mapNumberOrb, - offset, - 47 * scale, - 57 * scale, - 34 * scale, - ); - ctx.drawImage( - this.hovering == MapHover.PRAYER ? this.mapSelectedNumberOrb : this.mapNumberOrb, - offset, - 81 * scale, - 57 * scale, - 34 * scale, - ); - ctx.drawImage( - this.hovering == MapHover.RUN ? this.mapSelectedNumberOrb : this.mapNumberOrb, - offset + 10 * scale, - 114 * scale, - 57 * scale, - 34 * scale, - ); - ctx.drawImage( - this.hovering == MapHover.SPEC ? this.mapSelectedNumberOrb : this.mapNumberOrb, - offset + 32 * scale, - 140 * scale, - 57 * scale, - 34 * scale, - ); - - ctx.drawImage(this.mapHitpointOrbMasked, offset + 27 * scale, 51 * scale, 26 * scale, 26 * scale); - ctx.drawImage(this.mapHitpointIcon, offset + 27 * scale, 51 * scale, 26 * scale, 26 * scale); - ctx.drawImage(this.mapPrayerOrbMasked, offset + 27 * scale, 85 * scale, 26 * scale, 26 * scale); - ctx.drawImage(this.mapPrayerIcon, offset + 27 * scale, 85 * scale, 26 * scale, 26 * scale); - ctx.drawImage(this.mapRunOrbMasked, offset + 37 * scale, 118 * scale, 26 * scale, 26 * scale); - - let mapRunIcon = this.mapWalkIcon; - if (Viewport.viewport.player.effects.stamina) { - mapRunIcon = this.mapStamIcon; - } else if (Viewport.viewport.player.running) { - mapRunIcon = this.mapRunIcon; - } - ctx.drawImage(mapRunIcon, offset + 37 * scale, 118 * scale, 26 * scale, 26 * scale); - ctx.drawImage(this.mapSpecOrbMasked, offset + 59 * scale, 144 * scale, 26 * scale, 26 * scale); - ctx.drawImage(this.mapSpecIcon, offset + 57 * scale, 142 * scale, 30 * scale, 30 * scale); - - // // hitpoints - ctx.fillStyle = "black"; - ctx.fillText(String(this.currentStats.hitpoint), offset + 15 * scale, 74 * scale); - ctx.fillStyle = this.colorScale.getColor(this.currentStats.hitpoint / this.stats.hitpoint).toHexString(); - ctx.fillText(String(this.currentStats.hitpoint), offset + 14 * scale, 73 * scale); - // prayer - ctx.fillStyle = "black"; - ctx.fillText(String(this.currentStats.prayer), offset + 15 * scale, 108 * scale); - ctx.fillStyle = this.colorScale.getColor(this.currentStats.prayer / this.stats.prayer).toHexString(); - ctx.fillText(String(this.currentStats.prayer), offset + 14 * scale, 107 * scale); - - // run - ctx.fillStyle = "black"; - ctx.fillText(String(Math.floor(this.currentStats.run / 100)), offset + 25 * scale, 140 * scale); - ctx.fillStyle = this.colorScale.getColor(this.currentStats.run / 10000).toHexString(); - ctx.fillText(String(Math.floor(this.currentStats.run / 100)), offset + 24 * scale, 139 * scale); - - // spec - ctx.fillStyle = "black"; - ctx.fillText(String(this.currentStats.specialAttack), offset + 47 * scale, 166 * scale); - ctx.fillStyle = this.colorScale.getColor(this.currentStats.specialAttack / 100).toHexString(); - ctx.fillText(String(this.currentStats.specialAttack), offset + 46 * scale, 165 * scale); - } -} diff --git a/src/sdk/Mob.ts b/src/sdk/Mob.ts deleted file mode 100644 index 3399247f..00000000 --- a/src/sdk/Mob.ts +++ /dev/null @@ -1,549 +0,0 @@ -"use strict"; -import { every } from "lodash"; - -import { Settings } from "./Settings"; -import { LineOfSight } from "./LineOfSight"; -import { Pathing } from "./Pathing"; - -import { Weapon } from "./gear/Weapon"; -import { Unit, UnitBonuses, UnitOptions, UnitStats, UnitTypes } from "./Unit"; -import { Location } from "./Location"; -import { Collision } from "./Collision"; -import { Viewport } from "./Viewport"; -import { Random } from "./Random"; -import { Region } from "./Region"; -import { CanvasSpriteModel } from "./rendering/CanvasSpriteModel"; -import { Model } from "./rendering/Model"; -import { InputController } from "./Input"; -import { parseText } from "./utils/Text"; - -export enum AttackIndicators { - NONE = 0, - HIT = 1, - BLOCKED = 2, - SCAN = 3, -} - -export interface WeaponsMap { - [key: string]: Weapon; -} - -export class Mob extends Unit { - static mobIdTracker = 0; - mobId: number = Mob.mobIdTracker++; - hasResurrected = false; - attackFeedback: AttackIndicators; - stats: UnitStats; - currentStats: UnitStats; - hadLOS: boolean; - hasLOS: boolean; - weapons: WeaponsMap; - attackStyle: string; - tcc: Location[]; - removableWithRightClick = false; - - constructor(region: Region, location: Location, options?: UnitOptions) { - super(region, location, options); - } - - override get type() { - return UnitTypes.MOB; - } - - canBeAttacked() { - return true; - } - - override setStats() { - // non boosted numbers - this.stats = { - attack: 99, - strength: 99, - defence: 99, - range: 99, - magic: 99, - hitpoint: 99, - }; - - // with boosts - this.currentStats = { - attack: 99, - strength: 99, - defence: 99, - range: 99, - magic: 99, - hitpoint: 99, - }; - } - - override get bonuses(): UnitBonuses { - return { - attack: { - stab: 0, - slash: 0, - crush: 0, - magic: 0, - range: 0, - }, - defence: { - stab: 0, - slash: 0, - crush: 0, - magic: 0, - range: 0, - }, - other: { - meleeStrength: 0, - rangedStrength: 0, - magicDamage: 0, - prayer: 0, - }, - }; - } - - /** - * - * @returns the next location to move to - */ - getNextMovementStep(): { dx: number; dy: number } { - let dx = this.location.x + Math.sign(this.aggro.location.x - this.location.x); - let dy = this.location.y + Math.sign(this.aggro.location.y - this.location.y); - - if ( - Collision.collisionMath( - this.location.x, - this.location.y, - this.size, - this.aggro.location.x, - this.aggro.location.y, - 1, - ) - ) { - // Random movement if player is under the mob. - if (Random.get() < 0.5) { - dy = this.location.y; - if (Random.get() < 0.5) { - dx = this.location.x + 1; - } else { - dx = this.location.x - 1; - } - } else { - dx = this.location.x; - if (Random.get() < 0.5) { - dy = this.location.y + 1; - } else { - dy = this.location.y - 1; - } - } - } else if (Collision.collisionMath(dx, dy, this.size, this.aggro.location.x, this.aggro.location.y, 1)) { - // allows corner safespotting - dy = this.location.y; - } - - if (this.attackDelay > this.attackSpeed) { - // No movement right after melee dig. 8 ticks after the dig it should be able to move again. - dx = this.location.x; - dy = this.location.y; - } - return { dx, dy }; - } - - override movementStep() { - if (this.dying === 0) { - return; - } - this.processIncomingAttacks(); - - this.age--; - if (this.age > 0) { - return; - } - this.perceivedLocation = { x: this.location.x, y: this.location.y }; - - this.setHasLOS(); - if (this.canMove() && this.aggro) { - const { dx, dy } = this.getNextMovementStep(); - - const xOff = dx - this.location.x; - const yOff = this.location.y - dy; - - let xTiles = this.getXMovementTiles(xOff, yOff); - let yTiles = this.getYMovementTiles(xOff, yOff); - let xSpace = every( - xTiles.map((location: Location) => - Pathing.canTileBePathedTo(this.region, location.x, location.y, 1, this.consumesSpace as Mob), - ), - Boolean, - ); - let ySpace = every( - yTiles.map((location: Location) => - Pathing.canTileBePathedTo(this.region, location.x, location.y, 1, this.consumesSpace as Mob), - ), - Boolean, - ); - const both = xSpace && ySpace; - - // if (this.mobName() === EntityName.JAL_AK){ - // this.tcc = xTiles; //xTiles.concat(yTiles); - // } - - if (!both) { - xTiles = this.getXMovementTiles(xOff, 0); - xSpace = every( - xTiles.map((location: Location) => - Pathing.canTileBePathedTo(this.region, location.x, location.y, 1, this.consumesSpace as Mob), - ), - Boolean, - ); - if (!xSpace) { - yTiles = this.getYMovementTiles(0, yOff); - ySpace = every( - yTiles.map((location: Location) => - Pathing.canTileBePathedTo(this.region, location.x, location.y, 1, this.consumesSpace as Mob), - ), - Boolean, - ); - } - } - - if (both) { - this.location.x = dx; - this.location.y = dy; - } else if (xSpace) { - this.location.x = dx; - } else if (ySpace) { - this.location.y = dy; - } - } - } - - getXMovementTiles(xOff: number, yOff: number) { - const start = yOff === -1 ? -1 : 0; - const end = yOff === 1 ? this.size + 1 : this.size; - const xTiles = []; - if (xOff === -1) { - for (let i = start; i < end; i++) { - xTiles.push({ - x: this.location.x - 1, - y: this.location.y - i, - }); - } - } else if (xOff === 1) { - for (let i = start; i < end; i++) { - xTiles.push({ - x: this.location.x + this.size, - y: this.location.y - i, - }); - } - } - return xTiles; - } - - getYMovementTiles(xOff: number, yOff: number) { - const start = xOff === -1 ? -1 : 0; - const end = xOff === 1 ? this.size + 1 : this.size; - - const yTiles = []; - if (yOff === -1) { - // south - for (let i = start; i < end; i++) { - yTiles.push({ - x: this.location.x + i, - y: this.location.y + 1, - }); - } - } else if (yOff === 1) { - // north - for (let i = start; i < end; i++) { - yTiles.push({ - x: this.location.x + i, - y: this.location.y - this.size, - }); - } - } - - return yTiles; - } - // todo: Rename this possibly? it returns the attack style if it's possible - canMeleeIfClose(): "slash" | "crush" | "stab" | "" { - return ""; - } - - override attackStep() { - super.attackStep(); - - if (this.age > 0) { - return; - } - if (this.dying === 0) { - return; - } - - this.attackIfPossible(); - this.detectDeath(); - - this.frozen--; - this.stunned--; - } - - attackStyleForNewAttack() { - return "slash"; - } - - attackIfPossible() { - this.hadLOS = this.hasLOS; - this.setHasLOS(); - - if (!this.aggro || this.canAttack() === false) { - return; - } - - this.attackStyle = this.attackStyleForNewAttack(); - - const weaponIsAreaAttack = this.weapons[this.attackStyle].isAreaAttack; - let isUnderAggro = false; - if (!weaponIsAreaAttack) { - isUnderAggro = Collision.collisionMath( - this.location.x, - this.location.y, - this.size, - this.aggro.location.x, - this.aggro.location.y, - 1, - ); - } - this.attackFeedback = AttackIndicators.NONE; - - if (!isUnderAggro && this.hasLOS && this.attackDelay <= 0) { - this.attack() && this.didAttack(); - } - } - - magicMaxHit() { - return 0; - } - - attack() { - if (this.aggro.dying >= 0) { - return false; - } - if (this.canMeleeIfClose() && Weapon.isMeleeAttackStyle(this.attackStyle) === false) { - if (this.isWithinMeleeRange() && Random.get() < 0.5) { - this.attackStyle = this.canMeleeIfClose(); - } - } - - if ( - this.weapons[this.attackStyle].isBlockable(this, this.aggro, { - attackStyle: this.attackStyle, - }) - ) { - this.attackFeedback = AttackIndicators.BLOCKED; - } else { - this.attackFeedback = AttackIndicators.HIT; - } - this.weapons[this.attackStyle].attack(this, this.aggro as Unit /* hack */, { - attackStyle: this.attackStyle, - magicBaseSpellDamage: this.magicMaxHit(), - }); - - return true; - } - - visible() { - return this.region.world.getReadyTimer <= 0; - } - - get consumesSpace(): Unit { - return this; - } - - override get combatLevel() { - return 99; - } - - override contextActions(region: Region, x: number, y: number) { - const actions = [ - { - text: [ - { text: "Attack ", fillStyle: "white" }, - { text: this.mobName(), fillStyle: "yellow" }, - { - text: ` (level ${this.combatLevel})`, - fillStyle: Viewport.viewport.player.combatLevelColor(this), - }, - ], - action: () => { - Viewport.viewport.clickController.redClick(); - InputController.controller.queueAction(() => Viewport.viewport.clickController.playerAttackClick(this)); - }, - }, - ]; - - // hack hack hack - - if (this.removableWithRightClick) { - actions.push({ - text: [ - { text: "Remove ", fillStyle: "white" }, - { text: this.mobName(), fillStyle: "yellow" }, - { - text: ` (level ${this.combatLevel})`, - fillStyle: Viewport.viewport.player.combatLevelColor(this), - }, - ], - action: () => { - this.region.removeMob(this); - }, - }); - } - - return actions; - } - - drawOverTile(tickPercent: number, context: OffscreenCanvasRenderingContext2D, scale) { - // Override me - } - - drawUnderTile(tickPercent: number, context: OffscreenCanvasRenderingContext2D, scale) { - context.fillStyle = "#00000000"; - if (Settings.displayFeedback) { - if (this.dying > -1) { - context.fillStyle = "#964B0073"; - } else if (this.attackFeedback === AttackIndicators.BLOCKED) { - context.fillStyle = "#00FF0073"; - } else if (this.attackFeedback === AttackIndicators.HIT) { - context.fillStyle = "#FF000073"; - } else if (this.attackFeedback === AttackIndicators.SCAN) { - context.fillStyle = "#FFFF0073"; - } else if (this.hasLOS) { - context.fillStyle = "#FF730073"; - } else { - context.fillStyle = this.color; - } - } - // Draw mob - context.fillRect(-(this.size * scale) / 2, -(this.size * scale) / 2, this.size * scale, this.size * scale); - } - - override draw( - tickPercent: number, - context: OffscreenCanvasRenderingContext2D, - offset: Location, - scale: number, - drawUnderTile: boolean, - ) { - super.draw(tickPercent, context, offset, scale, drawUnderTile); - if (Settings.displayMobLoS) { - LineOfSight.drawLOS( - this.region, - this.location.x, - this.location.y, - this.size, - this.attackRange, - "#FF000055", - this.type === UnitTypes.MOB, - ); - } - - const perceivedX = offset.x; - const perceivedY = offset.y; - context.save(); - context.translate( - perceivedX * scale + (this.size * scale) / 2, - (perceivedY - this.size + 1) * scale + (this.size * scale) / 2, - ); - - if (drawUnderTile) { - this.drawUnderTile(tickPercent, context, scale); - } - const currentImage = this.unitImage; - - if (Settings.rotated === "south") { - context.rotate(Math.PI); - } - if (Settings.rotated === "south") { - context.scale(-1, 1); - } - - context.save(); - if (this.shouldShowAttackAnimation()) { - this.attackAnimation(tickPercent, context); - } - - if (currentImage) { - context.drawImage( - currentImage, - -(this.size * scale) / 2, - -(this.size * scale) / 2, - this.size * scale, - this.size * scale, - ); - } - - context.restore(); - - if (Settings.rotated === "south") { - context.scale(-1, 1); - } - - this.drawOverTile(tickPercent, context, scale); - - if (this.aggro) { - const unit = this.aggro as Unit; - - if ( - LineOfSight.playerHasLineOfSightOfMob( - this.region, - this.aggro.location.x, - this.aggro.location.y, - this, - unit.attackRange, - ) - ) { - context.strokeStyle = "#00FF0073"; - context.lineWidth = 1; - context.strokeRect(-(this.size * scale) / 2, -(this.size * scale) / 2, this.size * scale, this.size * scale); - } - } - - context.restore(); - - if (!this.tcc) { - return; - } - // if (this.mobName() !== EntityName.JAL_AK) { - // return; - // } - // if (this.mobId !== 4) { - // return; - // } - /*this.tcc.forEach((location: Location) => { - context.fillStyle = "#00FF0073"; - context.fillRect(location.x * scale, location.y * scale, scale, scale); - });*/ - } - - override drawUILayer(tickPercent, offset, context, scale, hitsplatsAbove) { - context.save(); - context.translate(offset.x, offset.y); - if (Settings.rotated === "south") { - context.rotate(Math.PI); - } - - this.drawHPBar(context, scale); - this.drawOverheadText(context, scale); - this.drawHitsplats(context, scale, hitsplatsAbove); - this.drawOverheadPrayers(context, scale); - - context.restore(); - } - - override create3dModel(): Model { - return CanvasSpriteModel.forRenderable(this); - } - - override get color() { - return "#FF0000"; - } -} diff --git a/src/sdk/Pathing.ts b/src/sdk/Pathing.ts deleted file mode 100644 index 778c915e..00000000 --- a/src/sdk/Pathing.ts +++ /dev/null @@ -1,320 +0,0 @@ -"use strict"; -import { sortBy, minBy, max } from "lodash"; -import { Location } from "./Location"; -import { Collision } from "./Collision"; -import { Region } from "./Region"; -import { Unit } from "./Unit"; - -interface PathingCache { - [key: string]: boolean; -} - -interface PathingNode { - x: number; - y: number; - parent?: PathingNode; - pathLength?: number; -} -export class Pathing { - static entitiesAtPoint(region: Region, x: number, y: number, s: number) { - const entities = []; - for (let i = 0; i < region.entities.length; i++) { - if ( - Collision.collisionMath( - x, - y, - s, - region.entities[i].location.x, - region.entities[i].location.y, - region.entities[i].size, - ) - ) { - entities.push(region.entities[i]); - } - } - return entities; - } - - // TODO: Make this more like entitiesAtPoint - static mobsAtAoeOffset(region: Region, mob: Unit, point: Location) { - const mobs = []; - for (let i = 0; i < region.mobs.length; i++) { - const collidedWithSpecificMob = - region.mobs[i].location.x === point.x + mob.location.x && - region.mobs[i].location.y === point.y + mob.location.y; - - if (collidedWithSpecificMob) { - mobs.push(region.mobs[i]); - } - } - - return sortBy(mobs, (m: Unit) => mob !== m); - } - - // Core pathing - - static linearInterpolation(x: number, y: number, a: number) { - return (y - x) * a + x; - } - - static dist(x: number, y: number, x2: number, y2: number) { - return Math.sqrt(Math.pow(x2 - x, 2) + Math.pow(y2 - y, 2)); - } - - static angle(x: number, y: number, x2: number, y2: number) { - return Math.atan2(y2 - y, x2 - x); - } - - static closestPointTo(x: number, y: number, mob: Unit) { - const corners = []; - for (let xx = 0; xx < mob.size; xx++) { - for (let yy = 0; yy < mob.size; yy++) { - corners.push({ - x: mob.location.x + xx, - y: mob.location.y - yy, - }); - } - } - - return minBy(corners, (point: Location) => Pathing.dist(x, y, point.x, point.y)); - } - - static tileCache: PathingCache = {}; - static purgeTileCache() { - Pathing.tileCache = {}; - } - - static canTileBePathedTo(region: Region, x: number, y: number, s: number, mobToAvoid: Unit = null) { - const cache = - Pathing.tileCache[`${region.serialNumber}-${x}-${y}-${s}-${mobToAvoid ? mobToAvoid.serialNumber : 0}`]; - if (cache !== undefined) { - return cache; - } - let collision = false; - collision = collision || Collision.collidesWithAnyEntities(region, x, y, s); - - if (mobToAvoid) { - // if no mobs to avoid, avoid them all - // Player can walk under mobs - collision = collision || Collision.collidesWithAnyMobs(region, x, y, s, mobToAvoid) !== null; - } - Pathing.tileCache[`${region.serialNumber}-${x}-${y}-${s}-${mobToAvoid ? mobToAvoid.serialNumber : 0}`] = !collision; - return !collision; - } - - /** - * - * @param region - * @param startPoint - * @param endPoints array of valid end points. the first should be the SW tile. - * @returns - */ - static constructPaths( - region: Region, - { x, y }: Location, - endPoints: Location[], - ): { - destination: Location | null; - path: Location[]; - } { - const unpathableEndPoints = endPoints.filter( - (location) => !Pathing.canTileBePathedTo(region, location.x, location.y, 1), - ); - if (unpathableEndPoints.length === endPoints.length) { - // no pathable end points - return { - destination: null, - path: [], - }; - } - - const pathableEndPoints = endPoints.filter((location) => - Pathing.canTileBePathedTo(region, location.x, location.y, 1), - ); - - let pathX = x; - let pathY = y; - - const nodes: PathingNode[] = [{ x, y, parent: null }]; - - // The order of possible directions in this array determines if the player moves first straight or diagonaly - // https://oldschool.runescape.wiki/w/Pathfinding#Determining_the_target_tile - const directions = [ - { x: -1, y: 0 }, // west - { x: 1, y: 0 }, // east - { x: 0, y: 1 }, // south - { x: 0, y: -1 }, // north - { x: -1, y: 1 }, // sw - { x: 1, y: 1 }, // se - { x: -1, y: -1 }, // nw - { x: 1, y: -1 }, // ne - ]; - - let currentDistance = 0; - - // Djikstra search for the optimal route - const explored: { [x: number]: { [y: number]: PathingNode } } = {}; - - // initialise first node - explored[pathX] = {}; - explored[pathX][pathY] = { x: pathX, y: pathY, parent: null, pathLength: 0 }; - let minExploredX = pathX; - let minExploredY = pathY; - let maxExploredX = pathX; - let maxExploredY = pathY; - - while (nodes.length !== 0 && nodes.length < 1000) { - const parentNode = nodes.shift(); - const matchedDestinations = pathableEndPoints.filter((d) => d.x === parentNode.x && d.y === parentNode.y); - for (const matchedDestination of matchedDestinations) { - const path = []; - let parent = parentNode; - while (parent) { - path.push({ x: parent.x, y: parent.y }); - parent = parent.parent; - } - return { destination: matchedDestination, path }; - } - currentDistance = (explored[parentNode.x] || {})[parentNode.y]?.pathLength || 0; - for (let i = 0; i < directions.length; i++) { - const iDirection = directions[i]; - pathX = parentNode.x + iDirection.x; - pathY = parentNode.y + iDirection.y; - - if (!Pathing.canTileBePathedTo(region, pathX, pathY, 1, null)) { - // Destination is not a valid square - continue; - } - if (i >= 4) { - // Check neighbouring squares for diagonal moves - let neighbourX = parentNode.x; - let neighbourY = parentNode.y + iDirection.y; - if (!Pathing.canTileBePathedTo(region, neighbourX, neighbourY, 1, null)) { - continue; - } - neighbourX = parentNode.x + iDirection.x; - neighbourY = parentNode.y; - if (!Pathing.canTileBePathedTo(region, neighbourX, neighbourY, 1, null)) { - continue; - } - } - - if (!(pathX in explored)) { - explored[pathX] = {}; - if (pathX < minExploredX) { - minExploredX = pathX; - } - if (pathX > maxExploredX) { - maxExploredX = pathX; - } - } - if (pathY in explored[pathX]) { - continue; - } else { - explored[pathX][pathY] = { - x: pathX, - y: pathY, - parent: parentNode, - pathLength: currentDistance + 1, - }; - if (pathY < minExploredY) { - minExploredY = pathY; - } - if (pathY > maxExploredY) { - maxExploredY = pathY; - } - } - nodes.push({ x: pathX, y: pathY, parent: parentNode }); - } - } - - // No path found yet. - // Find a backup tile within a 21x21 grid of the SW tile of the selection that: - // - has path length less than 100 - // - has the shortest path distance - // - has target tile as close as possible in Euclidean distance to the nearest requested tile - const swTile = endPoints[0]; - const minX = Math.max(minExploredX, swTile.x - 10); - const minY = Math.max(minExploredY, swTile.y - 10); - const maxX = Math.max(maxExploredX, swTile.x + 10); - const maxY = Math.max(maxExploredY, swTile.y + 10); - - let bestBackupTile: Location | null = null; - //let minEuclideanDistance = Pathing.dist(swTile.x, swTile.y, startPoint.x, startPoint.y); - let minEuclideanDistance = Number.MAX_VALUE; // Pathing.dist(swTile.x, swTile.y, startPoint.x, startPoint.y); - let minPathLength = 100; - - for (let x = minX; x <= maxX; ++x) { - if (!(x in explored)) { - continue; - } - for (let y = minY; y <= maxY; ++y) { - if (!(y in explored[x])) { - continue; - } - const pathLength = explored[x][y].pathLength; - - endPoints.forEach((endPoint) => { - const dist = Pathing.dist(x, y, endPoint.x, endPoint.y); - if (dist < minEuclideanDistance || (dist === minEuclideanDistance && pathLength < minPathLength)) { - bestBackupTile = { x, y }; - minPathLength = pathLength; - minEuclideanDistance = dist; - } - }); - } - } - // No LoS - path to best backup tile - if (bestBackupTile) { - // unwind the path - const path = []; - let node = explored[bestBackupTile.x][bestBackupTile.y]; - while (node) { - path.push({ x: node.x, y: node.y }); - node = node.parent; - } - return { - destination: bestBackupTile, - path, - }; - } - // no backup tile found - return { - destination: null, - path: [], - }; - } - - static path(region: Region, startPoint: Location, endPoint: Location, speed: number, seeking: Unit) { - let x: number, y: number; - const pathResult = Pathing.constructPaths(region, startPoint, [endPoint]); - const { path } = pathResult; - if (path.length === 0) { - return { x: startPoint.x, y: startPoint.y, path: [] }; - } - if (seeking && Collision.collidesWithMob(region, path[0].x, path[0].y, 1, seeking)) { - path.shift(); - } - - if (path.length === 0) { - return { - x: startPoint.x, - y: startPoint.y, - path: [], - }; - } - - if (path.length <= speed) { - // Step to the destination - x = path[0].x; - y = path[0].y; - } else { - // Move two steps forward - x = path[path.length - speed - 1].x; - y = path[path.length - speed - 1].y; - } - const destination = path[0]; - path.reverse(); - return { x, y, path: path.slice(1, 3), destination }; - } -} diff --git a/src/sdk/Player.ts b/src/sdk/Player.ts deleted file mode 100644 index d4b528c3..00000000 --- a/src/sdk/Player.ts +++ /dev/null @@ -1,998 +0,0 @@ -"use strict"; -import _ from "lodash"; - -import { Pathing } from "./Pathing"; -import { Settings } from "./Settings"; -import { LineOfSight } from "./LineOfSight"; -import { minBy, range, filter, find, map, min, uniq, sumBy, flatMap } from "lodash"; -import { Unit, UnitTypes, UnitBonuses, UnitOptions } from "./Unit"; -import { XpDropController } from "./XpDropController"; -import { AttackBonuses, Weapon } from "./gear/Weapon"; -import { BasePrayer } from "./BasePrayer"; -import { XpDrop, XpDropAggregator } from "./XpDrop"; -import { Location } from "./Location"; -import { Mob } from "./Mob"; -import { Equipment } from "./Equipment"; -import { SetEffect } from "./SetEffect"; -import chebyshev from "chebyshev"; -import { ItemName } from "./ItemName"; -import { Item } from "./Item"; -import { Collision } from "./Collision"; -import { Eating } from "./Eating"; -import { PlayerStats } from "./PlayerStats"; -import { PlayerRegenTimer } from "./PlayerRegenTimers"; -import { PrayerController } from "./PrayerController"; -import { AmmoType } from "./gear/Ammo"; -import { Region } from "./Region"; -import { Viewport } from "./Viewport"; -import { Sound, SoundCache } from "./utils/SoundCache"; - -import LeatherHit from "../assets/sounds/hit.ogg"; -import HumanHit from "../assets/sounds/human_hit_513.ogg"; -import { Model } from "./rendering/Model"; -import { TileMarker } from "../content/TileMarker"; - -import { GLTFModel } from "./rendering/GLTFModel"; -import { PlayerAnimationIndices } from "./rendering/GLTFAnimationConstants"; - -/* eslint-disable @typescript-eslint/no-explicit-any */ - -class PlayerEffects { - poisoned = 0; - venomed = 0; - stamina = 0; -} - -// player can rotate this many JAUs per client tick -const PLAYER_ROTATION_RATE_JAU = 64; -const CLIENT_TICKS_PER_SECOND = 50; -const JAU_PER_RADIAN = 512; -const RADIANS_PER_TICK = ((CLIENT_TICKS_PER_SECOND * PLAYER_ROTATION_RATE_JAU) / JAU_PER_RADIAN) * 0.6; - -const ENABLE_POSITION_DEBUG = false; - -// position that is "close enough" -const EPSILON = 0.1; - -export class Player extends Unit { - manualSpellCastSelection: Weapon; - - // this is the actual location that we want to move to (ignoring pathing) - destinationLocation?: Location; - // this is the location we are actually pathing towards - pathTargetLocation?: Location; - - stats: PlayerStats; - currentStats: PlayerStats; - xpDrops: XpDropAggregator; - overhead: BasePrayer; - running = true; - cachedBonuses: UnitBonuses = null; - useSpecialAttack = false; - effects = new PlayerEffects(); - regenTimer: PlayerRegenTimer = new PlayerRegenTimer(this); - - autocastDelay = 1; - manualCastHasTarget = false; - - eats: Eating = new Eating(); - inventory: Item[]; - - seekingItem: Item = null; - - path: (Location & { run: boolean })[] = []; - - clickMarker: ClickMarker | null = null; - aggroMarker: ClickMarker | null = null; - - pathMarkers: ClickMarker[] = []; - currentPoseAnimation = PlayerAnimationIndices.Idle; - - constructor(region: Region, location: Location, options: UnitOptions = {}) { - super(region, location, options); - - this.destinationLocation = location; - this.pathTargetLocation = location; - this.equipmentChanged(); - this.clearXpDrops(); - this.autoRetaliate = false; - this.eats.player = this; - - this.setUnitOptions(options); - - this.prayerController = new PrayerController(this); - } - - contextActions(region: Region, x: number, y: number) { - return super.contextActions(region, x, y).concat([ - { - text: [ - { text: "Attack ", fillStyle: "white" }, - { text: `Player`, fillStyle: "yellow" }, - { - text: ` (level ${this.combatLevel})`, - fillStyle: Viewport.viewport.player.combatLevelColor(this), - }, - ], - action: () => { - Viewport.viewport.clickController.redClick(); - Viewport.viewport.player.setAggro(this); - }, - }, - ]); - } - - setUnitOptions(options: UnitOptions) { - this.equipment = options.equipment || {}; - this.inventory = options.inventory || new Array(28).fill(null); - this.equipmentChanged(); - } - - interruptCombat() { - this.setAggro(null); - } - - get color() { - return "#00FF00"; - } - - get height() { - return 1; - } - - get isPlayer(): boolean { - return true; - } - - get attackRange() { - if (this.manualSpellCastSelection) { - return this.manualSpellCastSelection.attackRange; - } - if (this.equipment.weapon) { - return this.equipment.weapon.attackRange; - } - return 1; - } - - get attackSpeed() { - if (this.manualSpellCastSelection) { - return this.manualSpellCastSelection.attackSpeed; - } - if (this.equipment.weapon) { - return this.equipment.weapon.attackSpeed; - } - return 5; - } - - openInventorySlots(): number[] { - const openSpots = []; - for (let i = 0; i < 28; i++) { - if (!this.inventory[i]) { - openSpots.push(i); - } - } - return openSpots; - } - - postAttacksEvent() { - this.eats.checkRedemption(this); - } - - swapItemPositions(pos1: number, pos2: number) { - // positions can be negative if an item is destroyed due to consuming it on the same tick - const temp = this.inventory[pos1] ?? null; - this.inventory[pos1] = this.inventory[pos2] ?? null; - this.inventory[pos2] = temp; - } - - equipmentChanged() { - this.interruptCombat(); - - const gear = [ - this.equipment.weapon, - this.equipment.offhand, - this.equipment.helmet, - this.equipment.necklace, - this.equipment.chest, - this.equipment.legs, - this.equipment.feet, - this.equipment.gloves, - this.equipment.ring, - this.equipment.cape, - ]; - - if ( - this.equipment.weapon && - this.equipment.ammo && - this.equipment.weapon.compatibleAmmo().includes(this.equipment.ammo.itemName) - ) { - gear.push(this.equipment.ammo); - } else if (this.equipment.ammo && this.equipment.ammo.ammoType() == AmmoType.BLESSING) { - gear.push(this.equipment.ammo); - } - - // updated gear bonuses - this.cachedBonuses = Unit.emptyBonuses(); - gear.forEach((g: Equipment) => { - if (g && g.bonuses) { - g.updateBonuses(gear); - this.cachedBonuses = Unit.mergeEquipmentBonuses(this.cachedBonuses, g.bonuses); - } - }); - - // update set effects - const allSetEffects = []; - gear.forEach((equipment: Equipment) => { - if (equipment && equipment.equipmentSetEffect) { - allSetEffects.push(equipment.equipmentSetEffect); - } - }); - const completeSetEffects = []; - uniq(allSetEffects).forEach((setEffect: typeof SetEffect) => { - const itemsInSet = setEffect.itemsInSet(); - let setItemsEquipped = 0; - find(itemsInSet, (itemName: string) => { - gear.forEach((equipment: Equipment) => { - if (!equipment) { - return; - } - if (itemName === equipment.itemName) { - setItemsEquipped++; - } - }); - }); - if (itemsInSet.length === setItemsEquipped) { - completeSetEffects.push(setEffect); - } - }); - this.setEffects = completeSetEffects; - - if (this.path.length === 0) { - this.currentPoseAnimation = this.getIdlePoseId(); - } - this.invalidateModel(); - } - - get bonuses(): UnitBonuses { - return this.cachedBonuses; - } - - setStats() { - // non boosted numbers - this.stats = Settings.player_stats; - - // with boosts - this.currentStats = JSON.parse(JSON.stringify(Settings.player_stats)); - } - - get weight(): number { - let gear: Item[] = [ - this.equipment.weapon, - this.equipment.offhand, - this.equipment.helmet, - this.equipment.necklace, - this.equipment.chest, - this.equipment.legs, - this.equipment.feet, - this.equipment.gloves, - this.equipment.ring, - this.equipment.cape, - this.equipment.ammo, - ]; - gear = gear.concat(this.inventory); - gear = filter(gear); - - const kgs = Math.max(Math.min(64, sumBy(gear, "weight")), 0); - return kgs; - } - - get prayerDrainResistance(): number { - // https://oldschool.runescape.wiki/w/Prayer#Prayer_drain_mechanics - return 2 * this.bonuses.other.prayer + 60; - } - - get type() { - return UnitTypes.PLAYER; - } - - clearXpDrops() { - this.xpDrops = {}; - } - - grantXp(xpDrop: XpDrop) { - if (!this.xpDrops[xpDrop.skill]) { - this.xpDrops[xpDrop.skill] = 0; - } - this.xpDrops[xpDrop.skill] += xpDrop.xp; - } - - sendXpToController() { - if (!XpDropController.controller) { - return; - } - if (this !== Viewport.viewport.player) { - return; - } - - Object.keys(this.xpDrops).forEach((skill) => { - XpDropController.controller.registerXpDrop({ - skill, - xp: Math.ceil(this.xpDrops[skill]), - }); - }); - - this.clearXpDrops(); - } - - moveTo(x: number, y: number) { - this.interruptCombat(); - - this.manualSpellCastSelection = null; - - this.pathTargetLocation = null; - - const clickedOnEntities = Collision.collideableEntitiesAtPoint(this.region, x, y, 1); - if (clickedOnEntities.length) { - // Clicked on an entity, scan around to find the best spot to actually path to - const clickedOnEntity = clickedOnEntities[0]; - const maxDist = Math.ceil(clickedOnEntity.size / 2); - let bestDistances = []; - let bestDistance = 9999; - for (let yOff = -maxDist; yOff < maxDist; yOff++) { - for (let xOff = -maxDist; xOff < maxDist; xOff++) { - const potentialX = x + xOff; - const potentialY = y + yOff; - const e = Collision.collideableEntitiesAtPoint(this.region, potentialX, potentialY, 1); - if (e.length === 0) { - const distance = Pathing.dist(potentialX, potentialY, x, y); - if (distance <= bestDistance) { - if (bestDistances[0] && bestDistances[0].bestDistance > distance) { - bestDistance = distance; - bestDistances = []; - } - bestDistances.push({ - x: potentialX, - y: potentialY, - bestDistance, - }); - } - } - } - } - const winner = minBy(bestDistances, (distance) => - Pathing.dist(distance.x, distance.y, this.location.x, this.location.y), - ); - if (winner) { - this.destinationLocation = { x: winner.x, y: winner.y }; - } - } else { - this.destinationLocation = { x, y }; - } - } - - attack(): boolean { - if (this.manualSpellCastSelection) { - const target = this.aggro; - this.manualSpellCastSelection.cast(this, target); - this.manualSpellCastSelection = null; - this.interruptCombat(); - this.destinationLocation = this.location; - } else { - // use equipped weapon - if (this.equipment.weapon) { - if (this.equipment.weapon.hasSpecialAttack() && this.useSpecialAttack) { - if (this.currentStats.specialAttack >= this.equipment.weapon.specialAttackDrain()) { - this.equipment.weapon.specialAttack(this, this.aggro as Unit /* hack */); - this.currentStats.specialAttack -= this.equipment.weapon.specialAttackDrain(); - this.regenTimer.specUsed(); - } - this.useSpecialAttack = false; - } else { - const bonuses: AttackBonuses = {}; - if (this.equipment.helmet && this.equipment.helmet.itemName === ItemName.SLAYER_HELMET_I) { - bonuses.gearMeleeMultiplier = 7 / 6; - bonuses.gearRangeMultiplier = 1.15; - bonuses.gearMageMultiplier = 1.15; - } - - return this.equipment.weapon.attack(this, this.aggro /* hack */, bonuses); - } - } else { - return false; - } - } - - return true; - } - - activatePrayers() { - this.lastOverhead = this.overhead; - this.overhead = this.prayerController.overhead(); - if (this.lastOverhead && !this.overhead) { - this.lastOverhead.playOffSound(); - } else if (this.lastOverhead !== this.overhead) { - this.overhead.playOnSound(); - } - } - - setAggro(mob: Unit) { - if (mob !== this.aggro) { - // do spam clicks constantly reset autocast delay? idk - this.autocastDelay = 1; // not sure if this is actually correct behavior but whatever - } - - if (this.manualSpellCastSelection && mob != null) { - this.manualCastHasTarget = true; - } else { - this.manualCastHasTarget = false; - } - - this.aggro = mob; - this.seekingItem = null; - } - - setSeekingItem(item: Item) { - this.interruptCombat(); - this.seekingItem = item; - } - determineDestination() { - if (this.aggro) { - if (this.aggro.dying > -1) { - this.destinationLocation = this.location; - return; - } - const isUnderAggrodMob = Collision.collisionMath( - this.location.x, - this.location.y, - 1, - this.aggro.location.x, - this.aggro.location.y, - this.aggro.size, - ); - this.setHasLOS(); - - if (isUnderAggrodMob) { - const maxDist = Math.ceil(this.aggro.size / 2); - let bestDistance = 9999; - let winner = null; - for (let yy = -maxDist; yy < maxDist; yy++) { - for (let xx = -maxDist; xx < maxDist; xx++) { - const x = this.location.x + xx; - const y = this.location.y + yy; - if (Pathing.canTileBePathedTo(this.region, x, y, 1, {} as Mob)) { - const distance = Pathing.dist(this.location.x, this.location.y, x, y); - if (distance > 0 && distance < bestDistance) { - bestDistance = distance; - winner = { x, y }; - } - } - } - } - if (winner) { - this.destinationLocation = { x: winner.x, y: winner.y }; - } else { - console.log("I don't understand what could cause this, but i'd like to find out"); - } - } else if (!this.hasLOS) { - const seekingTiles: Location[] = []; - // "When clicking on an npc, object, or player, the requested tiles will be all tiles" - // "within melee range of the npc, object, or player." - // For implementation reasons we also ensure the north/south tiles are added to seekingTiles *first* so that - // in cases of ties, the north and south tiles are picked by minBy below. - const aggroSize = this.aggro.size; - range(0, aggroSize).forEach((xx) => { - [-1, this.aggro.size].forEach((yy) => { - // Don't path into an unpathable object. - const px = this.aggro.location.x + xx; - const py = this.aggro.location.y - yy; - if (!Collision.collidesWithAnyEntities(this.region, px, py, 1)) { - seekingTiles.push({ - x: px, - y: py, - }); - } - }); - }); - range(0, aggroSize).forEach((yy) => { - [-1, this.aggro.size].forEach((xx) => { - // Don't path into an unpathable object. - const px = this.aggro.location.x + xx; - const py = this.aggro.location.y - yy; - if (!Collision.collidesWithAnyEntities(this.region, px, py, 1)) { - seekingTiles.push({ - x: px, - y: py, - }); - } - }); - }); - // Create paths to all npc tiles - const path = Pathing.constructPaths(this.region, this.location, seekingTiles); - this.destinationLocation = path.destination ?? this.location; - } else { - // stop moving - this.destinationLocation = this.location; - } - } else if (this.seekingItem) { - this.destinationLocation = this.seekingItem.groundLocation; - } - } - private getIdlePoseId() { - return this.equipment.weapon ? this.equipment.weapon.idleAnimationId : PlayerAnimationIndices.Idle; - } - - // WARNING: client ticks do NOT happen in line with render or logic ticks. Do not use this for anything other than - // visual logic. - clientTick(tickPercent) { - // based on https://github.com/dennisdev/rs-map-viewer/blob/master/src/mapviewer/webgl/npc/Npc.ts#L115 - if (this.path.length === 0) { - return; - } - let { x, y } = this.perceivedLocation; - const { x: nextX, y: nextY, run } = this.path[0]; - - const currentAngle = this.getPerceivedRotation(tickPercent); - - // 30 client ticks per tick and we want to walk 1 tile per tick so - const baseMovementSpeed = 1 / 30; - let movementSpeed = baseMovementSpeed; - - this.currentPoseAnimation = PlayerAnimationIndices.Walk; - - const canRotate = true; - if (currentAngle !== this.nextAngle && canRotate) { - if (ENABLE_POSITION_DEBUG) console.log("must rotate", this.path.length, run); - movementSpeed = baseMovementSpeed / 2; - this.currentPoseAnimation = PlayerAnimationIndices.Rotate180; - } - if (this.path.length === 3) { - if (ENABLE_POSITION_DEBUG) console.log("path length medium", this.path.length, run); - movementSpeed = baseMovementSpeed * 1.5; - } - if (this.path.length > 3) { - if (ENABLE_POSITION_DEBUG) console.log("path length warp", this.path.length, run); - movementSpeed = baseMovementSpeed * 2; - } - if (this.path.length < 3) { - if (ENABLE_POSITION_DEBUG) console.log("normal speed", this.path.length, run); - } - if (run) { - movementSpeed *= 2; - this.currentPoseAnimation = PlayerAnimationIndices.Run; - } - let diffX = Math.abs(x - nextX); - let diffY = Math.abs(y - nextY); - if (diffX > EPSILON || diffY > EPSILON) { - if (x < nextX) { - x = Math.min(x + movementSpeed, nextX); - } else if (x > nextX) { - x = Math.max(x - movementSpeed, nextX); - } - if (y < nextY) { - y = Math.min(y + movementSpeed, nextY); - } else if (y > nextY) { - y = Math.max(y - movementSpeed, nextY); - } - } - this.perceivedLocation = { x, y }; - diffX = Math.abs(x - nextX); - diffY = Math.abs(y - nextY); - if (diffX < EPSILON && diffY < EPSILON) { - this.perceivedLocation.x = nextX; - this.perceivedLocation.y = nextY; - this.path.shift(); - if (ENABLE_POSITION_DEBUG) { - const headTile = this.pathMarkers.shift(); - this.region.removeEntity(headTile); - } - if (this.path.length === 0) { - this.currentPoseAnimation = this.getIdlePoseId(); - this.restingAngle = this.nextAngle; - } else { - this.nextAngle = this.getTargetAngle(); - } - } - } - - moveTowardsDestination() { - this.nextAngle = this.getTargetAngle(); - // Calculate run energy - const dist = this.pathTargetLocation - ? chebyshev([this.location.x, this.location.y], [this.pathTargetLocation.x, this.pathTargetLocation.y]) - : 0; - if (this.running && dist > 1) { - const runReduction = 67 + Math.floor(67 + Math.min(Math.max(0, this.weight), 64) / 64); - if (this.effects.stamina) { - this.currentStats.run -= Math.floor(0.3 * runReduction); - } else if (this.equipment.ring && this.equipment.ring.itemName === ItemName.RING_OF_ENDURANCE) { - this.currentStats.run -= Math.floor(0.85 * runReduction); - } else { - this.currentStats.run -= runReduction; - } - } else { - this.currentStats.run += Math.floor(this.currentStats.agility / 6) + 8; - } - this.currentStats.run = Math.min(Math.max(this.currentStats.run, 0), 10000); - if (this.currentStats.run === 0) { - this.running = false; - } - // Tick down stamina - this.effects.stamina--; - this.effects.stamina = Math.min(Math.max(this.effects.stamina, 0), 200); - - // Path to next position if not already there. - if ( - !this.destinationLocation || - (this.location.x === this.destinationLocation.x && this.location.y === this.destinationLocation.y) - ) { - this.pathTargetLocation = null; - return; - } - - const speed = this.running ? 2 : 1; - - const { path, destination } = Pathing.path(this.region, this.location, this.destinationLocation, speed, this.aggro); - this.pathTargetLocation = destination; - if (!path.length || !destination) { - return; - } - const originalLocation = this.location; - if (path.length < speed) { - // Step to the destination - this.location = path[path.length - 1]; - } else { - // Move one or two steps forward - this.location = path[speed - 1]; - } - // postprocess the path to corners only - // save the next 2 steps for interpolation purposes - let newTiles = path.map((pos, idx) => ({ - ...pos, - run: this.running && path.length >= 2, - direction: Pathing.angle( - idx === 0 ? originalLocation.x : path[idx - 1].x, - idx === 0 ? originalLocation.y : path[idx - 1].y, - pos.x, - pos.y, - ), - })); - // only add corners to the path (and the last point) - newTiles = newTiles.filter((v, idx) => idx === path.length - 1 || v.direction !== newTiles[idx + 1].direction); - if (newTiles.length > 1 && newTiles[1].direction === newTiles[0].direction) { - newTiles.shift(); - } - if (ENABLE_POSITION_DEBUG) { - newTiles.forEach((tile) => { - const marker = new ClickMarker(this.region, tile, "#FF0000"); - this.pathMarkers.push(marker); - this.region.addEntity(marker); - }); - } - this.path.push(...newTiles); - this.nextAngle = this.getTargetAngle(); - } - - takeSeekingItem() { - if (this.seekingItem) { - if (this.seekingItem.groundLocation.x === this.location.x) { - if (this.seekingItem.groundLocation.y === this.location.y) { - // Verify player is close. Apparently we need to have the player keep track of this item - this.region.removeGroundItem(this.seekingItem, this.location.x, this.location.y); - const slots = this.openInventorySlots(); - if (slots.length) { - const slot = slots[0]; - this.inventory[slot] = this.seekingItem; - } - this.seekingItem = null; - } - } - } - } - - dead() { - super.dead(); - this.perceivedLocation = this.location; - this.destinationLocation = this.location; - } - - // Rotation Code - private restingAngle = 0; - private nextAngle = 0; - - private _angle = 0; - - private lastTickPercent = 0; - - getPerceivedRotation(tickPercent) { - // https://gist.github.com/shaunlebron/8832585 - function shortAngleDist(a0, a1) { - const da = (a1 - a0) % (Math.PI * 2); - return ((2 * da) % (Math.PI * 2)) - da; - } - // - const turnAmount = RADIANS_PER_TICK * Math.max(0, tickPercent - this.lastTickPercent); - this.lastTickPercent = tickPercent; - const diff = (this.nextAngle - this._angle + Math.PI * 2) % (Math.PI * 2); - const direction = diff - Math.PI > 0 ? -1 : 1; - if (diff >= turnAmount) { - this._angle += turnAmount * direction; - } else { - this._angle = this.nextAngle; - } - return this._angle; - } - - getTargetAngle() { - if (this.aggro) { - const angle = Pathing.angle( - this.perceivedLocation.x + this.size / 2, - this.perceivedLocation.y - this.size / 2, - this.aggro.location.x + this.aggro.size / 2, - this.aggro.location.y - this.aggro.size / 2, - ); - return -angle; - } - if (this.path.length > 0) { - const angle = Pathing.angle(this.perceivedLocation.x, this.perceivedLocation.y, this.path[0].x, this.path[0].y); - return -angle; - } - return this.restingAngle; - } - - movementStep() { - if (this.dying > -1) { - return; - } - - this.activatePrayers(); - - this.takeSeekingItem(); - - if (!this.isFrozen()) { - this.determineDestination(); - this.moveTowardsDestination(); - } - - this.updatePathMarker(); - this.frozen--; - } - - removeClickMarker() { - if (!this.clickMarker) { - return; - } - this.clickMarker.remove(); - this.region.removeEntity(this.clickMarker); - this.clickMarker = null; - } - - updatePathMarker() { - if (!this.pathTargetLocation) { - this.removeClickMarker(); - return; - } - if ( - this.clickMarker && - this.location.x === this.pathTargetLocation.x && - this.location.y === this.pathTargetLocation.x - ) { - this.removeClickMarker(); - } else if (!this.clickMarker) { - this.clickMarker = new ClickMarker(this.region, this.pathTargetLocation); - this.region.addEntity(this.clickMarker); - } else { - this.clickMarker.location = this.pathTargetLocation; - } - } - - hitSound(damaged: boolean): Sound | null { - return damaged ? new Sound(HumanHit, 0.1) : new Sound(LeatherHit, 0.15); - } - - damageTaken() { - if ( - this.prayerController.isPrayerActiveByName("Redemption") && - this.currentStats.hitpoint > 0 && - this.currentStats.hitpoint < Math.floor(this.stats.hitpoint / 10) - ) { - this.eats.redemptioned = true; - } - } - - pretick() { - this.prayerController.tick(this); - } - - override attackStep() { - super.attackStep(); - this.detectDeath(); - - this.processIncomingAttacks(); - - if (this.dying > -1) { - return; - } - - this.clearXpDrops(); - - // clear aggro if target is nulled (e.g. healers on zuk after tag) - if (this.aggro && this.aggro.isNulled) { - this.aggro = null; - } - - this.attackIfPossible(); - - this.eats.tickFood(this); - - this.regenTimer.regen(); - - this.sendXpToController(); - } - - attackIfPossible() { - if (this.canAttack() === false) { - return; - } - - if (this.aggro) { - this.setHasLOS(); - if (this.hasLOS && this.attackDelay <= 0 && this.aggro.isDying() === false) { - this.attack() && this.didAttack(); - } else if ( - this.manualSpellCastSelection && - this.manualCastHasTarget && - this.hasLOS && - this.attackDelay <= 0 && - this.aggro.dying == this.aggro.deathAnimationLength - ) { - // Phantom/ghost barrage - this.attack() && this.didAttack(); - } - - // After allowing ghost barrage, unset aggro if enemy is dead - if (this.aggro && this.aggro.isDying()) { - this.interruptCombat(); - } - } - } - - draw(tickPercent: number) { - // this.region.context.fillStyle = '#FFFF00' - // this.region.context.fillRect( - // 26 * Settings.tileSize, - // 24 * Settings.tileSize, - // 6 * Settings.tileSize, - // 12 * Settings.tileSize - // // 26 - 32 x - // // 24 - 36 y - - // ) - if (Settings.displayPlayerLoS) { - LineOfSight.drawLOS( - this.region, - this.location.x, - this.location.y, - this.size, - this.attackRange, - "#00FF0055", - this.type === UnitTypes.MOB, - ); - } - - this.region.context.save(); - const perceivedLocation = this.getPerceivedLocation(tickPercent); - const perceivedX = perceivedLocation.x; - const perceivedY = perceivedLocation.y; - - // Perceived location - - if (this.dying === -1) { - this.region.context.globalAlpha = 0.7; - this.region.context.fillStyle = "#FFFF00"; - this.region.context.fillRect( - perceivedX * Settings.tileSize, - perceivedY * Settings.tileSize, - Settings.tileSize, - Settings.tileSize, - ); - this.region.context.globalAlpha = 1; - } - - // Draw player on true tile - this.region.context.fillStyle = "#ffffff73"; - // feedback for when you shoot - if (this.shouldShowAttackAnimation()) { - this.region.context.fillStyle = "#00FFFF"; - } - if (this.dying > -1) { - this.region.context.fillStyle = "#000"; - } - this.region.context.strokeStyle = "#FFFFFF73"; - this.region.context.lineWidth = 3; - this.region.context.fillRect( - this.location.x * Settings.tileSize, - this.location.y * Settings.tileSize, - Settings.tileSize, - Settings.tileSize, - ); - - // Destination location - this.region.context.strokeStyle = "#FFFFFF73"; - this.region.context.lineWidth = 3; - this.region.context.strokeRect( - this.destinationLocation.x * Settings.tileSize, - this.destinationLocation.y * Settings.tileSize, - Settings.tileSize, - Settings.tileSize, - ); - this.region.context.restore(); - return { x: perceivedX, y: perceivedY }; - } - - getPerceivedLocation(tickPercent: number) { - return { ...this.perceivedLocation, z: 0 }; - } - - drawUILayer( - tickPercent: number, - offset: Location, - context: OffscreenCanvasRenderingContext2D, - scale: number, - hitsplatsAbove: boolean, - ) { - if (this.dying > -1) { - return; - } - context.save(); - - context.translate(offset.x, offset.y); - - if (Settings.rotated === "south") { - this.region.context.rotate(Math.PI); - } - this.drawHPBar(context, scale); - this.drawHitsplats(context, scale, hitsplatsAbove); - this.drawOverheadPrayers(context, scale); - context.restore(); - } - - create3dModel(): Model { - return GLTFModel.forRenderableMulti( - this, - Object.values(this.equipment) - .map((e) => e?.model) - .filter((e) => !!e), - 1 / 128, - ); - } - - override get animationIndex() { - return this.currentPoseAnimation; - } - - override get drawOutline() { - // not needed with a real 3d model - return false; - } - - override get attackAnimationId() { - return this.equipment.weapon?.attackAnimationId; - } - - get canBlendAttackAnimation() { - return true; - } - - override get drawTrueTile() { - return true; - } -} - -class ClickMarker extends TileMarker { - constructor(region: Region, location: Location, color = "#FFFFFF") { - super(region, location, color, 1, false); - } - remove() { - this.dying = 0; - } -} diff --git a/src/sdk/PlayerRegenTimers.ts b/src/sdk/PlayerRegenTimers.ts deleted file mode 100644 index b1045b31..00000000 --- a/src/sdk/PlayerRegenTimers.ts +++ /dev/null @@ -1,44 +0,0 @@ -"use strict"; - -import { Player } from "./Player"; - -export class PlayerRegenTimer { - player: Player; - spec: number; - hitpoint: number; - - constructor(player: Player) { - this.player = player; - this.spec = 50; - this.hitpoint = 100; - } - - specUsed() { - if (this.spec <= 0) { - this.spec = 50; - } - } - - regen() { - this.specRegen(); - this.hitpointRegen(); - } - - specRegen() { - this.spec--; - if (this.spec === 0) { - this.spec = 50; - this.player.currentStats.specialAttack += 10; - this.player.currentStats.specialAttack = Math.min(100, this.player.currentStats.specialAttack); - } - } - - hitpointRegen() { - this.hitpoint--; - if (this.hitpoint === 0) { - this.hitpoint = 100; - this.player.currentStats.hitpoint++; - this.player.currentStats.hitpoint = Math.min(this.player.stats.hitpoint, this.player.currentStats.hitpoint); - } - } -} diff --git a/src/sdk/PlayerStats.ts b/src/sdk/PlayerStats.ts deleted file mode 100644 index 0090773c..00000000 --- a/src/sdk/PlayerStats.ts +++ /dev/null @@ -1,27 +0,0 @@ -"use strict"; -import { UnitStats } from "./Unit"; - -export function SerializePlayerStats(stats: PlayerStats): string { - return JSON.stringify(stats); -} - -export function DeserializePlayerStats(serializedStats: string): PlayerStats { - const stats = JSON.parse(serializedStats) || {}; - stats.attack = stats.attack || 99; - stats.strength = stats.strength || 99; - stats.defence = stats.defence || 99; - stats.range = stats.range || 99; - stats.magic = stats.magic || 99; - stats.hitpoint = stats.hitpoint || 99; - stats.agility = stats.agility || 99; - stats.prayer = stats.prayer || 99; - stats.run = stats.run || 10000; - stats.specialAttack = stats.specialAttack || 100; - return stats; -} - -export interface PlayerStats extends UnitStats { - agility: number; - run: number; - specialAttack: number; -} diff --git a/src/sdk/PrayerController.ts b/src/sdk/PrayerController.ts deleted file mode 100644 index 0c58744f..00000000 --- a/src/sdk/PrayerController.ts +++ /dev/null @@ -1,145 +0,0 @@ -import { filter, find, intersection } from "lodash"; -import { Augury } from "../content/prayers/Augury"; -import { BurstOfStrength } from "../content/prayers/BurstOfStrength"; -import { Chivalry } from "../content/prayers/Chivalry"; -import { ClarityOfThought } from "../content/prayers/ClarityOfThought"; -import { EagleEye } from "../content/prayers/EagleEye"; -import { HawkEye } from "../content/prayers/HawkEye"; -import { ImprovedReflexes } from "../content/prayers/ImprovedReflexes"; -import { IncredibleReflexes } from "../content/prayers/IncredibleReflexes"; -import { MysticLore } from "../content/prayers/MysticLore"; -import { MysticMight } from "../content/prayers/MysticMight"; -import { MysticWill } from "../content/prayers/MysticWill"; -import { Piety } from "../content/prayers/Piety"; -import { Preserve } from "../content/prayers/Preserve"; -import { ProtectItem } from "../content/prayers/ProtectItem"; -import { ProtectMage } from "../content/prayers/ProtectMage"; -import { ProtectMelee } from "../content/prayers/ProtectMelee"; -import { ProtectRange } from "../content/prayers/ProtectRange"; -import { RapidHeal } from "../content/prayers/RapidHeal"; -import { RapidRestore } from "../content/prayers/RapidRestore"; -import { Redemption } from "../content/prayers/Redemption"; -import { Retribution } from "../content/prayers/Retribution"; -import { Rigour } from "../content/prayers/Rigour"; -import { RockSkin } from "../content/prayers/RockSkin"; -import { SharpEye } from "../content/prayers/SharpEye"; -import { Smite } from "../content/prayers/Smite"; -import { SteelSkin } from "../content/prayers/SteelSkin"; -import { SuperhumanStrength } from "../content/prayers/SuperhumanStrength"; -import { ThickSkin } from "../content/prayers/ThickSkin"; -import { UltimateStrength } from "../content/prayers/UltimateStrength"; -import { BasePrayer, PrayerGroups } from "./BasePrayer"; -import { Player } from "./Player"; - -export class PrayerController { - drainCounter = 0; - player: Player; - - constructor(player: Player) { - this.player = player; - } - - tick(player: Player) { - // "transfer" prayers from client to "server" - this.prayers.forEach((prayer) => prayer.tick()); - - // Deactivate any incompatible prayers - const conflictingPrayers = {}; - player.prayerController.prayers.forEach((activePrayer) => { - activePrayer.groups.forEach((group) => { - if (!conflictingPrayers[group]) { - conflictingPrayers[group] = []; - } - conflictingPrayers[group].push(activePrayer); - }); - }); - - for (const prayer in conflictingPrayers) { - conflictingPrayers[prayer].sort((p1: BasePrayer, p2: BasePrayer) => p2.lastActivated - p1.lastActivated); - conflictingPrayers[prayer].shift(); - conflictingPrayers[prayer].forEach((prayer: BasePrayer) => { - prayer.isLit = false; - prayer.isActive = false; - }); - } - - // calc prayer drain - - const prayerDrainThisTick = this.drainRate(); - this.drainCounter += prayerDrainThisTick; - while (this.drainCounter > this.player.prayerDrainResistance) { - this.player.currentStats.prayer--; - this.drainCounter -= this.player.prayerDrainResistance; - } - - // deactivate prayers when out of prayer - - if (this.player.currentStats.prayer <= 0) { - this.activePrayers().forEach((prayer) => prayer.deactivate()); - this.player.currentStats.prayer = 0; - } - } - - drainRate(): number { - return this.activePrayers().reduce((a, b) => a + b.drainRate(), 0); - } - - findPrayerByName(name: string): BasePrayer { - return find(this.prayers, (prayer: BasePrayer) => prayer.name === name); - } - - isPrayerActiveByName(name: string): BasePrayer { - return find(this.activePrayers(), (prayer: BasePrayer) => prayer.name === name); - } - - activePrayers(): BasePrayer[] { - return filter(this.prayers, (prayer: BasePrayer) => prayer.isActive); - } - - matchFeature(feature: string): BasePrayer { - return find(this.activePrayers(), (prayer: BasePrayer) => prayer.feature() === feature); - } - - matchGroup(group: PrayerGroups): BasePrayer { - return find(this.activePrayers(), (prayer: BasePrayer) => prayer.groups.includes(group)); - } - - overhead(): BasePrayer { - return find( - this.activePrayers(), - (prayer: BasePrayer) => intersection(prayer.groups, [PrayerGroups.OVERHEADS]).length, - ) as BasePrayer; - } - - prayers: BasePrayer[] = [ - new ThickSkin(), - new BurstOfStrength(), - new ClarityOfThought(), - new SharpEye(), - new MysticWill(), - new RockSkin(), - new SuperhumanStrength(), - new ImprovedReflexes(), - new RapidRestore(), - new RapidHeal(), - new ProtectItem(), - new HawkEye(), - new MysticLore(), - new SteelSkin(), - new UltimateStrength(), - new IncredibleReflexes(), - new ProtectMage(), - new ProtectRange(), - new ProtectMelee(), - new EagleEye(), - new MysticMight(), - new Retribution(), - new Redemption(), - new Smite(), - new Preserve(), - new Chivalry(), - new Piety(), - new Rigour(), - new Augury(), - ]; -} diff --git a/src/sdk/Random.ts b/src/sdk/Random.ts deleted file mode 100644 index e2da6bd8..00000000 --- a/src/sdk/Random.ts +++ /dev/null @@ -1,18 +0,0 @@ -export class Random { - static memory = 0; - static callCount = 0; - static randomFn = () => Math.random(); - static setRandom(fn: () => number) { - Random.randomFn = fn; - } - - static reset() { - Random.memory = 0; - Random.callCount = 0; - } - - static get() { - this.callCount++; - return Random.randomFn(); - } -} diff --git a/src/sdk/Region.ts b/src/sdk/Region.ts deleted file mode 100644 index c4cecc71..00000000 --- a/src/sdk/Region.ts +++ /dev/null @@ -1,196 +0,0 @@ -"use strict"; - -import { remove } from "lodash"; -import { Entity } from "./Entity"; -import { Item } from "./Item"; -import { Mob } from "./Mob"; -import { Player } from "./Player"; -import { Settings } from "./Settings"; -import { Unit } from "./Unit"; -import { World } from "./World"; -import { Projectile } from "./weapons/Projectile"; - -interface GroundYItems { - [key: number]: Item[]; -} - -export interface GroundItems { - [key: number]: GroundYItems; -} - -export enum CardinalDirection { - NORTH, - SOUTH, -} - -// Base class for any trainer region. -export abstract class Region { - canvas: OffscreenCanvas; - - players: Player[] = []; - - world: World; - - newMobs: Mob[] = []; - mobs: Mob[] = []; - entities: Entity[] = []; - // free-floating projectiles not associated with a mob/player. TODO maybe they all should be here. - projectiles: Projectile[] = []; - - mapImage: HTMLImageElement; - - groundItems: GroundItems = {}; - - _serialNumber: string; - get serialNumber(): string { - if (!this._serialNumber) { - this._serialNumber = String(Math.random()); - } - return this._serialNumber; - } - - get initialFacing(): CardinalDirection { - return CardinalDirection.SOUTH; - } - - midTick() { - // Override me - } - - postTick() { - // Override me - } - - addPlayer(player: Player) { - this.players.push(player); - player.addedToWorld(); - } - - rightClickActions() { - return []; - } - - get context() { - if (!this.canvas) { - if (Settings.mobileCheck()) { - this.canvas = new OffscreenCanvas(2000, 2000); - } else { - this.canvas = new OffscreenCanvas(10000, 10000); - } - } - return this.canvas.getContext("2d"); - } - - addEntity(entity: Entity) { - this.entities.push(entity); - } - - removeEntity(entity: Entity) { - entity.dying = 0; - remove(this.entities, entity); - } - - addMob(mob: Mob) { - if (!mob.region.world) { - this.mobs.push(mob); - mob.addedToWorld(); - } else { - this.newMobs.push(mob); - } - } - - removeMob(mob: Mob) { - remove(this.mobs, mob); - } - removePlayer(player: Player) { - remove(this.players, player); - } - addGroundItem(player: Player, item: Item, x: number, y: number) { - if (!this.groundItems[x]) { - this.groundItems[x] = {}; - } - if (!this.groundItems[x][y]) { - this.groundItems[x][y] = []; - } - - item.groundLocation = { x: player.location.x, y: player.location.y }; - this.groundItems[x][y].push(item); - } - - addProjectile(projectile: Projectile) { - this.projectiles.push(projectile); - } - - removeProjectile(projectile: Projectile) { - remove(this.projectiles, projectile); - } - - getName(): string { - return "My Region"; - } - - get width(): number { - return 0; - } - - get height(): number { - return 0; - } - - mapImagePath(): string { - return ""; - } - - drawWorldBackground(context: OffscreenCanvasRenderingContext2D, scale: number) { - // Override me - } - - drawDefaultFloor() { - return true; - } - - groundItemsAtLocation(x: number, y: number) { - return (this.groundItems[x] ? this.groundItems[x][y] : []) || []; - } - - removeGroundItem(item: Item, x: number, y: number) { - if (this.groundItems[x]) { - if (this.groundItems[x][y]) { - remove(this.groundItems[x][y], item); - } - } - } - - drawGroundItems(ctx: OffscreenCanvasRenderingContext2D) { - Object.entries(this.groundItems).forEach((scope1: [string, string]) => { - const x = parseInt(scope1[0]); - Object.entries(this.groundItems[x]).forEach((scope2: [string, string]) => { - const y = parseInt(scope2[0]); - const items = this.groundItems[x][y]; - items.forEach((item: Item) => { - ctx.drawImage( - item.inventorySprite, - x * Settings.tileSize, - y * Settings.tileSize, - Settings.tileSize, - Settings.tileSize, - ); - }); - }); - }); - } - - abstract initialiseRegion(): { player: Player }; - - getSidebarContent(): string { - return "Nothing to see here"; - } - - // calls preload on all renderable children - async preload() { - await Promise.all(this.entities.map((entity) => entity.preload())); - await Promise.all(this.mobs.map((mob) => mob.preload())); - await Promise.all(this.newMobs.map((mob) => mob.preload())); - await Promise.all(this.players.map((players) => players.preload())); - } -} diff --git a/src/sdk/Renderable.ts b/src/sdk/Renderable.ts deleted file mode 100644 index bb089fbb..00000000 --- a/src/sdk/Renderable.ts +++ /dev/null @@ -1,168 +0,0 @@ -import { create } from "lodash"; -import { Location, Location3 } from "./Location"; - -import { Model } from "./rendering/Model"; - -export interface RenderableListener { - animationChanged(id: number, blend: boolean): Promise; - modelChanged(); -} - -const NIL_OFFSET: Location3[] = [{ x: 0, y: 0, z: 0 }]; - -export abstract class Renderable { - private _selected = false; - private cachedModel: Model | null = null; - private animationChangeListener: RenderableListener | null = null; - - // in case the animation is set before animationChangeListener is set - private queuedAnimationId = -1; - - abstract getPerceivedLocation(tickPercent: number): Location3; - - /** - * return the angle of this renderable in radians, around the Z (up) axis. - * West is zero degrees, and increasing values represent clockwise rotation. - */ - abstract getPerceivedRotation(tickPercent: number): number; - - abstract getTrueLocation(): Location; - - /** - * return the pitch angle of this renderable in radians, i.e. how up/down it is pointing - * 0 is flat, increasing is up, decreasing is down - */ - getPerceivedPitch(tickPercent: number): number { - return 0; - } - - /** - * allow offsetting the components of a multi-model renderable - */ - getPerceivedOffsets(tickPercent: number): Location3[] { - return NIL_OFFSET; - } - - abstract get size(): number; - - get drawOutline(): boolean { - return true; - } - - get drawTrueTile(): boolean { - return false; - } - - get height(): number { - return this.size; - } - - get clickboxHeight(): number | null { - return null; - } - - get clickboxRadius(): number | null { - return null; - } - - abstract get color(): string; - - get colorHex() { - return parseInt(this.color.replace("#", ""), 16); - } - - get selectable(): boolean { - return true; - } - - visible(tickPercent): boolean { - return true; - } - - /** - * Should remove from the scene - */ - abstract shouldDestroy(): boolean; - - get selected(): boolean { - return this._selected; - } - - set selected(selected: boolean) { - this._selected = selected; - } - - drawUILayer( - tickPercent: number, - screenPosition: Location, - context: OffscreenCanvasRenderingContext2D, - scale: number, - hitsplatAbove = true, - ) { - // Override me - } - - // draw in 2d mode - draw( - tickPercent: number, - context: OffscreenCanvasRenderingContext2D, - offset: Location = { x: 0, y: 0 }, - scale = 20, - drawUnderTile = true, - ) { - // Override me - } - - /** - * Return a new model for this renderable in 3d mode. it will be associated with the Renderable and destroyed when the renderable is - * destroyed. - */ - protected create3dModel(): Model | null { - return null; - } - - public get3dModel(): Model | null { - return this.cachedModel ?? this.create3dModel(); - } - - /** - * Return the index of the animation that should be playing at this moment. - * Note: if the value changes, the new animation will start upon the next tick. - */ - abstract get animationIndex(); - - async playAnimation(index: number, blend = false) { - if (this.animationChangeListener) { - return this.animationChangeListener.animationChanged(index, blend); - } else { - this.queuedAnimationId = index; - } - } - - setAnimationListener(listener: RenderableListener) { - this.animationChangeListener = listener; - if (this.queuedAnimationId >= 0) { - listener.animationChanged(this.queuedAnimationId, false); - this.queuedAnimationId = -1; - } - } - - clearAnimationListener() { - this.animationChangeListener = null; - } - - invalidateModel() { - this.cachedModel = null; - if (this.animationChangeListener) { - this.animationChangeListener.modelChanged(); - } - } - - async preload() { - // Create an offscreen version of the model so that loading it is faster next time. - this.cachedModel = this.create3dModel(); - if (this.cachedModel) { - await this.cachedModel.preload(); - } - } -} diff --git a/src/sdk/SetEffect.ts b/src/sdk/SetEffect.ts deleted file mode 100644 index 9ebda6f8..00000000 --- a/src/sdk/SetEffect.ts +++ /dev/null @@ -1,11 +0,0 @@ -export enum SetEffectTypes { - JUSTICIAR = "JUSTICIAR", -} -export class SetEffect { - static effectName(): string { - return ""; - } - static itemsInSet(): string[] { - return []; - } -} diff --git a/src/sdk/Settings.ts b/src/sdk/Settings.ts deleted file mode 100644 index a9ad0a47..00000000 --- a/src/sdk/Settings.ts +++ /dev/null @@ -1,150 +0,0 @@ -"use strict"; - -import { PlayerStats, SerializePlayerStats, DeserializePlayerStats } from "./PlayerStats"; -import { Location } from "./Location"; - -export class Settings { - static zoomScale = 1; - - static _tileSize: number; - static get tileSize() { - return Settings._tileSize * Settings.zoomScale; - } - - static fps = 50; - static tickMs = 600; - static playsAudio: boolean; - static playsAreaAudio: boolean; - static inputDelay: number; - static rotated: string; - static region: string; - static displayXpDrops: boolean; - static lockPOV: boolean; - static displayFeedback: boolean; - static metronome: boolean; - - static inventory_key: string; - static spellbook_key: string; - static equipment_key: string; - static prayer_key: string; - static combat_key: string; - static tile_markers: Location[]; - - static loadout: string; - static onTask: boolean; - static player_stats: PlayerStats; - static is_keybinding = false; - static southPillar = true; - static westPillar = true; - static northPillar = true; - - static displayPlayerLoS = false; - static displayMobLoS = false; - static menuVisible: boolean; - - static minimapScale: number; - static controlPanelScale: number; - - static maxUiScale: number; - - static _isMobileResult = null; - - static use3dView = true; - - static mobileCheck() { - if (Settings._isMobileResult !== null) { - return Settings._isMobileResult; - } - Settings._isMobileResult = /Mobi/.test(navigator.userAgent); - return Settings._isMobileResult; - } - - static persistToStorage() { - // window.localStorage.setItem('tileSize', Settings.tileSize); - // window.localStorage.setItem('framesPerTick', Settings.framesPerTick); - window.localStorage.setItem("zoomScale", String(Settings.zoomScale)); - window.localStorage.setItem("playsAudio", String(Settings.playsAudio)); - window.localStorage.setItem("playsAreaAudio", String(Settings.playsAreaAudio)); - window.localStorage.setItem("inputDelay", String(Settings.inputDelay)); - window.localStorage.setItem("rotated", Settings.rotated); - window.localStorage.setItem("region", Settings.region); - window.localStorage.setItem("displayXpDrops", String(Settings.displayXpDrops)); - - window.localStorage.setItem("inventory_key", Settings.inventory_key); - window.localStorage.setItem("spellbook_key", Settings.spellbook_key); - window.localStorage.setItem("equipment_key", Settings.equipment_key); - window.localStorage.setItem("prayer_key", Settings.prayer_key); - window.localStorage.setItem("combat_key", Settings.combat_key); - window.localStorage.setItem("stats", SerializePlayerStats(Settings.player_stats)); - window.localStorage.setItem("loadout", Settings.loadout); - window.localStorage.setItem("onTask", String(Settings.onTask)); - window.localStorage.setItem("southPillar", String(Settings.southPillar)); - window.localStorage.setItem("westPillar", String(Settings.westPillar)); - window.localStorage.setItem("northPillar", String(Settings.northPillar)); - window.localStorage.setItem("displayPlayerLoS", String(Settings.displayPlayerLoS)); - window.localStorage.setItem("displayMobLoS", String(Settings.displayMobLoS)); - window.localStorage.setItem("metronome", String(Settings.metronome)); - window.localStorage.setItem("displayFeedback", String(Settings.displayFeedback)); - window.localStorage.setItem("tile_markers", JSON.stringify(Settings.tile_markers)); - window.localStorage.setItem("lockPOV", JSON.stringify(Settings.lockPOV)); - window.localStorage.setItem("menuVisible", String(Settings.menuVisible)); - window.localStorage.setItem("use3dView", String(Settings.use3dView)); - window.localStorage.setItem("maxUiScale", String(Settings.maxUiScale)); - } - - static readFromStorage() { - Settings.minimapScale = Settings.mobileCheck() ? 0.65 : 1; - Settings.controlPanelScale = Settings.mobileCheck() ? 0.9 : 1.5; - - Settings.zoomScale = parseFloat(window.localStorage.getItem("zoomScale")) || 1; - - Settings.playsAudio = window.localStorage.getItem("playsAudio") === "true" || false; - Settings.playsAreaAudio = window.localStorage.getItem("playsAreaAudio") === "true" || false; - - if (Settings.mobileCheck()) { - Settings.playsAudio = false; - Settings.playsAreaAudio = false; - } - // Settings.tileSize = parseInt(window.localStorage.getItem('tileSize')) || 23; - // Settings.framesPerTick = parseInt(window.localStorage.getItem('framesPerTick')) || 30; - Settings.inputDelay = parseInt(window.localStorage.getItem("inputDelay") ?? '100'); - Settings.rotated = window.localStorage.getItem("rotated") || "south"; - Settings.loadout = window.localStorage.getItem("loadout") || "max_tbow_speed"; - Settings.onTask = window.localStorage.getItem("onTask") === "true" || false; - Settings.southPillar = window.localStorage.getItem("southPillar") !== "false" || false; - Settings.westPillar = window.localStorage.getItem("westPillar") !== "false" || false; - Settings.northPillar = window.localStorage.getItem("northPillar") !== "false" || false; - Settings.displayPlayerLoS = window.localStorage.getItem("displayPlayerLoS") === "true" || false; - Settings.displayMobLoS = window.localStorage.getItem("displayMobLoS") === "true" || false; - Settings.lockPOV = false; //window.localStorage.getItem('lockPOV') !== 'false' || false; - Settings.displayFeedback = !(window.localStorage.getItem("displayFeedback") === "false" || false); - Settings.metronome = window.localStorage.getItem("metronome") === "true" || false; - - Settings.region = "inferno"; - Settings.displayXpDrops = !(window.localStorage.getItem("displayXpDrops") === "false" || false); - - Settings.inventory_key = window.localStorage.getItem("inventory_key") || "F4"; - Settings.spellbook_key = window.localStorage.getItem("spellbook_key") || "F2"; - Settings.equipment_key = window.localStorage.getItem("equipment_key") || "F1"; - Settings.prayer_key = window.localStorage.getItem("prayer_key") || "F3"; - Settings.combat_key = window.localStorage.getItem("combat_key") || "F5"; - Settings.player_stats = DeserializePlayerStats(window.localStorage.getItem("stats")); - Settings.tile_markers = JSON.parse(window.localStorage.getItem("tile_markers")); - - if (window.localStorage.getItem("menuVisible") === "true") { - Settings.menuVisible = true; - } else if (window.localStorage.getItem("menuVisible") === "false") { - Settings.menuVisible = false; - } else { - Settings.menuVisible = Settings.mobileCheck() === false; - } - if (!Settings.menuVisible) { - document.getElementById("right_panel").classList.add("hidden"); - } - Settings.use3dView = window.localStorage.getItem("use3dView") !== "false" || false; - if (Settings.use3dView) { - Settings.rotated = "north"; - } - Settings.maxUiScale = parseFloat(window.localStorage.getItem("maxUiScale")) || 1.0; - } -} diff --git a/src/sdk/Unit.ts b/src/sdk/Unit.ts deleted file mode 100644 index bd93fe84..00000000 --- a/src/sdk/Unit.ts +++ /dev/null @@ -1,814 +0,0 @@ -import HealSplat from "../assets/images/hitsplats/heal.png"; -import MissSplat from "../assets/images/hitsplats/miss.png"; -import DamageSplat from "../assets/images/hitsplats/damage.png"; -import { Settings } from "./Settings"; -import { LineOfSight, LineOfSightMask } from "./LineOfSight"; -import { remove, filter, clamp } from "lodash"; -import { BasePrayer } from "./BasePrayer"; -import { Projectile } from "./weapons/Projectile"; -import { XpDrop } from "./XpDrop"; -import { Location } from "./Location"; -import { Pathing } from "./Pathing"; -import { ImageLoader } from "./utils/ImageLoader"; -import { Weapon } from "./gear/Weapon"; -import { Offhand } from "./gear/Offhand"; -import { Helmet } from "./gear/Helmet"; -import { Necklace } from "./gear/Necklace"; -import { Chest } from "./gear/Chest"; -import { Legs } from "./gear/Legs"; -import { Feet } from "./gear/Feet"; -import { Gloves } from "./gear/Gloves"; -import { Ring } from "./gear/Ring"; -import { Cape } from "./gear/Cape"; -import { Ammo } from "./gear/Ammo"; -import { SetEffect } from "./SetEffect"; -import { EntityName } from "./EntityName"; -import { Item } from "./Item"; -import { PrayerController } from "./PrayerController"; -import { Region } from "./Region"; -import { Player } from "./Player"; -import { CollisionType } from "./Collision"; -import { Renderable } from "./Renderable"; -import { Sound, SoundCache } from "./utils/SoundCache"; -import { DelayedAction } from "./DelayedAction"; -import { TextSegment, parseText } from "./utils/Text"; -/* eslint-disable @typescript-eslint/no-explicit-any */ - -export enum UnitTypes { - MOB = 0, - PLAYER = 1, - ENTITY = 2, -} - -export class UnitEquipment { - weapon?: Weapon = null; - offhand?: Offhand = null; - helmet?: Helmet = null; - necklace?: Necklace = null; - chest?: Chest = null; - legs?: Legs = null; - feet?: Feet = null; - gloves?: Gloves = null; - ring?: Ring = null; - cape?: Cape = null; - ammo?: Ammo = null; -} - -export interface UnitOptions { - aggro?: Unit; - equipment?: UnitEquipment; - spawnDelay?: number; - cooldown?: number; - inventory?: Item[]; -} - -export interface UnitStats { - attack: number; - strength: number; - defence: number; - range: number; - magic: number; - hitpoint: number; - prayer?: number; -} - -export interface UnitBonuses { - attack: UnitStyleBonuses; - defence: UnitStyleBonuses; - other: UnitOtherBonuses; - targetSpecific?: UnitTargetBonuses; -} - -export interface UnitStyleBonuses { - stab: number; - slash: number; - crush: number; - magic: number; - range: number; -} - -export interface UnitOtherBonuses { - meleeStrength: number; - rangedStrength: number; - magicDamage: number; - prayer: number; - crystalAccuracy?: number; - crystalDamage?: number; -} - -export interface UnitTargetBonuses { - undead: number; - slayer: number; -} - -export abstract class Unit extends Renderable { - prayerController: PrayerController; - lastOverhead?: BasePrayer = null; - aggro?: Unit; - perceivedLocation: Location; - attackDelay = 0; - lastHitAgo = Number.MAX_SAFE_INTEGER; - hasLOS = false; - frozen = 0; - stunned = 0; - incomingProjectiles: Projectile[] = []; - healHitsplatImage: HTMLImageElement = ImageLoader.createImage(HealSplat); - missedHitsplatImage: HTMLImageElement = ImageLoader.createImage(MissSplat); - damageHitsplatImage: HTMLImageElement = ImageLoader.createImage(DamageSplat); - unitImage: HTMLImageElement = ImageLoader.createImage(this.image); - currentStats: UnitStats; - stats: UnitStats; - equipment: UnitEquipment = new UnitEquipment(); - setEffects: (typeof SetEffect)[] = []; - autoRetaliate = false; - age = 0; - lastRotation = 0; - hasDiedAndAwaitingRemoval = false; - nulledTicks = 0; - - overheadText: string | null = null; - overheadTextTimer = 0; - - get deathAnimationLength(): number { - return 3; - } - - get completeSetEffects(): SetEffect[] { - return null; - } - - get type(): UnitTypes { - return UnitTypes.MOB; - } - - get isPlayer(): boolean { - return false; - } - - get xpBonusMultiplier() { - return 1.0; - } - - mobName(): EntityName { - return null; - } - - get isNulled() { - return this.nulledTicks > 0; - } - - get combatLevel() { - const base = 0.25 * (this.stats.defence + this.stats.hitpoint + Math.floor((this.stats.prayer || 0) * 0.5)); - const melee = (13 / 40) * (this.stats.attack + this.stats.strength); - const range = (13 / 40) * Math.floor(this.stats.range * (3 / 2)); - const mage = (13 / 40) * Math.floor(this.stats.magic * (3 / 2)); - return Math.floor(base + Math.max(melee, range, mage)); - } - - combatLevelColor(against: Unit) { - // https://oldschool.runescape.wiki/w/Combat_level#Colours - const colorScale = [ - "#ff0000", //+ 10 - "#ff3000", - "#ff3000", - "#ff3000", - "#ff7000", - "#ff7000", - "#ff7000", - "#ffb000", - "#ffb000", - "#ffb000", - "#ffff00", // + 0 - "#c0ff00", - "#c0ff00", - "#c0ff00", - "#80ff00", - "#80ff00", - "#80ff00", - "#40ff00", - "#40ff00", - "#40ff00", - "#00ff00", // -10 - ]; - - const myCombatLevel = this.combatLevel; - const theirCombatLevel = against.combatLevel; - const difference = Math.min(10, Math.max(-10, theirCombatLevel - myCombatLevel)); - - return colorScale[10 - difference]; - } - - constructor(region: Region, location: Location, options?: UnitOptions) { - super(); - this.region = region; - this.aggro = options.aggro || null; - this.perceivedLocation = location; - this.location = location; - this.setStats(); - this.age = options.spawnDelay || 0; - this.autoRetaliate = true; - this.currentStats.hitpoint = this.stats.hitpoint; - - if (options.cooldown) { - this.attackDelay = options.cooldown; - } - } - - contextActions(region: Region, x: number, y: number) { - return []; - } - - setAggro(mob: Unit) { - this.aggro = mob; - } - - grantXp(xpDrop: XpDrop) { - // Override me - } - - setStats() { - // Override me - } - - movementStep() { - // Override me - } - - attackStep() { - // Override me, called after all movement has been resolved - this.nulledTicks--; - this.attackDelay--; - this.lastRotation = this.getPerceivedRotation(0); - - if (this.overheadTextTimer <= 0) { - this.overheadText = null; - } - this.overheadTextTimer--; - } - - // called when the unit has attacked - didAttack() { - this.attackDelay = this.attackSpeed; - this.playAttackAnimation(); - } - - playAttackAnimation() { - if (this.attackAnimationId) { - // only blend if not idle - const doBlend = this.animationIndex !== this.idlePoseId && this.canBlendAttackAnimation; - this.playAnimation(this.attackAnimationId, doBlend); - } - } - - getPerceivedLocation(tickPercent: number) { - const perceivedX = Pathing.linearInterpolation(this.perceivedLocation.x, this.location.x, tickPercent); - const perceivedY = Pathing.linearInterpolation(this.perceivedLocation.y, this.location.y, tickPercent); - return { x: perceivedX, y: perceivedY, z: 0 }; - } - - getPerceivedRotation(tickPercent) { - if (this.aggro) { - const perceivedLocation = this.aggro.getPerceivedLocation(tickPercent); - return -Pathing.angle( - this.location.x + this.size / 2, - this.location.y - this.size / 2, - perceivedLocation.x + this.aggro.size / 2, - perceivedLocation.y - this.aggro.size / 2, - ); - } - return this.lastRotation; - } - - addedToWorld() { - // override me - } - - getTrueLocation() { - return this.location; - } - - removedFromWorld() { - // Override me - } - - static mergeEquipmentBonuses(firstBonuses: UnitBonuses, secondBonuses: UnitBonuses): UnitBonuses { - return { - attack: { - stab: firstBonuses.attack.stab + secondBonuses.attack.stab, - slash: firstBonuses.attack.slash + secondBonuses.attack.slash, - crush: firstBonuses.attack.crush + secondBonuses.attack.crush, - magic: firstBonuses.attack.magic + secondBonuses.attack.magic, - range: firstBonuses.attack.range + secondBonuses.attack.range, - }, - defence: { - stab: firstBonuses.defence.stab + secondBonuses.defence.stab, - slash: firstBonuses.defence.slash + secondBonuses.defence.slash, - crush: firstBonuses.defence.crush + secondBonuses.defence.crush, - magic: firstBonuses.defence.magic + secondBonuses.defence.magic, - range: firstBonuses.defence.range + secondBonuses.defence.range, - }, - other: { - meleeStrength: firstBonuses.other.meleeStrength + secondBonuses.other.meleeStrength, - rangedStrength: firstBonuses.other.rangedStrength + secondBonuses.other.rangedStrength, - magicDamage: firstBonuses.other.magicDamage + secondBonuses.other.magicDamage, - prayer: firstBonuses.other.prayer + secondBonuses.other.prayer, - crystalAccuracy: (firstBonuses.other.crystalAccuracy || 0) + (secondBonuses.other.crystalAccuracy || 0), - crystalDamage: (firstBonuses.other.crystalDamage || 0) + (secondBonuses.other.crystalDamage || 0), - }, - targetSpecific: { - undead: firstBonuses.targetSpecific.undead + secondBonuses.targetSpecific.undead, - slayer: firstBonuses.targetSpecific.slayer + secondBonuses.targetSpecific.slayer, - }, - }; - } - - static emptyBonuses(): UnitBonuses { - return { - attack: { - stab: 0, - slash: 0, - crush: 0, - magic: 0, - range: 0, - }, - defence: { - stab: 0, - slash: 0, - crush: 0, - magic: 0, - range: 0, - }, - other: { - meleeStrength: 0, - rangedStrength: 0, - magicDamage: 1, - prayer: 0, - crystalAccuracy: 1, - crystalDamage: 1, - }, - targetSpecific: { - undead: 0, - slayer: 0, - }, - }; - } - - get bonuses(): UnitBonuses { - return Unit.emptyBonuses(); - } - - get attackSpeed() { - return 0; - } - - get flinchDelay() { - return Math.floor(this.attackSpeed / 2); - } - - get attackRange() { - return 0; - } - - get maxHit() { - return 0; - } - - get image(): string { - return null; - } - - get isAnimated(): boolean { - return false; - } - - // Returns true if the NPC can move towards the unit it is aggro'd against. - canMove() { - return !this.hasLOS && !this.isFrozen() && !this.isStunned() && !this.isDying(); - } - - canAttack() { - return !this.isDying() && !this.isStunned(); - } - - freeze(ticks: number) { - if (ticks < this.frozen) { - return; - } - //this.perceivedLocation = this.location; - this.frozen = ticks; - } - - isFrozen() { - return this.frozen > 0; - } - - isStunned() { - return this.stunned > 0; - } - - region: Region; - location: Location; - dying = -1; - _serialNumber: string; - get serialNumber(): string { - if (!this._serialNumber) { - this._serialNumber = String(Math.random()); - } - return this._serialNumber; - } - - get size() { - return 1; - } - - isDying() { - return this.dying > 0; - } - - get collisionType() { - return CollisionType.BLOCK_MOVEMENT; - } - - get lineOfSight(): LineOfSightMask { - return LineOfSightMask.FULL_MASK; - } - - // Returns true if this game object is on the specified tile. - isOnTile(x: number, y: number) { - return ( - x >= this.location.x && - x <= this.location.x + this.size && - y <= this.location.y && - y >= this.location.y - this.size - ); - } - - // Returns the closest tile on this mob to the specified point. - getClosestTileTo(x: number, y: number): [number, number] { - // We simply clamp the target point to our own boundary box. - return [ - clamp(x, this.location.x, this.location.x + this.size - 1), - clamp(y, this.location.y - this.size + 1, this.location.y), - ]; - } - - // TODO more modular - get rangeAttackAnimation() { - return null; - } - - /** Sounds **/ - - // sound to play when hit - hitSound(damaged: boolean): Sound | null { - return null; - } - - get color(): string { - return "#FFFFFF00"; - } - - get healthScale(): number { - // the server usually only sends hitpoints as a fraction where this is the denominator. - return Math.min(this.stats.hitpoint, 30); - } - - shouldDestroy() { - // this is -1 for a living npc. - return this.dying === 0; - } - - shouldShowAttackAnimation() { - return this.attackDelay === this.attackSpeed && this.dying === -1 && this.isStunned() === false; - } - - setHasLOS() { - if (!this.aggro) { - this.hasLOS = false; - return; - } - if (this.aggro.type === UnitTypes.PLAYER) { - this.hasLOS = LineOfSight.mobHasLineOfSightOfPlayer( - this.region, - this.aggro as Player, - this.location.x, - this.location.y, - this.size, - this.attackRange, - true, - ); - } else if (this.type === UnitTypes.PLAYER) { - this.hasLOS = LineOfSight.playerHasLineOfSightOfMob( - this.region, - this.location.x, - this.location.y, - this.aggro, - this.attackRange, - ); - } else if (this.type === UnitTypes.MOB && this.aggro.type === UnitTypes.MOB) { - this.hasLOS = LineOfSight.mobHasLineOfSightToMob(this.region, this, this.aggro, this.attackRange); - } else if (this.aggro.type === UnitTypes.MOB) { - this.hasLOS = LineOfSight.playerHasLineOfSightOfMob( - this.region, - this.location.x, - this.location.y, - this.aggro, - this.attackRange, - ); - } else if (this.aggro.type === UnitTypes.ENTITY) { - this.hasLOS = false; - } - } - - // Returns true if this mob is in melee range of its target. - isWithinMeleeRange() { - const targetX = this.aggro.location.x; - const targetY = this.aggro.location.y; - let isWithinMeleeRange = false; - - if ( - targetX === this.location.x - 1 && - targetY <= this.location.y + 1 && - targetY > this.location.y - this.size - 1 - ) { - isWithinMeleeRange = true; - } else if (targetY === this.location.y + 1 && targetX >= this.location.x && targetX < this.location.x + this.size) { - isWithinMeleeRange = true; - } else if ( - targetX === this.location.x + this.size && - targetY <= this.location.y + 1 && - targetY > this.location.y - this.size - 1 - ) { - isWithinMeleeRange = true; - } else if ( - targetY === this.location.y - this.size && - targetX >= this.location.x && - targetX < this.location.x + this.size - ) { - isWithinMeleeRange = true; - } - return isWithinMeleeRange; - } - - addProjectile(projectile: Projectile) { - if (this.age > 0 && this.autoRetaliate && !this.aggro) { - this.setAggro(projectile.from); - } - this.incomingProjectiles.push(projectile); - } - - setLocation(location: Location) { - this.location = location; - } - - attackAnimation(tickPercent: number, context: OffscreenCanvasRenderingContext2D) { - // override pls - } - - cancelDeath() { - // e.g. when revived - this.hasDiedAndAwaitingRemoval = false; - this.dying = -1; - } - - dead() { - this.perceivedLocation = this.location; - this.dying = this.deathAnimationLength; - this.aggro = null; - this.hasDiedAndAwaitingRemoval = true; - if (this.deathAnimationId) { - DelayedAction.registerDelayedAction( - new DelayedAction( - () => - this.playAnimation(this.deathAnimationId, false).then(() => { - if (this.hasDiedAndAwaitingRemoval) { - // can be cancelled - this.dying = 0; - this.detectDeath(); - } - }), - 1, - ), - ); - } - } - - detectDeath() { - if (this.dying === -1 && this.currentStats.hitpoint <= 0) { - this.dead(); - return; - } - - if (this.dying > 0) { - this.dying--; - } - if (this.dying === 0) { - this.removedFromWorld(); - } - } - - processIncomingAttacks() { - this.lastHitAgo++; - this.incomingProjectiles = filter( - this.incomingProjectiles, - (projectile: Projectile) => !projectile.shouldDestroy(), - ); - this.incomingProjectiles.forEach((projectile) => { - projectile.onTick(); - - if (projectile.remainingDelay === 0) { - // may override damage etc - projectile.beforeHit(); - // Some attacks can be nullified if they land after the attackers death. - if ( - projectile.options && - projectile.options.cancelOnDeath === true && - projectile.from && - projectile.from.isDying() === true - ) { - return; - } - - if (projectile.damage < 0) { - // subtracting a negative gives a positive - if (this.currentStats.hitpoint < this.stats.hitpoint) { - this.currentStats.hitpoint -= projectile.damage; - this.currentStats.hitpoint = Math.min(this.currentStats.hitpoint, this.stats.hitpoint); - } - } else { - this.currentStats.hitpoint -= projectile.damage; - const sound = this.hitSound(projectile.damage > 0); - if (sound) { - SoundCache.play(sound); - } - } - this.damageTaken(); - this.lastHitAgo = 0; - if (this.shouldChangeAggro(projectile)) { - this.setAggro(projectile.from); - - if (this.attackDelay < this.flinchDelay + 1) { - this.attackDelay = this.flinchDelay + 1; - } - } - } - }); - this.currentStats.hitpoint = Math.max(0, this.currentStats.hitpoint); - this.postAttacksEvent(); - } - - shouldChangeAggro(projectile: Projectile) { - return !this.aggro && this.autoRetaliate; - } - - postAttacksEvent() { - // Override me - } - - damageTaken() { - // Override me - } - - setOverheadText(text: string) { - this.overheadText = text; - this.overheadTextTimer = 8; - } - - drawOverheadText(context: OffscreenCanvasRenderingContext2D, scale: number, alignCenter = true, prefix = "") { - if (!this.overheadText) { - return; - } - const parsedText = parseText(this.overheadText); - const textParts = prefix ? [{ text: prefix }, ...parsedText] : parsedText; - this.drawText(context, textParts, scale, alignCenter, prefix); - } - - drawText(context: OffscreenCanvasRenderingContext2D, textParts: TextSegment[], scale: number, alignCenter = true, prefix = "") { - context.font = "24px OSRS"; - const fullText = textParts.map(({text}) => text).join(""); - const fullWidth = context.measureText(fullText); - const startX = alignCenter ? -(fullWidth.width / 2) : 0; - context.fillStyle = "black"; - context.fillText(fullText, startX + 1, (-(this.size / 2) * scale) - 10 + 1); - let x = startX; - for (let i = 0; i < textParts.length; i++) { - const { text, color } = textParts[i]; - context.fillStyle = color ? `#${color}` : "yellow"; - context.fillText(text, x, (-(this.size / 2) * scale) - 10); - x += context.measureText(text).width; - } - } - - override draw(tickPercent, context, offset, scale, drawUnderTile) { - if (this.isAnimated) { - this.unitImage = ImageLoader.imageCache[this.image]; - } - super.draw(tickPercent, context, offset, scale, drawUnderTile); - } - - drawHitsplat(projectile: Projectile): boolean { - return true; - } - - drawHPBar(context: OffscreenCanvasRenderingContext2D, scale: number) { - context.fillStyle = "red"; - context.fillRect((-this.size / 2) * scale, -(this.size / 2) * scale, scale * this.size, 5); - - const healthRatio = Math.min(1, Math.ceil((this.currentStats.hitpoint / this.stats.hitpoint) * this.healthScale) / this.healthScale); - context.fillStyle = "lime"; - const w = healthRatio * (scale * this.size); - context.fillRect((-this.size / 2) * scale, (-this.size / 2) * scale, w, 5); - } - - drawHitsplats(context: OffscreenCanvasRenderingContext2D, scale: number, above: boolean) { - let projectileOffsets = [ - [0, 12], - [0, 28], - [-14, 20], - [14, 20], - ]; - - let projectileCounter = 0; - let verticalOffset = -((this.size + 1) * scale) / 2; - if (!above) { - verticalOffset *= -1; - } - this.incomingProjectiles.forEach((projectile) => { - if (projectile.remainingDelay > 0) { - return; - } - if (projectileCounter > 3) { - return; - } - projectileCounter++; - if (this.drawHitsplat(projectile)) { - let image = projectile.damage === 0 ? this.missedHitsplatImage : this.damageHitsplatImage; - if (!projectile.offsetX && !projectile.offsetY) { - projectile.offsetX = projectileOffsets[0][0]; - projectile.offsetY = projectileOffsets[0][1]; - } - - projectileOffsets = remove(projectileOffsets, (offset) => { - return offset[0] !== projectile.offsetX || offset[1] !== projectile.offsetY; - }); - - if (projectile.damage < 0) { - image = this.healHitsplatImage; - } - - context.drawImage(image, projectile.offsetX - 12, verticalOffset - projectile.offsetY, 24, 23); - context.fillStyle = "#FFFFFF"; - context.font = "16px Stats_11"; - context.textAlign = "center"; - context.fillText( - String(Math.abs(projectile.damage)), - projectile.offsetX, - verticalOffset - projectile.offsetY + 15, - ); - context.textAlign = "left"; - } - }); - } - - drawOverheadPrayers(context: OffscreenCanvasRenderingContext2D, scale: number) { - if (!this.prayerController) { - return; - } - - const overhead = this.prayerController.overhead(); - if (overhead) { - const overheadImg = overhead.overheadImage(); - if (overheadImg) { - context.drawImage(overheadImg, -scale / 2, -scale * 3, scale, scale); - } - } - } - - get idlePoseId() { - return 0; - } - - get walkingPoseId(): number | null { - return 1; - } - - get animationIndex() { - // can be overriden by setAnimation - if (this.perceivedLocation.x !== this.location.x || this.perceivedLocation.y !== this.location.y) { - return this.walkingPoseId ?? this.idlePoseId; - } - return this.idlePoseId; - } - - get attackAnimationId(): number | null { - return null; - } - - get canBlendAttackAnimation(): boolean { - return false; - } - - get deathAnimationId(): number | null { - return null; - } -} diff --git a/src/sdk/Viewport.ts b/src/sdk/Viewport.ts deleted file mode 100644 index d402f624..00000000 --- a/src/sdk/Viewport.ts +++ /dev/null @@ -1,225 +0,0 @@ -"use strict"; -import { Settings } from "./Settings"; -import { ClickController } from "./ClickController"; -import { Chrome } from "./Chrome"; -import { Player } from "./Player"; -import { ContextMenu } from "./ContextMenu"; -import { World } from "./World"; -import { ControlPanelController } from "./ControlPanelController"; -import { MapController } from "./MapController"; -import { XpDropController } from "./XpDropController"; -import { ImageLoader } from "./utils/ImageLoader"; -import ButtonActiveIcon from "../assets/images/interface/button_active.png"; -import { CardinalDirection, Region } from "./Region"; -import { Viewport3d } from "./Viewport3d"; -import { Location } from "./Location"; -import { Mob } from "./Mob"; -import { Item } from "./Item"; -import { Viewport2d } from "./Viewport2d"; -import { CombatControls } from "./controlpanels/CombatControls"; - -type ViewportEntitiesClick = { - type: "entities"; - mobs: Mob[]; - players: Player[]; - groundItems: Item[]; - location: Location; -}; - -type ViewportCoordinateClick = { - type: "coordinate"; - location: Location; -}; - -type ViewportClickResult = ViewportEntitiesClick | ViewportCoordinateClick | null; - -type ViewportDrawResult = { - // game canvas - canvas: OffscreenCanvas; - // drawn on top of the game canvas. optional, not used for 2d view - uiCanvas: OffscreenCanvas | null; - flip: boolean; - offsetX: number; - offsetY: number; -}; - -export interface ViewportDelegate { - initialise(world: World, region: Region): Promise; - - draw(world: World, region: Region): ViewportDrawResult; - - // translate the click (relative to the viewport) to a location in the world or something that got clicked - translateClick(offsetX: number, offsetY: number, world: World, viewport: Viewport): ViewportClickResult; - - getMapRotation(): number; - - setMapRotation(direction: CardinalDirection); -} - -export class Viewport { - static viewport: Viewport; - static setupViewport(region: Region, force2d = false) { - const faceInitialSouth = region.initialFacing === CardinalDirection.SOUTH; - // called after Settings have been initialized - Viewport.viewport = new Viewport( - Settings.use3dView && !force2d ? new Viewport3d(faceInitialSouth) : new Viewport2d(), - ); - } - - activeButtonImage: HTMLImageElement = ImageLoader.createImage(ButtonActiveIcon); - contextMenu: ContextMenu = new ContextMenu(); - - clickController: ClickController; - canvas: HTMLCanvasElement; - player: Player; - width: number; - height: number; - - constructor(private delegate: ViewportDelegate) {} - - /** - * Return all objects or world coordinates at the given position (relative to the top-left of the viewport). - */ - translateClick(offsetX: number, offsetY: number, world: World): ViewportClickResult { - return this.delegate.translateClick(offsetX, offsetY, world, this); - } - - get context() { - return this.canvas.getContext("2d"); - } - setPlayer(player: Player) { - this.player = player; - window.addEventListener("orientationchange", () => this.calculateViewport()); - window.addEventListener("resize", () => this.calculateViewport()); - window.addEventListener("wheel", () => this.calculateViewport()); - window.addEventListener("resize", () => this.calculateViewport()); - this.canvas = document.getElementById("world") as HTMLCanvasElement; - this.calculateViewport(); - this.canvas.width = Settings._tileSize * 2 * this.width; - this.canvas.height = Settings._tileSize * 2 * this.height; - this.clickController = new ClickController(this); - this.clickController.registerClickActions(); - } - - // called after all graphics have loaded - async initialise() { - await this.delegate.initialise(this.player.region.world, this.player.region); - return; - } - - calculateViewport() { - const { width, height } = Chrome.size(); - Settings._tileSize = width / this.player.region.width; - this.width = width / Settings.tileSize; - this.height = height / Settings.tileSize; - if (width !== this.canvas.width || height !== this.canvas.height) { - this.canvas.width = width; - this.canvas.height = height; - } - } - - getViewport(tickPercent: number) { - if (this.player.dying > -1) { - tickPercent = 0; - } - const { x, y } = this.player.getPerceivedLocation(tickPercent); - const viewportX = x + 0.5 - this.width / 2; - const viewportY = y + 0.5 - this.height / 2; - return { viewportX, viewportY }; - } - - drawText(text: string, x: number, y: number) { - x = Math.floor(x); - y = Math.floor(y); - this.context.fillStyle = "#000"; - this.context.fillText(text, x - 2, y - 2); - this.context.fillText(text, x + 2, y - 2); - this.context.fillText(text, x, y); - this.context.fillText(text, x, y - 4); - this.context.fillStyle = "#FFFFFF"; - this.context.fillText(text, x, y - 2); - } - - tick() { - if (MapController.controller && this.player) { - MapController.controller.updateOrbsMask(this.player.currentStats, this.player.stats); - } - } - - getMapRotation() { - return this.delegate.getMapRotation(); - } - - rotateSouth() { - this.delegate.setMapRotation(CardinalDirection.SOUTH); - } - - rotateNorth() { - this.delegate.setMapRotation(CardinalDirection.NORTH); - } - - getDelegate() { - return this.delegate; - } - - draw(world: World) { - this.context.globalAlpha = 1; - this.context.fillStyle = "#3B3224"; - this.context.restore(); - this.context.save(); - this.context.fillStyle = "black"; - const { width, height } = Chrome.size(); - this.context.fillRect(0, 0, width, height); - const { canvas, uiCanvas, flip, offsetX, offsetY } = this.delegate.draw(world, this.player.region); - if (flip) { - this.context.rotate(Math.PI); - this.context.translate(-width, -height); - } - this.context.drawImage(canvas, offsetX, offsetY); - if (uiCanvas) { - this.context.drawImage(uiCanvas, offsetX, offsetY); - } - this.context.restore(); - this.context.save(); - - if (Settings.mobileCheck()) { - this.context.fillStyle = "#FFFF00"; - this.context.font = 16 + "px OSRS"; - this.context.textAlign = "center"; - - this.context.drawImage( - this.activeButtonImage, - 20, - 20, - this.activeButtonImage.width, - this.activeButtonImage.height, - ); - this.context.fillText("RESET", 40, 45); - } - - // draw control panel - ControlPanelController.controller.draw(this.context); - XpDropController.controller.draw( - this.context, - width - 140 - MapController.controller.width - (Settings.menuVisible ? 232 : 0), - 0, - world.tickPercent, - ); - MapController.controller.draw(this.context); - this.contextMenu.draw(); - - if (this.clickController.clickAnimation) { - this.clickController.clickAnimation.draw(); - } - - this.context.restore(); - this.context.save(); - - this.context.textAlign = "left"; - if (world.getReadyTimer > 0) { - this.context.font = "72px OSRS"; - this.context.textAlign = "center"; - this.drawText(`GET READY...${world.getReadyTimer}`, width / 2, height / 2 - 50); - } - } -} diff --git a/src/sdk/Viewport2d.ts b/src/sdk/Viewport2d.ts deleted file mode 100644 index cbbf5347..00000000 --- a/src/sdk/Viewport2d.ts +++ /dev/null @@ -1,195 +0,0 @@ -"use strict"; -import { Player } from "./Player"; -import { World } from "./World"; -import { Viewport, ViewportDelegate } from "./Viewport"; -import { CardinalDirection, GroundItems, Region } from "./Region"; -import { Settings } from "./Settings"; -import { Renderable } from "./Renderable"; -import { Unit } from "./Unit"; -import { Pathing } from "./Pathing"; -import { Mob } from "./Mob"; -import { Collision } from "./Collision"; -import { Item } from "./Item"; -import _ from "lodash"; - -export class Viewport2d implements ViewportDelegate { - async initialise(world: World, region: Region) { - // do nothing, but maybe we should buffer the world background - return; - } - - draw(world: World, region: Region) { - region.context.save(); - region.drawWorldBackground(region.context, Settings.tileSize); - region.drawGroundItems(region.context); - - // Draw all things on the map - const renderables: Renderable[] = [...region.entities]; - const units: Unit[] = []; - - if (world.getReadyTimer <= 0) { - units.push(...region.mobs); - units.push(...region.newMobs); - } - units.push(...region.players); - renderables.concat(units).forEach((r) => { - const location = r.getPerceivedLocation(world.tickPercent); - r.draw(world.tickPercent, region.context, location, Settings.tileSize); - }); - const getOffset = (r: Renderable) => { - const perceivedLocation = r.getPerceivedLocation(world.tickPercent); - const perceivedX = perceivedLocation.x; - const perceivedY = perceivedLocation.y; - - return { - x: perceivedX * Settings.tileSize + (r.size * Settings.tileSize) / 2, - y: (perceivedY - r.size + 1) * Settings.tileSize + (r.size * Settings.tileSize) / 2, - }; - }; - - region.entities.forEach((entity) => entity.drawUILayer(world.tickPercent, getOffset(entity), entity.region.context, Settings.tileSize, true)); - if (world.getReadyTimer <= 0) { - region.mobs.forEach((mob) => - mob.drawUILayer(world.tickPercent, getOffset(mob), mob.region.context, Settings.tileSize, true), - ); - - region.players.forEach((player: Player) => { - player.drawUILayer(world.tickPercent, getOffset(player), player.region.context, Settings.tileSize, true); - }); - - units.forEach((unit) => { - if (unit.dying === -1) { - this.drawIncomingProjectiles(unit, unit.region.context, world.tickPercent); - } - }); - } - - region.context.restore(); - - const { viewportX, viewportY } = Viewport.viewport.getViewport(world.tickPercent); - return { - canvas: region.canvas, - uiCanvas: null, - flip: Settings.rotated === "south", - offsetX: -viewportX * Settings.tileSize, - offsetY: -viewportY * Settings.tileSize, - }; - } - - translateClick(offsetX, offsetY, world: World, viewport: Viewport) { - const { viewportX, viewportY } = viewport.getViewport(world.tickPercent); - let x: number = offsetX + viewportX * Settings.tileSize; - let y: number = offsetY + viewportY * Settings.tileSize; - - if (Settings.rotated === "south") { - x = viewport.width * Settings.tileSize - offsetX + viewportX * Settings.tileSize; - y = viewport.height * Settings.tileSize - offsetY + viewportY * Settings.tileSize; - } - const adjustedX = x / Settings.tileSize; - const adjustedY = y / Settings.tileSize; - const mobs: Mob[] = []; - const players: Player[] = []; - const groundItems: Item[] = []; - const region = viewport.player.region; - - mobs.push( - ...Collision.collidesWithAnyMobsAtPerceivedDisplayLocation(region, adjustedX, adjustedY, world.tickPercent), - ); - players.push( - ...Collision.collidesWithAnyPlayersAtPerceivedDisplayLocation( - region, - adjustedX, - adjustedY, - world.tickPercent, - ).filter((player: Player) => player !== Viewport.viewport.player), - ); - groundItems.push(...region.groundItemsAtLocation(Math.floor(adjustedX), Math.floor(adjustedY))); - if (mobs.length > 0 || players.length > 0 || groundItems.length > 0) { - return { - type: "entities" as const, - mobs: _.uniq(mobs), - players: players, - groundItems: groundItems, - location: { - x: adjustedX, - y: adjustedY, - }, - }; - } - return { - type: "coordinate" as const, - location: { - x: adjustedX, - y: adjustedY, - }, - }; - } - - // The rendering context is the world. - drawIncomingProjectiles( - unit: Unit, - context: OffscreenCanvasRenderingContext2D, - tickPercent: number, - scale: number = Settings.tileSize, - ) { - const { incomingProjectiles } = unit; - incomingProjectiles.forEach((projectile) => { - if (projectile.options.hidden) { - return; - } - - if (projectile.remainingDelay < 0) { - return; - } - - const startX = projectile.currentLocation.x; - const startY = projectile.currentLocation.y; - const { x: endX, y: endY } = projectile.getTargetDestination(tickPercent); - - const perceivedX = Pathing.linearInterpolation(startX, endX, tickPercent / (projectile.remainingDelay + 1)); - const perceivedY = Pathing.linearInterpolation(startY, endY, tickPercent / (projectile.remainingDelay + 1)); - - context.save(); - context.translate(perceivedX * Settings.tileSize, perceivedY * Settings.tileSize); - - if (projectile.image) { - context.rotate(Math.PI); - context.drawImage(projectile.image, -scale / 2, -scale / 2, scale, scale); - } else { - context.beginPath(); - - context.fillStyle = "#D1BB7773"; - if ( - projectile.attackStyle === "slash" || - projectile.attackStyle === "crush" || - projectile.attackStyle === "stab" - ) { - context.fillStyle = "#FF000073"; - } else if (projectile.attackStyle === "range") { - context.fillStyle = "#00FF0073"; - } else if (projectile.attackStyle === "magic") { - context.fillStyle = "#0000FF73"; - } else if (projectile.attackStyle === "heal") { - context.fillStyle = "#9813aa73"; - } else { - console.log("[WARN] This style is not accounted for in custom coloring: ", projectile.attackStyle); - } - context.arc(0, 0, 5, 0, 2 * Math.PI); - context.fill(); - } - context.restore(); - }); - } - - setMapRotation(direction: CardinalDirection) { - if (direction === CardinalDirection.SOUTH) { - Settings.rotated = "south"; - } else if (direction === CardinalDirection.NORTH) { - Settings.rotated = "north"; - } - } - - getMapRotation(): number { - return Settings.rotated === "south" ? Math.PI : 0; - } -} diff --git a/src/sdk/Viewport3d.ts b/src/sdk/Viewport3d.ts deleted file mode 100644 index 2f4fbc4c..00000000 --- a/src/sdk/Viewport3d.ts +++ /dev/null @@ -1,476 +0,0 @@ -"use strict"; -import { World } from "./World"; -import { Viewport, ViewportDelegate } from "./Viewport"; -import { CardinalDirection, Region } from "./Region"; - -import * as THREE from "three"; -import Stats from "three/examples/jsm/libs/stats.module"; - -import { Chrome } from "./Chrome"; -import { Settings } from "./Settings"; -import { Player } from "./Player"; -import { Mob } from "./Mob"; -import { Entity } from "./Entity"; -import { Renderable } from "./Renderable"; -import { Location } from "./Location"; -import { Actor } from "./rendering/Actor"; -import _ from "lodash"; -import { Unit } from "./Unit"; -import { Projectile } from "./weapons/Projectile"; - -// how many pixels wide should 2d elements be scaled to -const SPRITE_SCALE = 32; - -const MIN_PITCH = -Math.PI / 2; -const MAX_PITCH = 0.1; - -const FLOOR_Y_POS = -0.5; - -export class Viewport3d implements ViewportDelegate { - private canvas: OffscreenCanvas; - private uiCanvas: OffscreenCanvas; - private uiCanvasContext: OffscreenCanvasRenderingContext2D; - - private canvasDimensions: { width: number; height: number } = this.calculateCanvasDimensions(); - - public scene: THREE.Scene; - private renderer: THREE.WebGLRenderer; - private camera: THREE.PerspectiveCamera; - private raycaster: THREE.Raycaster; - - private pivot = new THREE.Object3D(); - private yaw = new THREE.Object3D(); - private pitch = new THREE.Object3D(); - - private yawDelta = 0; - private pitchDelta = 0; - - private stats = new Stats(); - - private knownActors: Map = new Map(); - - private selectedTile: Location | null = null; - private selectedTileMesh: THREE.LineSegments; - - private clock = new THREE.Clock(); - - constructor(faceCameraSouth = true) { - this.scene = new THREE.Scene(); - - this.canvas = new OffscreenCanvas(this.canvasDimensions.width, this.canvasDimensions.height); - this.uiCanvas = new OffscreenCanvas(this.canvasDimensions.width, this.canvasDimensions.height); - this.uiCanvasContext = this.uiCanvas.getContext("2d"); - - this.checkGpu(); - - this.camera = new THREE.PerspectiveCamera(70, this.canvasDimensions.width / this.canvasDimensions.height, 0.1, 50); - this.raycaster = new THREE.Raycaster(); - this.raycaster.params.Points.threshold = 0.1; - this.raycaster.params.Line.threshold = 0.1; - - const worldCanvas = document.getElementById("world") as HTMLCanvasElement; - this.initCameraEvents(worldCanvas); - window.addEventListener("resize", () => this.updateCanvasSize()); - - this.renderer = new THREE.WebGLRenderer({ - canvas: this.canvas, - logarithmicDepthBuffer: true, - antialias: true, - //precision: "lowp", // is this making everything purple on mobile? - }); - - // Set up camera positioning - this.camera.position.set(0, 1, 0); - this.pivot.position.set(0, 0, 0); - // Face south - if (faceCameraSouth) { - this.yaw.rotation.y = Math.PI; - } - // Pitch down slightly - this.pitch.rotation.x = -0.7; - // Zoom out - this.camera.position.z = 12; - this.scene.add(this.pivot); - this.pivot.add(this.yaw); - this.yaw.add(this.pitch); - this.pitch.add(this.camera); - - const lineMaterial = new THREE.LineBasicMaterial({ - color: "#FFFFFF", - linewidth: 2, - }); - const points = [ - new THREE.Vector3(0, 0, 0), - new THREE.Vector3(1, 0, 0), - new THREE.Vector3(1, 0, 0), - new THREE.Vector3(1, 0, -1), - new THREE.Vector3(1, 0, -1), - new THREE.Vector3(0, 0, -1), - new THREE.Vector3(0, 0, -1), - new THREE.Vector3(0, 0, 0), - ]; - const geometry = new THREE.BufferGeometry().setFromPoints(points); - this.selectedTileMesh = new THREE.LineSegments(geometry, lineMaterial); - this.scene.add(this.selectedTileMesh); - - this.animate(); - } - - checkGpu() { - try { - const canvas = document.createElement('canvas'); - const gl = canvas.getContext("webgl"); - const debugInfo = gl?.getExtension("WEBGL_debug_renderer_info"); - const gpuInfo: string = gl?.getParameter(debugInfo.UNMASKED_VENDOR_WEBGL)?.toLowerCase() ?? "none"; - if (gpuInfo.includes("nvidia") || gpuInfo.includes("gpu") || gpuInfo.includes("geforce") || gpuInfo.includes("amd") || gpuInfo.includes("radeon")) { - return; - } - if (gpuInfo === "none" || gpuInfo.includes("google") || gpuInfo.includes("apple") || gpuInfo.includes("intel")) { - document.getElementById("gpu_warning").innerHTML = `Software rendering detected. Framerate may be low. Turn on Hardware Acceleration in your browser if you have a GPU.
${gpuInfo}
`; - } - } catch(err) { - console.warn('error trying to detect gpu', err); - } - } - - // implementation from https://codepen.io/seanwasere/pen/BaMBoPd - onDocumentMouseMove(e: MouseEvent) { - if ((e.buttons & 4) !== 4) return; - this.yaw.rotation.y -= e.movementX * 0.002; - const v = this.pitch.rotation.x - e.movementY * 0.002; - if (v > MIN_PITCH && v < MAX_PITCH) { - this.pitch.rotation.x = v; - } - return false; - } - - onDocumentMouseWheel(e: WheelEvent) { - const v = this.camera.position.z + e.deltaY * 0.005; - if (v >= 2 && v <= 20) { - this.camera.position.z = v; - } - e.preventDefault(); - return false; - } - - onKeyDown(e: KeyboardEvent) { - // values are desired change per second - switch (e.key) { - case "ArrowLeft": - case "a": - case "A": - this.yawDelta = -2; - break; - case "ArrowRight": - case "d": - case "D": - this.yawDelta = 2; - break; - case "ArrowUp": - case "w": - case "W": - this.pitchDelta = -1; - break; - case "ArrowDown": - case "s": - case "S": - this.pitchDelta = 1; - break; - } - } - - onKeyUp(e: KeyboardEvent) { - switch (e.key) { - case "ArrowLeft": - case "ArrowRight": - case "a": - case "d": - case "A": - case "D": - this.yawDelta = 0; - break; - case "ArrowUp": - case "ArrowDown": - case "w": - case "s": - case "W": - case "S": - this.pitchDelta = 0; - break; - } - } - - initCameraEvents(canvas) { - canvas.addEventListener("mousemove", this.onDocumentMouseMove.bind(this), false); - canvas.addEventListener("wheel", this.onDocumentMouseWheel.bind(this), false); - window.addEventListener("keydown", this.onKeyDown.bind(this), false); - window.addEventListener("keyup", this.onKeyUp.bind(this), false); - } - - calculateCanvasDimensions() { - const { width, height } = Chrome.size(); - - const visibleWidth = width - (Settings.menuVisible ? 232 : 0); - - return { width: visibleWidth, height }; - } - - render() { - this.renderer.render(this.scene, this.camera); - } - - animate() { - requestAnimationFrame(() => this.animate()); - - this.render(); - - this.stats.update(); - } - - async initialise(world: World, region: Region) { - document.body.appendChild(this.stats.dom); - - /*const light = new THREE.PointLight(0xffffaa, 1200); - light.position.set(region.width / 2, 30, region.height / 2); - this.scene.add(light);*/ - const hemiLight = new THREE.HemisphereLight(0xffffff, 0xffffff); - hemiLight.position.set(0, 100, 0); - this.scene.add(hemiLight); - const ambientLight = new THREE.AmbientLight(0xffffff, 1); - this.scene.add(ambientLight); - - const floorCanvas = new OffscreenCanvas(region.width * SPRITE_SCALE, region.height * SPRITE_SCALE); - const floorContext = floorCanvas.getContext("2d"); - - region.drawWorldBackground(floorContext, SPRITE_SCALE); - - const floorTexture = new THREE.Texture(floorCanvas); - floorTexture.needsUpdate = true; - - const floorGeometry = new THREE.PlaneGeometry(region.width, region.height, 1, 1); - const floorMaterial = new THREE.MeshStandardMaterial({ - map: floorTexture, - transparent: true, - color: 0xffffff, - side: THREE.FrontSide, - }); - floorGeometry.rotateX(-Math.PI / 2); - floorGeometry.translate(region.width / 2, FLOOR_Y_POS, region.height / 2 - 1); - const plane = new THREE.Mesh(floorGeometry, floorMaterial); - plane.userData.clickable = true; - // used for right-click walk here - plane.userData.isFloor = true; - plane.visible = Viewport.viewport.player.region.drawDefaultFloor(); - this.scene.add(plane); - - this.scene.add(this.selectedTileMesh); - - // preload by adding a bunch of models to the scene but out of sight - await Viewport.viewport.player.region.preload(); - await this.renderer.compileAsync(this.scene, this.camera); - } - - private updateCanvasSize() { - // update canvas if necessary - const newDimensions = this.calculateCanvasDimensions(); - if (newDimensions.width !== this.canvasDimensions.width || newDimensions.height !== this.canvasDimensions.height) { - this.canvas.width = newDimensions.width; - this.canvas.height = newDimensions.height; - this.uiCanvas.width = newDimensions.width; - this.uiCanvas.height = newDimensions.height; - this.camera.aspect = newDimensions.width / newDimensions.height; - this.camera.updateProjectionMatrix(); - this.renderer.setSize(newDimensions.width, newDimensions.height, false); - this.canvasDimensions = newDimensions; - } - } - - draw(world: World, region: Region) { - this.updateCanvasSize(); - this.draw3dScene(world, region); - this.draw2dScene(world, region); - - return { - canvas: this.canvas, - uiCanvas: this.uiCanvas, - flip: false, - offsetX: 0, - offsetY: 0, - }; - } - - updateCamera(delta: number) { - this.yaw.rotation.y += this.yawDelta * delta; - this.pitch.rotation.x = Math.max(Math.min(this.pitch.rotation.x + this.pitchDelta * delta, MAX_PITCH), MIN_PITCH); - } - - draw3dScene(world: World, region: Region) { - // create actors - region.entities.forEach((entity: Entity) => { - let actor = this.knownActors.get(entity); - if (!actor) { - actor = new Actor(entity); - this.knownActors.set(entity, actor); - } - }); - - const projectiles: Projectile[] = []; - region.players.forEach((player: Player) => { - let actor = this.knownActors.get(player); - if (!actor) { - actor = new Actor(player); - this.knownActors.set(player, actor); - } - // Update the camera position relative to the player's mesh - const v = new THREE.Vector3(0.5, 0, -0.5); - v.add(actor.getModel().getWorldPosition()); - this.pivot.position.lerp(v, 0.1); - // Add all projectiles to scene - projectiles.push(...player.incomingProjectiles); - }); - - region.mobs.concat(region.newMobs).forEach((mob: Mob) => { - let actor = this.knownActors.get(mob); - if (!actor) { - actor = new Actor(mob); - this.knownActors.set(mob, actor); - } - // Add all projectiles to scene - projectiles.push(...mob.incomingProjectiles); - }); - - region.projectiles.forEach((projectile: Projectile) => { - let actor = this.knownActors.get(projectile); - if (!actor) { - actor = new Actor(projectile); - this.knownActors.set(projectile, actor); - } - // Add all projectiles to scene - projectiles.push(projectile); - }); - - projectiles.forEach((projectile) => { - let actor = this.knownActors.get(projectile); - if (!actor) { - actor = new Actor(projectile); - this.knownActors.set(projectile, actor); - } - }); - - const delta = this.clock.getDelta(); - this.updateCamera(delta); - - this.knownActors.forEach((actor, entity) => { - if (actor.shouldRemove()) { - // remove destroyed actors - actor.destroy(this.scene); - this.knownActors.delete(entity); - } else { - actor.draw(this.scene, delta, world.tickPercent); - } - }); - - // highlight selected tile - if (this.selectedTile) { - this.selectedTileMesh.position.x = this.selectedTile.x - 0.5; - this.selectedTileMesh.position.y = -0.49; - this.selectedTileMesh.position.z = this.selectedTile.y - 0.5; - this.selectedTileMesh.visible = !Viewport.viewport.clickController.hasSelectedMob(); - } - } - - draw2dScene(world: World, region: Region) { - // draw UI elements into a separate canvas that gets drawn over the 3d canvas - this.uiCanvasContext.clearRect(0, 0, this.uiCanvas.width, this.uiCanvas.height); - const translator = (pos: Location, z = 0) => this.projectToScreen(new THREE.Vector3(pos.x, z, pos.y)); - - const get2dOffset = (r: Renderable) => { - const perceivedLocation = r.getPerceivedLocation(world.tickPercent); - const { x, y } = translator( - { - x: perceivedLocation.x + r.size / 2, - y: perceivedLocation.y - r.size / 2, - }, - r.height, - ); - return { x, y }; - }; - const units: Unit[] = [...region.players, ...(world.getReadyTimer <= 0 ? region.mobs : [])]; - - const renderables: Renderable[] = (units as Renderable[]).concat(region.entities); - - renderables.forEach((r) => { - r.drawUILayer(world.tickPercent, get2dOffset(r), this.uiCanvasContext, SPRITE_SCALE, false); - }); - } - - // return canvas coordinates from world coordinates - projectToScreen(vector: THREE.Vector3) { - const newVector = vector.clone(); - newVector.project(this.camera); - const { width, height } = this.canvasDimensions; - return { - x: Math.round((newVector.x + 1) * (width / 2)), - y: Math.round((-newVector.y + 1) * (height / 2)), - }; - } - - // return intersection with world object or world coordinates from canvas coordinates - translateClick(offsetX, offsetY, world, viewport) { - const { width, height } = this.canvasDimensions; - const rayX = (offsetX / width) * 2 - 1; - const rayY = -(offsetY / height) * 2 + 1; - - this.raycaster.setFromCamera(new THREE.Vector2(rayX, rayY), this.camera); - // check intersection of the ray and the flor plane - const floorPlane = new THREE.Plane(new THREE.Vector3(0, -1, 0), FLOOR_Y_POS); - const floor = new THREE.Vector3(0, 0, 0); - this.raycaster.ray.intersectPlane(floorPlane, floor); - - this.selectedTile = { - x: Math.floor(floor.x) + 0.5, - y: Math.floor(floor.z) + 1.5, - }; - const intersections = this.raycaster.intersectObjects( - this.scene.children.filter((c) => c.userData.clickable === true), - ); - - // check if there were any NPCs on the way. - const mobs = intersections - .filter((i) => i.object.userData.unit instanceof Mob) - .map((i) => i.object.userData.unit as Mob); - - // Note: we currently only handle clicking on mobs - if (mobs.length > 0) { - return { - type: "entities" as const, - mobs: _.uniq(mobs), - players: [], - groundItems: [], - location: { - x: this.selectedTile.x, - y: this.selectedTile.y, - }, - }; - } - return { - type: "coordinate" as const, - location: { - x: this.selectedTile.x, - y: this.selectedTile.y, - }, - }; - } - - setMapRotation(direction: CardinalDirection) { - if (direction === CardinalDirection.SOUTH) { - this.yaw.rotation.y = Math.PI; - } else if (direction === CardinalDirection.NORTH) { - this.yaw.rotation.y = 0; - } - } - - getMapRotation(): number { - return this.yaw.rotation.y; - } -} diff --git a/src/sdk/World.ts b/src/sdk/World.ts deleted file mode 100644 index 2134710f..00000000 --- a/src/sdk/World.ts +++ /dev/null @@ -1,186 +0,0 @@ -"use strict"; -import { Settings } from "./Settings"; -import { XpDropController } from "./XpDropController"; -import { Player } from "./Player"; -import { Region } from "./Region"; -import { DelayedAction } from "./DelayedAction"; -import { Viewport } from "./Viewport"; -import MetronomeSound from "../assets/sounds/bonk.ogg"; -import { Pathing } from "./Pathing"; -import { InputController } from "./Input"; -import { ControlPanelController } from "./ControlPanelController"; -import { Projectile } from "./weapons/Projectile"; -import { filter } from "lodash"; - -const CLIENT_TICK_MS = 20; - -export class World { - regions: Region[] = []; - globalTickCounter = 0; - isPaused = true; - tickPercent: number; - clientTickPercent: number; - getReadyTimer = 0; - deltaTimeSincePause = -1; - deltaTimeSinceLastTick = -1; - lastMenuVisible: boolean; - fpsInterval = 1000 / Settings.fps; - then: number; - startTime: number; - frameCount = 0; - tickTimer = 0; - clientTickTimer = 0; - - clientTickHandle: ReturnType | null = null; - - addRegion(region: Region) { - this.regions.push(region); - } - - startTicking() { - this.isPaused = false; - if (this.deltaTimeSincePause === -1) { - this.tickTimer = window.performance.now(); - this.then = window.performance.now(); - } else { - this.then = window.performance.now() - this.deltaTimeSincePause; - - this.tickTimer = window.performance.now() - this.deltaTimeSinceLastTick; - - this.deltaTimeSincePause = -1; - } - ControlPanelController.controller.onWorldTick(); - this.browserLoop(window.performance.now()); - this.clientTickHandle = setInterval(() => this.doClientTick(), CLIENT_TICK_MS); - } - - stopTicking() { - this.deltaTimeSincePause = window.performance.now() - this.then; - this.deltaTimeSinceLastTick = window.performance.now() - this.tickTimer; - this.isPaused = true; - clearInterval(this.clientTickHandle); - this.clientTickHandle = null; - } - - doClientTick() { - const now = window.performance.now(); - const clientTickElapsed = now - this.clientTickTimer; - // client tick every 20ms, doing multiple if missed - const tickPercent = (now - this.tickTimer) / Settings.tickMs; - const clientTicksElapsed = Math.min(50, Math.max(1, Math.floor(clientTickElapsed / CLIENT_TICK_MS))); - for (let i = 0; i < clientTicksElapsed; i++) { - this.tickClient(tickPercent); - this.clientTickTimer = now; - } - } - - browserLoop(now: number) { - window.requestAnimationFrame(this.browserLoop.bind(this)); - if (this.isPaused) { - return; - } - const elapsed = now - this.then; - const tickElapsed = now - this.tickTimer; - if (tickElapsed >= 600) { - this.tickTimer = now; - if (this.getReadyTimer > 0) { - this.getReadyTimer--; - } - this.tickWorld(); - } - this.tickPercent = (window.performance.now() - this.tickTimer) / Settings.tickMs; - - if (elapsed > this.fpsInterval) { - this.then = now - (elapsed % this.fpsInterval); - Viewport.viewport.draw(this); - this.frameCount++; - } - } - - tickWorld(n = 1) { - this.globalTickCounter++; - InputController.controller.onWorldTick(); - ControlPanelController.controller.onWorldTick(); - this.regions.forEach((region: Region) => this.tickRegion(region)); - - if (n > 1) { - return this.tickWorld(n - 1); - } - } - - tickClient(tickPercent: number) { - this.regions.forEach((region: Region) => this.clientTick(region, tickPercent)); - } - - tickRegion(region: Region) { - Pathing.purgeTileCache(); - - if (Settings.metronome) { - new Audio(MetronomeSound).play(); - } - - // TODO: Clean up this since its now region based - if (region.newMobs.length) { - region.mobs.unshift(...region.newMobs); - region.newMobs = []; - } - - region.players.forEach((player: Player) => player.pretick()); - - region.entities.forEach((entity) => entity.tick()); - - if (this.getReadyTimer == 0) { - region.mobs.forEach((mob) => { - mob.movementStep(); - }); - region.mobs.forEach((mob) => mob.attackStep()); - - region.newMobs.forEach((mob) => { - mob.movementStep(); - }); - region.newMobs.forEach((mob) => mob.attackStep()); - } - - DelayedAction.afterNpcTick(); - - region.projectiles = filter( - region.projectiles, - (projectile: Projectile) => !projectile.shouldDestroy(), - ); - region.projectiles.forEach((projectile: Projectile) => { - projectile.onTick(); - - if (projectile.remainingDelay === 0) { - projectile.beforeHit(); - } - }); - - region.players.forEach((player: Player) => { - player.movementStep(); - if (this.getReadyTimer <= 0) { - player.attackStep(); - } - }); - - region.midTick(); - DelayedAction.tick(); - XpDropController.controller.tick(); - Viewport.viewport.tick(); - - region.postTick(); - - // Safely remove the dead stuff from the world. If we do it while iterating we can cause ticks to be stole'd - const deadPlayers = region.players.filter((player) => player.dying === 0); - const deadMobs = region.mobs.filter((mob) => mob.dying === 0); - const deadEntities = region.entities.filter((entity) => entity.dying === 0); - deadPlayers.forEach((player) => region.removePlayer(player)); - deadMobs.forEach((mob) => region.removeMob(mob)); - deadEntities.forEach((entity) => region.removeEntity(entity)); - } - - clientTick(region: Region, tickPercent: number) { - region.players.forEach((player: Player) => { - player.clientTick(tickPercent); - }); - } -} diff --git a/src/sdk/XpDrop.ts b/src/sdk/XpDrop.ts deleted file mode 100644 index b578edcb..00000000 --- a/src/sdk/XpDrop.ts +++ /dev/null @@ -1,12 +0,0 @@ -export interface XpDropAggregator { - [key: string]: number; -} - -export class XpDrop { - skill: string; - xp: number; - constructor(skill: string, xp: number) { - this.skill = skill; - this.xp = xp; - } -} diff --git a/src/sdk/XpDropController.ts b/src/sdk/XpDropController.ts deleted file mode 100644 index d9fe54a4..00000000 --- a/src/sdk/XpDropController.ts +++ /dev/null @@ -1,147 +0,0 @@ -import AttackXpDropImage from "../assets/images/xpdrops/attack.png"; -import StrengthXpDropImage from "../assets/images/xpdrops/strength.png"; -import DefenceXpDropImage from "../assets/images/xpdrops/defence.png"; -import RangeXpDropImage from "../assets/images/xpdrops/range.png"; -import MagicXpDropImage from "../assets/images/xpdrops/magic.png"; -import HitpointXpDropImage from "../assets/images/xpdrops/hitpoint.png"; -import { find } from "lodash"; -import { XpDrop } from "./XpDrop"; -import { ImageLoader } from "./utils/ImageLoader"; -import { Settings } from "./Settings"; - -/* eslint-disable @typescript-eslint/no-empty-interface */ - -interface SkillTypes { - type: string; - imgSrc: string; - image?: HTMLImageElement; -} - -interface Empty { - // Empty interface -} - -export class XpDropController { - static controller = new XpDropController(); - static outlineColor = "#3A3021"; - static inlineColor = "#5D5344"; - static fillColor = "#5D534473"; // guess ATM - - canvas: OffscreenCanvas = new OffscreenCanvas(110, 200); - ctx: OffscreenCanvasRenderingContext2D; - drops: XpDrop[] | Empty[]; - lastDropSkill?: string; - timeout: NodeJS.Timeout; - - static skills: SkillTypes[] = [ - { type: "attack", imgSrc: AttackXpDropImage, image: null }, - { type: "strength", imgSrc: StrengthXpDropImage, image: null }, - { type: "defence", imgSrc: DefenceXpDropImage, image: null }, - { type: "range", imgSrc: RangeXpDropImage, image: null }, - { type: "magic", imgSrc: MagicXpDropImage, image: null }, - { type: "hitpoint", imgSrc: HitpointXpDropImage, image: null }, - ]; - - constructor() { - this.ctx = this.canvas.getContext("2d"); - - this.drops = [{ abc: "asdf" }, {}, {}, {}]; - this.lastDropSkill = null; - this.startupTimeout(); - } - - startupTimeout() { - if (this.timeout) { - clearTimeout(this.timeout); - } - this.timeout = setTimeout(() => { - this.lastDropSkill = null; - }, 1000 * 16); // Not sure if 16 seconds is correct but good enough for now - } - - registerXpDrop(drop: XpDrop) { - this.drops.push(drop); - if (drop.skill) { - this.lastDropSkill = drop.skill; - } - } - - tick() { - this.drops.shift(); - if (this.drops.length < 4) { - this.drops.push({} as XpDrop); // TODO: This is bad - } - } - - draw(destinationCanvas: CanvasRenderingContext2D, x: number, y: number, tickPercent: number) { - this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); - if (!Settings.displayXpDrops) { - return; - } - const scale = Settings.maxUiScale; - this.canvas.width = 110 * scale * 2; - this.canvas.height = 200 * scale * 2; - - const skillInfo = find(XpDropController.skills, { type: this.lastDropSkill }); - - if (skillInfo && skillInfo.type) { - // Draw overall XP box at top - this.ctx.lineWidth = 1; - this.ctx.strokeStyle = XpDropController.outlineColor; - this.ctx.strokeRect(0, 0, 110 * scale, 42 * scale); - this.ctx.strokeStyle = XpDropController.inlineColor; - this.ctx.strokeRect(1 * scale, 1 * scale, 109 * scale, 41 * scale); - this.ctx.strokeRect(1 * scale, 30 * scale, 108 * scale, 11 * scale); - this.ctx.fillStyle = XpDropController.fillColor; - this.ctx.fillRect(2 * scale, 2 * scale, 108 * scale, 40 * scale); - this.ctx.fillStyle = "#000000"; - this.ctx.fillRect(2 * scale, 31 * scale, 106 * scale, 9 * scale); - this.ctx.fillStyle = "#00BF00"; - this.ctx.fillRect(3 * scale, 32 * scale, 90 * scale, 7 * scale); - - this.ctx.fillStyle = "#FFFFFF"; - this.ctx.font = `${Math.floor(16 * scale)}px Stats_11`; - this.ctx.textAlign = "right"; - - this.ctx.drawImage(skillInfo.image, 4 * scale, 2 * scale, 26 * scale, 26 * scale); - this.ctx.fillStyle = "#000000"; - - this.ctx.fillText("200,000,000", 106 * scale, 21 * scale); - this.ctx.fillStyle = "#FFFFFF"; - this.ctx.fillText("200,000,000", 105 * scale, 20 * scale); - } - - const xpDropYOffset = 85; - const dropFontSize = Math.floor(16 * (Settings.maxUiScale * 2)); - this.ctx.fillStyle = "#FFFFFF"; - this.ctx.font = `${dropFontSize}px Stats_11`; - this.ctx.textAlign = "right"; - this.drops.forEach((drop, index) => { - const textSize = dropFontSize + 4; - if (!drop.skill) { - return; - } - const skill = drop.skill; - - const skillInfo = find(XpDropController.skills, { type: skill }); - if (skillInfo.image) { - this.ctx.drawImage( - skillInfo.image, - 110 - this.ctx.measureText(String(drop.xp)).width - 20, - (index - tickPercent) * textSize - 13 + xpDropYOffset, - 16, - 16, - ), - skillInfo.image.width * Settings.maxUiScale * 2, - skillInfo.image.height * Settings.maxUiScale * 2; - } - - this.ctx.fillText(String(drop.xp), 110, (index - tickPercent) * textSize + xpDropYOffset); - }); - destinationCanvas.drawImage(this.canvas, x, y); - } -} - -XpDropController.skills.forEach((skill) => { - skill.image = ImageLoader.createImage(skill.imgSrc); -}); diff --git a/src/sdk/__mocks__/ControlPanelController.ts b/src/sdk/__mocks__/ControlPanelController.ts deleted file mode 100644 index 55990c39..00000000 --- a/src/sdk/__mocks__/ControlPanelController.ts +++ /dev/null @@ -1,7 +0,0 @@ -export const ControlPanelController = { - controller: { - onWorldTick: () => { - // - } - }, -}; diff --git a/src/sdk/__mocks__/MapController.ts b/src/sdk/__mocks__/MapController.ts deleted file mode 100644 index e5679494..00000000 --- a/src/sdk/__mocks__/MapController.ts +++ /dev/null @@ -1,5 +0,0 @@ -export const MapController = { - controller: { - updateOrbsMask: () => true, - }, -}; diff --git a/src/sdk/__mocks__/XpDropController.ts b/src/sdk/__mocks__/XpDropController.ts deleted file mode 100644 index 88ae10d6..00000000 --- a/src/sdk/__mocks__/XpDropController.ts +++ /dev/null @@ -1,6 +0,0 @@ -export const XpDropController = { - controller: { - tick: () => true, - registerXpDrop: () => true, - }, -}; diff --git a/src/sdk/controlpanels/AccountControls.ts b/src/sdk/controlpanels/AccountControls.ts deleted file mode 100644 index 4c0e0fb2..00000000 --- a/src/sdk/controlpanels/AccountControls.ts +++ /dev/null @@ -1,13 +0,0 @@ -import InventoryPanel from "../../assets/images/panels/inventory.png"; -import AccountTab from "../../assets/images/tabs/account.png"; -import { BaseControls } from "./BaseControls"; - -export class AccountControls extends BaseControls { - get panelImageReference() { - return InventoryPanel; - } - - get tabImageReference() { - return AccountTab; - } -} diff --git a/src/sdk/controlpanels/AncientsSpellbookControls.ts b/src/sdk/controlpanels/AncientsSpellbookControls.ts deleted file mode 100644 index 194d5677..00000000 --- a/src/sdk/controlpanels/AncientsSpellbookControls.ts +++ /dev/null @@ -1,55 +0,0 @@ -import StandardSpellbookTab from "../../assets/images/tabs/standard_spellbook.png"; -import AncientsPanel from "../../assets/images/panels/ancients.png"; -import { BaseControls } from "./BaseControls"; -import { IceBarrageSpell } from "../weapons/IceBarrageSpell"; -import { BloodBarrageSpell } from "../weapons/BloodBarrageSpell"; -import { Settings } from "../Settings"; -import { ControlPanelController } from "../ControlPanelController"; -import { ItemName } from "../ItemName"; -import { Viewport } from "../Viewport"; - -export class AncientsSpellbookControls extends BaseControls { - get panelImageReference() { - return AncientsPanel; - } - - get tabImageReference() { - // Need to extract the other images later - return StandardSpellbookTab; - } - - get keyBinding() { - return Settings.spellbook_key; - } - - get isAvailable(): boolean { - return true; - } - - panelClickDown(x: number, y: number) { - Viewport.viewport.player.manualSpellCastSelection = null; - const scale = Settings.controlPanelScale; - - x = x / scale; - y = y / scale; - if (x >= 21 && x <= 42 && y >= 229 && y <= 249) { - Viewport.viewport.player.manualSpellCastSelection = new IceBarrageSpell(); - } else if (x >= 166 && x <= 187 && y >= 194 && y <= 214) { - Viewport.viewport.player.manualSpellCastSelection = new BloodBarrageSpell(); - } - } - - draw(context, ctrl: ControlPanelController, x: number, y: number) { - super.draw(context, ctrl, x, y); - Viewport.viewport.context.fillStyle = "#D1BB7773"; - - const scale = Settings.controlPanelScale; - if (Viewport.viewport.player.manualSpellCastSelection) { - if (Viewport.viewport.player.manualSpellCastSelection.itemName === ItemName.ICE_BARRAGE) { - Viewport.viewport.context.fillRect(x + 20 * scale, y + 225 * scale, 21 * scale, 21 * scale); - } else if (Viewport.viewport.player.manualSpellCastSelection.itemName === ItemName.BLOOD_BARRAGE) { - Viewport.viewport.context.fillRect(x + 164 * scale, y + 188 * scale, 21 * scale, 21 * scale); - } - } - } -} diff --git a/src/sdk/controlpanels/BaseControls.ts b/src/sdk/controlpanels/BaseControls.ts deleted file mode 100644 index e339a99c..00000000 --- a/src/sdk/controlpanels/BaseControls.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { ControlPanelController } from "../ControlPanelController"; -import { ImageLoader } from "../utils/ImageLoader"; -import { Settings } from "../Settings"; -import { Viewport } from "../Viewport"; - -export class BaseControls { - panelImage: HTMLImageElement = ImageLoader.createImage(this.panelImageReference); - tabImage: HTMLImageElement = ImageLoader.createImage(this.tabImageReference); - selected = false; - - get keyBinding(): string { - return ""; - } - - get isAvailable(): boolean { - return false; - } - - get panelImageReference(): string { - return ""; - } - - get tabImageReference(): string { - return ""; - } - - get appearsOnLeftInMobile(): boolean { - return true; - } - - cursorMovedto(x: number, y: number) { - // Override me - } - - panelRightClick(x: number, y: number) { - // Override me - } - - panelClickDown(x: number, y: number) { - // - } - panelClickUp(x: number, y: number) { - // - } - - onWorldTick() { - // Override me - } - - draw(context: CanvasRenderingContext2D, ctrl: ControlPanelController, x: number, y: number) { - const scale = Settings.controlPanelScale; - if (this.panelImage) { - context.drawImage(this.panelImage, x, y, 204 * scale, 275 * scale); - } - } -} diff --git a/src/sdk/controlpanels/ClanChatControls.ts b/src/sdk/controlpanels/ClanChatControls.ts deleted file mode 100644 index 7e851695..00000000 --- a/src/sdk/controlpanels/ClanChatControls.ts +++ /dev/null @@ -1,13 +0,0 @@ -import InventoryPanel from "../../assets/images/panels/inventory.png"; -import ClanChatTab from "../../assets/images/tabs/clanchat.png"; -import { BaseControls } from "./BaseControls"; - -export class ClanChatControls extends BaseControls { - get panelImageReference() { - return InventoryPanel; - } - - get tabImageReference() { - return ClanChatTab; - } -} diff --git a/src/sdk/controlpanels/CombatControls.ts b/src/sdk/controlpanels/CombatControls.ts deleted file mode 100644 index 2adc26d5..00000000 --- a/src/sdk/controlpanels/CombatControls.ts +++ /dev/null @@ -1,221 +0,0 @@ -import InventoryPanel from "../../assets/images/panels/inventory.png"; -import CombatTab from "../../assets/images/tabs/combat.png"; -import { ControlPanelController } from "../ControlPanelController"; -import { ImageLoader } from "../utils/ImageLoader"; -import { BaseControls } from "./BaseControls"; -import SelectedCombatStyleButtonImage from "../../assets/images/attackstyles/interface/attack_style_button_highlighted.png"; -import CombatStyleButtonImage from "../../assets/images/attackstyles/interface/attack_style_button.png"; -import SelectedAutoRetaliateButtonImage from "../../assets/images/attackstyles/interface/auto_retal_button_highlighted.png"; -import AutoRetaliateButtonImage from "../../assets/images/attackstyles/interface/auto_retal_button.png"; -import SpecialAttackBarBackground from "../../assets/images/attackstyles/interface/special_attack_background.png"; -import { AttackStyle, AttackStylesController } from "../AttackStylesController"; -import { Weapon } from "../gear/Weapon"; -import { Location } from "../../sdk/Location"; -import { startCase, toLower } from "lodash"; -import { Settings } from "../Settings"; -import { Viewport } from "../Viewport"; -import { PlayerStats } from "../PlayerStats"; - -export class CombatControls extends BaseControls { - private playerStats: PlayerStats; - - selectedCombatStyleButtonImage: HTMLImageElement = ImageLoader.createImage(SelectedCombatStyleButtonImage); - combatStyleButtonImage: HTMLImageElement = ImageLoader.createImage(CombatStyleButtonImage); - autoRetailButtonImage: HTMLImageElement = ImageLoader.createImage(AutoRetaliateButtonImage); - selectedAutoRetailButtonImage: HTMLImageElement = ImageLoader.createImage(SelectedAutoRetaliateButtonImage); - specialAttackBarBackground: HTMLImageElement = ImageLoader.createImage(SpecialAttackBarBackground); - - get panelImageReference() { - return InventoryPanel; - } - - get tabImageReference() { - return CombatTab; - } - - get keyBinding() { - return Settings.combat_key; - } - - updateStats(playerStats: PlayerStats) { - this.playerStats = playerStats; - } - - panelClickDown(x: number, y: number) { - const scale = Settings.controlPanelScale; - - x = x / scale; - y = y / scale; - - const attackStyleOffsets = [ - { x: 25, y: 45 }, - { x: 105, y: 45 }, - { x: 25, y: 100 }, - { x: 105, y: 100 }, - ]; - const weapon = Viewport.viewport.player.equipment.weapon; - const attackStyles = weapon.attackStyles(); - - attackStyleOffsets.slice(0, attackStyles.length).forEach((offset: Location, index: number) => { - if (offset.x < x && x < offset.x + 70 && offset.y < y && y < offset.y + 48) { - AttackStylesController.controller.setWeaponAttackStyle(weapon, attackStyles[index]); - } - }); - - if (x > 28 && x < 175 && y > 160 && y < 200) { - Viewport.viewport.player.autoRetaliate = !Viewport.viewport.player.autoRetaliate; - } - if ( - x > 25 && - y > 210 && - x < 25 + this.specialAttackBarBackground.width && - y < 210 + this.specialAttackBarBackground.height - ) { - const canSpec = - Viewport.viewport.player.equipment.weapon && Viewport.viewport.player.equipment.weapon.hasSpecialAttack(); - if (canSpec) { - Viewport.viewport.player.useSpecialAttack = !Viewport.viewport.player.useSpecialAttack; - } - } - } - - get isAvailable(): boolean { - return true; - } - - drawAttackStyleButton( - context: CanvasRenderingContext2D, - weapon: Weapon, - attackStyle: AttackStyle, - attackStyleImage: HTMLImageElement, - x: number, - y: number, - ) { - const scale = Settings.controlPanelScale; - const currentAttackStyle = weapon.attackStyle(); - - const currentAttackStyleImage = - currentAttackStyle === attackStyle ? this.selectedCombatStyleButtonImage : this.combatStyleButtonImage; - context.drawImage( - currentAttackStyleImage, - x, - y, - currentAttackStyleImage.width * scale, - currentAttackStyleImage.height * scale, - ); - - context.drawImage( - attackStyleImage, - x + (35 - Math.floor(attackStyleImage.width / 2)) * scale, - y + 5 * scale, - attackStyleImage.width * scale, - attackStyleImage.height * scale, - ); - - context.font = 16 * scale + "px Stats_11"; - context.textAlign = "center"; - - context.fillStyle = "#000"; - context.fillText(startCase(toLower(attackStyle)), x + 36 * scale, y + 41 * scale); - - context.fillStyle = "#FF9700"; - context.fillText(startCase(toLower(attackStyle)), x + 35 * scale, y + 40 * scale); - } - - draw(context: CanvasRenderingContext2D, ctrl: ControlPanelController, x: number, y: number) { - super.draw(context, ctrl, x, y); - - const scale = Settings.controlPanelScale; - - const weapon = Viewport.viewport.player.equipment.weapon; - - if (!weapon) { - return; - } - - context.font = 21 * scale + "px Stats_11"; - context.textAlign = "center"; - - context.fillStyle = "#000"; - context.fillText(startCase(toLower(weapon.itemName)), x + 101 * scale, y + 31 * scale); - - context.fillStyle = "#FF9700"; - context.fillText(startCase(toLower(weapon.itemName)), x + 100 * scale, y + 30 * scale); - - const attackStyleOffsets = [ - { x: 25, y: 45 }, - { x: 105, y: 45 }, - { x: 25, y: 100 }, - { x: 105, y: 100 }, - ]; - - const attackStyles = weapon.attackStyles(); - - const imageMap = AttackStylesController.attackStyleImageMap[weapon.attackStyleCategory()]; - if (imageMap) { - attackStyles.forEach((style: AttackStyle, index: number) => { - const offsets = attackStyleOffsets[index]; - - const attackStyleImage = imageMap[weapon.attackStyles()[index]]; - if (attackStyleImage) { - this.drawAttackStyleButton( - context, - weapon, - weapon.attackStyles()[index], - attackStyleImage, - x + offsets.x * scale, - y + offsets.y * scale, - ); - } - }); - } - - const autoRetailateImage = Viewport.viewport.player.autoRetaliate - ? this.selectedAutoRetailButtonImage - : this.autoRetailButtonImage; - context.drawImage( - autoRetailateImage, - x + 25 * scale, - y + 155 * scale, - autoRetailateImage.width * scale, - autoRetailateImage.height * scale, - ); - - context.font = 19 * scale + "px Stats_11"; - context.textAlign = "center"; - - context.fillStyle = "#000"; - context.fillText("Auto Retaliate", x + 116 * scale, y + 183 * scale); - - context.fillStyle = "#FF9700"; - context.fillText("Auto Retaliate", x + 115 * scale, y + 182 * scale); - - const canSpec = - Viewport.viewport.player.equipment.weapon && Viewport.viewport.player.equipment.weapon.hasSpecialAttack(); - const isUsingSpec = canSpec && Viewport.viewport.player.useSpecialAttack; - - if (canSpec) { - const specAmount = (Viewport.viewport.player?.currentStats.specialAttack ?? 0.0) / 100.0; - context.drawImage( - this.specialAttackBarBackground, - x + 25 * scale, - y + 210 * scale, - this.specialAttackBarBackground.width * scale, - this.specialAttackBarBackground.height * scale, - ); - - context.fillStyle = "#730606"; - context.fillRect(x + 28 * scale, y + 216 * scale, 144 * scale, 14 * scale); - context.fillStyle = "#397d3b"; - context.fillRect(x + 28 * scale, y + 216 * scale, 144 * scale * specAmount, 14 * scale); - context.fillStyle = "#000000"; - context.globalAlpha = 0.5; - context.strokeRect(x + 28 * scale, y + 216 * scale, 144 * scale, 14 * scale); - context.globalAlpha = 1; - context.font = `${16 * scale}px Stats_11`; - context.textAlign = "center"; - context.fillStyle = isUsingSpec ? "#FFFF00" : "#000000"; - context.fillText(`Special Attack: ${Math.round(specAmount * 100)}%`, x + 100 * scale, y + 227 * scale); - } - } -} diff --git a/src/sdk/controlpanels/EmotesControls.ts b/src/sdk/controlpanels/EmotesControls.ts deleted file mode 100644 index 8d05be48..00000000 --- a/src/sdk/controlpanels/EmotesControls.ts +++ /dev/null @@ -1,13 +0,0 @@ -import InventoryPanel from "../../assets/images/panels/inventory.png"; -import EmotesTab from "../../assets/images/tabs/emotes.png"; -import { BaseControls } from "./BaseControls"; - -export class EmotesControls extends BaseControls { - get panelImageReference() { - return InventoryPanel; - } - - get tabImageReference() { - return EmotesTab; - } -} diff --git a/src/sdk/controlpanels/EmptyControls.ts b/src/sdk/controlpanels/EmptyControls.ts deleted file mode 100644 index 0ad794ba..00000000 --- a/src/sdk/controlpanels/EmptyControls.ts +++ /dev/null @@ -1,13 +0,0 @@ -import InventoryPanel from "../../assets/images/panels/inventory.png"; -import EmptyTab from "../../assets/images/tabs/empty.png"; -import { BaseControls } from "./BaseControls"; - -export class EmptyControls extends BaseControls { - get panelImageReference() { - return InventoryPanel; - } - - get tabImageReference() { - return EmptyTab; - } -} diff --git a/src/sdk/controlpanels/EquipmentControls.ts b/src/sdk/controlpanels/EquipmentControls.ts deleted file mode 100644 index 1309b781..00000000 --- a/src/sdk/controlpanels/EquipmentControls.ts +++ /dev/null @@ -1,164 +0,0 @@ -import EquipmentPanel from "../../assets/images/panels/equipment.png"; -import EquipmentTab from "../../assets/images/tabs/equipment.png"; -import { BaseControls } from "./BaseControls"; -import UsedSpotBackground from "../../assets/images/interface/equipment_spot_used.png"; -import { Settings } from "../Settings"; -import { ControlPanelController } from "../ControlPanelController"; -import { ImageLoader } from "../utils/ImageLoader"; -import { Viewport } from "../Viewport"; -import { EQUIPMENT_TYPE_TO_SLOT, EquipmentTypes } from "../Equipment"; -import { InputController } from "../Input"; - -export class EquipmentControls extends BaseControls { - static instance: EquipmentControls | null = null; - - constructor() { - super(); - EquipmentControls.instance = this; - } - - usedSpotBackground: HTMLImageElement = ImageLoader.createImage(UsedSpotBackground); - - private DEFAULT_EQUIPMENT_INTERACTIONS = [(slot) => this.unequipItem(slot)]; - - equipmentInteractions: ((slot: EquipmentTypes) => void)[] = [...this.DEFAULT_EQUIPMENT_INTERACTIONS]; - - private clickedSlot: EquipmentTypes = null; - - resetEquipmentInteractions() { - this.equipmentInteractions = [...this.DEFAULT_EQUIPMENT_INTERACTIONS]; - } - - addEquipmentInteraction(interaction: (slot: EquipmentTypes) => void) { - this.equipmentInteractions.unshift(interaction); - } - - get panelImageReference() { - return EquipmentPanel; - } - - get tabImageReference() { - return EquipmentTab; - } - - get keyBinding() { - return Settings.equipment_key; - } - - override panelClickDown(x: number, y: number) { - const scale = Settings.controlPanelScale; - x = x / scale; - y = y / scale; - let clicked: EquipmentTypes | null = null; - - if (x > 84 && y > 11 && x < 84 + 36 && y < 11 + 36) { - // helmet - clicked = EquipmentTypes.HELMET; - } else if (x > 43 && y > 50 && x < 43 + 36 && y < 50 + 36) { - // cape - clicked = EquipmentTypes.BACK; - } else if (x > 84 && y > 50 && x < 84 + 36 && y < 50 + 36) { - // necklace - clicked = EquipmentTypes.NECK; - } else if (x > 124 && y > 50 && x < 124 + 36 && y < 50 + 36) { - // ammo - clicked = EquipmentTypes.AMMO; - } else if (x > 28 && y > 89 && x < 28 + 36 && y < 89 + 36) { - // weapon - clicked = EquipmentTypes.WEAPON; - } else if (x > 84 && y > 89 && x < 84 + 36 && y < 89 + 36) { - // chest - clicked = EquipmentTypes.CHEST; - } else if (x > 140 && y > 89 && x < 140 + 36 && y < 89 + 36) { - // offhand - clicked = EquipmentTypes.OFFHAND; - } else if (x > 84 && y > 129 && x < 84 + 36 && y < 129 + 36) { - // legs - clicked = EquipmentTypes.LEGS; - } else if (x > 28 && y > 169 && x < 28 + 36 && y < 169 + 36) { - // gloves - clicked = EquipmentTypes.GLOVES; - } else if (x > 84 && y > 169 && x < 84 + 36 && y < 169 + 36) { - // feet - clicked = EquipmentTypes.FEET; - } else if (x > 140 && y > 169 && x < 140 + 36 && y < 169 + 36) { - // ring - clicked = EquipmentTypes.RING; - } - this.clickedSlot = clicked; - if (clicked) { - InputController.controller.queueAction(() => { - this.equipmentInteractions[0](clicked); - }); - } - } - - override panelClickUp() { - this.clickedSlot = null; - } - - private unequipItem(clicked: EquipmentTypes) { - const equipmentSlot = EQUIPMENT_TYPE_TO_SLOT[clicked]; - Viewport.viewport.player.equipment[equipmentSlot]?.unequip(Viewport.viewport.player); - } - - get isAvailable(): boolean { - return true; - } - - get appearsOnLeftInMobile(): boolean { - return false; - } - - drawEquipment( - context: OffscreenCanvasRenderingContext2D, - x: number, - y: number, - slotX: number, - slotY: number, - scale: number, - slot: EquipmentTypes, - ) { - const equipmentSlot = EQUIPMENT_TYPE_TO_SLOT[slot]; - if (Viewport.viewport.player.equipment[equipmentSlot]) { - context.drawImage( - this.usedSpotBackground, - x + slotX * scale, - y + slotY * scale, - this.usedSpotBackground.width * scale, - this.usedSpotBackground.height * scale, - ); - if (this.clickedSlot === slot) { - context.globalAlpha = 0.5; - } else { - context.globalAlpha = 1.0; - } - const sprite = Viewport.viewport.player.equipment[equipmentSlot].inventorySprite; - Viewport.viewport.context.drawImage( - sprite, - x + (slotX + 18 - Math.floor(sprite.width / 2)) * scale, - y + (slotY + 18 - Math.floor(sprite.height / 2)) * scale, - sprite.width * scale, - sprite.height * scale, - ); - context.globalAlpha = 1.0; - } - } - - draw(context, ctrl: ControlPanelController, x: number, y: number) { - super.draw(context, ctrl, x, y); - const scale = Settings.controlPanelScale; - - this.drawEquipment(context, x, y, 84, 11, scale, EquipmentTypes.HELMET); - this.drawEquipment(context, x, y, 43, 50, scale, EquipmentTypes.BACK); - this.drawEquipment(context, x, y, 84, 50, scale, EquipmentTypes.NECK); - this.drawEquipment(context, x, y, 124, 50, scale, EquipmentTypes.AMMO); - this.drawEquipment(context, x, y, 28, 89, scale, EquipmentTypes.WEAPON); - this.drawEquipment(context, x, y, 84, 89, scale, EquipmentTypes.CHEST); - this.drawEquipment(context, x, y, 140, 89, scale, EquipmentTypes.OFFHAND); - this.drawEquipment(context, x, y, 84, 129, scale, EquipmentTypes.LEGS); - this.drawEquipment(context, x, y, 28, 169, scale, EquipmentTypes.GLOVES); - this.drawEquipment(context, x, y, 84, 169, scale, EquipmentTypes.FEET); - this.drawEquipment(context, x, y, 140, 169, scale, EquipmentTypes.RING); - } -} diff --git a/src/sdk/controlpanels/FriendsControls.ts b/src/sdk/controlpanels/FriendsControls.ts deleted file mode 100644 index 19c50f24..00000000 --- a/src/sdk/controlpanels/FriendsControls.ts +++ /dev/null @@ -1,13 +0,0 @@ -import InventoryPanel from "../../assets/images/panels/inventory.png"; -import FriendsTab from "../../assets/images/tabs/friends.png"; -import { BaseControls } from "./BaseControls"; - -export class FriendsControls extends BaseControls { - get panelImageReference() { - return InventoryPanel; - } - - get tabImageReference() { - return FriendsTab; - } -} diff --git a/src/sdk/controlpanels/InventoryControls.ts b/src/sdk/controlpanels/InventoryControls.ts deleted file mode 100644 index e328de01..00000000 --- a/src/sdk/controlpanels/InventoryControls.ts +++ /dev/null @@ -1,219 +0,0 @@ -import { first, filter } from "lodash"; -import InventoryPanel from "../../assets/images/panels/inventory.png"; -import InventoryTab from "../../assets/images/tabs/inventory.png"; -import { Pathing } from "../Pathing"; -import { BaseControls } from "./BaseControls"; -import { Settings } from "../Settings"; -import { Item } from "../Item"; -import { ControlPanelController } from "../ControlPanelController"; -import { Location } from "../../sdk/Location"; -import { Collision } from "../Collision"; -import { MenuOption } from "../ContextMenu"; -import { MapController } from "../MapController"; -import { Viewport } from "../Viewport"; -import { InputController } from "../Input"; -/* eslint-disable @typescript-eslint/no-explicit-any */ - -export class InventoryControls extends BaseControls { - clickedDownItem: Item = null; - clickedDownLocation: Location = null; - cursorLocation: Location = null; - // this is the visual representation of the inventory, which updates instantly when items are moved but is refreshed - // every tick - inventoryCache: Item[] = []; - - get panelImageReference() { - return InventoryPanel; - } - - get tabImageReference() { - return InventoryTab; - } - - get keyBinding() { - return Settings.inventory_key; - } - - cursorMovedto(x: number, y: number) { - this.cursorLocation = { x, y }; - } - - get isAvailable(): boolean { - return true; - } - - get appearsOnLeftInMobile(): boolean { - return false; - } - - override onWorldTick() { - this.inventoryCache = [...Viewport.viewport.player.inventory]; - } - - panelRightClick(x: number, y: number) { - const scale = Settings.controlPanelScale; - - let menuOptions: MenuOption[] = []; - // mobs.forEach((mob) => { - // menuOptions = menuOptions.concat(mob.contextActions(x, y)) - // }) - - const clickedItem = first( - filter(Viewport.viewport.player.inventory, (inventoryItem: Item, index: number) => { - if (!inventoryItem) { - return; - } - const x2 = index % 4; - const y2 = Math.floor(index / 4); - const itemX = 20 + x2 * 43; - const itemY = 17 + (y2 + 1) * 35; - return Collision.collisionMath(x, y, 1, itemX * scale, itemY * scale, 32 * scale); - }), - ) as Item; - - if (clickedItem) { - menuOptions = menuOptions.concat(clickedItem.contextActions(Viewport.viewport.player)); - } - - Viewport.viewport.contextMenu.setMenuOptions(menuOptions); - Viewport.viewport.contextMenu.setActive(); - } - - panelClickUp(x: number, y: number) { - if (!this.clickedDownItem) { - return; - } - const scale = Settings.controlPanelScale; - - const sanitizedInventory = Viewport.viewport.player.inventory.map((item: Item, index: number) => { - if (item) { - return item; - } - return { - inventoryPosition: () => index, - isPlaceholder: true, - }; - }); - const clickedItem = first( - filter(sanitizedInventory, (inventoryItem: Item, index: number) => { - if (!inventoryItem) { - return; - } - const x2 = index % 4; - const y2 = Math.floor(index / 4); - const itemX = 20 + x2 * 43; - const itemY = 17 + (y2 + 1) * 35; - return Collision.collisionMath(x, y, 1, itemX * scale, itemY * scale, 32 * scale); - }), - ) as Item; - - const isPlaceholder: boolean = clickedItem && !!(clickedItem as any).isPlaceholder; - - if (!isPlaceholder && clickedItem && this.clickedDownItem === clickedItem) { - if (clickedItem.hasInventoryLeftClick) { - InputController.controller.queueAction(() => clickedItem.inventoryLeftClick(Viewport.viewport.player)); - MapController.controller.updateOrbsMask(null, null); - } else { - clickedItem.selected = true; - } - } else if (!isPlaceholder && clickedItem) { - const theItemWereReplacing = clickedItem; - const theItemWereReplacingPosition = clickedItem.inventoryPosition(Viewport.viewport.player); - const thisPosition = this.clickedDownItem.inventoryPosition(Viewport.viewport.player); - // update the local cache immediately, but the real position updates upon server tick - this.inventoryCache[theItemWereReplacingPosition] = this.clickedDownItem; - this.inventoryCache[thisPosition] = theItemWereReplacing; - InputController.controller.queueAction(() => { - Viewport.viewport.player.swapItemPositions(theItemWereReplacingPosition, thisPosition); - }); - } else if (clickedItem) { - const thisPosition = this.clickedDownItem.inventoryPosition(Viewport.viewport.player); - const clickedPosition = clickedItem.inventoryPosition(Viewport.viewport.player); - this.inventoryCache[clickedPosition] = this.clickedDownItem; - this.inventoryCache[thisPosition] = null; - InputController.controller.queueAction(() => { - Viewport.viewport.player.swapItemPositions(clickedPosition, thisPosition); - }); - } - this.clickedDownItem = null; - this.cursorLocation = null; - } - - panelClickDown(x: number, y: number) { - this.cursorLocation = { x, y }; - this.clickedDownLocation = { x, y }; - const scale = Settings.controlPanelScale; - - const clickedItem = first( - filter(Viewport.viewport.player.inventory, (inventoryItem: Item, index: number) => { - if (!inventoryItem) { - return; - } - const x2 = index % 4; - const y2 = Math.floor(index / 4); - const itemX = 20 + x2 * 43; - const itemY = 17 + (y2 + 1) * 35; - return Collision.collisionMath(x, y, 1, itemX * scale, itemY * scale, 32 * scale); - }), - ) as Item; - - Viewport.viewport.player.inventory.forEach((inventoryItem) => inventoryItem && (inventoryItem.selected = false)); - - if (clickedItem) { - this.clickedDownItem = clickedItem; - } - } - - draw(context, ctrl: ControlPanelController, x: number, y: number) { - super.draw(context, ctrl, x, y); - - const scale = Settings.controlPanelScale; - this.inventoryCache.forEach((inventoryItem, index) => { - const x2 = index % 4; - const y2 = Math.floor(index / 4); - - const itemX = x + (20 + x2 * 43) * scale; - const itemY = y + (17 + y2 * 35) * scale; - - if (inventoryItem !== null) { - context.fillStyle = "#ffffff22"; - // Viewport.viewport.context.fillRect(itemX, itemY, 32, 32) - const sprite = inventoryItem.inventorySprite; - - const xOff = Math.floor((32 - sprite.width) / 2); - const yOff = Math.floor((32 - sprite.height) / 2); - if (inventoryItem === this.clickedDownItem) { - context.globalAlpha = 0.4; - if ( - Pathing.dist( - this.cursorLocation.x, - this.cursorLocation.y, - this.clickedDownLocation.x, - this.clickedDownLocation.y, - ) > 5 - ) { - context.drawImage( - sprite, - x + this.cursorLocation.x - (sprite.width * scale) / 2, - y + this.cursorLocation.y - (sprite.height * scale) / 2, - sprite.width * scale, - sprite.height * scale, - ); - } else { - context.drawImage(sprite, itemX + xOff, itemY + yOff, sprite.width * scale, sprite.height * scale); - } - context.globalAlpha = 1; - } else { - context.drawImage(sprite, itemX + xOff, itemY + yOff, sprite.width * scale, sprite.height * scale); - } - - if (inventoryItem.selected) { - context.beginPath(); - context.fillStyle = "#D1BB7773"; - context.arc(itemX + 15 * scale, itemY + 17 * scale, 16 * scale, 0, 2 * Math.PI); - context.fill(); - } - } - }); - } -} diff --git a/src/sdk/controlpanels/MusicControls.ts b/src/sdk/controlpanels/MusicControls.ts deleted file mode 100644 index 6a64ae94..00000000 --- a/src/sdk/controlpanels/MusicControls.ts +++ /dev/null @@ -1,13 +0,0 @@ -import InventoryPanel from "../../assets/images/panels/inventory.png"; -import MusicTab from "../../assets/images/tabs/music.png"; -import { BaseControls } from "./BaseControls"; - -export class MusicControls extends BaseControls { - get panelImageReference() { - return InventoryPanel; - } - - get tabImageReference() { - return MusicTab; - } -} diff --git a/src/sdk/controlpanels/PrayerControls.ts b/src/sdk/controlpanels/PrayerControls.ts deleted file mode 100644 index 2bb4a76c..00000000 --- a/src/sdk/controlpanels/PrayerControls.ts +++ /dev/null @@ -1,100 +0,0 @@ -import PrayerPanel from "../../assets/images/panels/prayer.png"; -import PrayerTab from "../../assets/images/tabs/prayer.png"; -import { BaseControls } from "./BaseControls"; -import { Settings } from "../Settings"; -import { ControlPanelController } from "../ControlPanelController"; -import { Viewport } from "../Viewport"; - -export class PrayerControls extends BaseControls { - hasQuickPrayersActivated = false; - - get panelImageReference() { - return PrayerPanel; - } - - get tabImageReference() { - return PrayerTab; - } - - get keyBinding() { - return Settings.prayer_key; - } - - deactivateAllPrayers() { - this.hasQuickPrayersActivated = false; - Viewport.viewport.player.prayerController.activePrayers().forEach((prayer) => prayer.deactivate()); - } - - activateQuickPrayers() { - this.hasQuickPrayersActivated = true; - - Viewport.viewport.player.prayerController.prayers.forEach((prayer) => { - prayer.deactivate(); - if (prayer.name === "Protect from Magic") { - prayer.activate(Viewport.viewport.player); - } - if (prayer.name === "Rigour") { - prayer.activate(Viewport.viewport.player); - } - }); - } - - panelClickDown(x: number, y: number) { - const scale = Settings.controlPanelScale; - - x = x / scale; - y = y / scale; - - const gridX = x - 14; - const gridY = y - 22; - - const clickedPrayer = - Viewport.viewport.player.prayerController.prayers[Math.floor(gridY / 35) * 5 + Math.floor(gridX / 35)]; - if (clickedPrayer && Viewport.viewport.player.currentStats.prayer > 0) { - clickedPrayer.toggle(Viewport.viewport.player); - - if (this.hasQuickPrayersActivated && Viewport.viewport.player.prayerController.activePrayers().length === 0) { - ControlPanelController.controls.PRAYER.hasQuickPrayersActivated = false; - } - } - } - - get isAvailable(): boolean { - return true; - } - - draw(context, ctrl: ControlPanelController, x: number, y: number) { - super.draw(context, ctrl, x, y); - const scale = Settings.controlPanelScale; - - Viewport.viewport.player.prayerController.prayers.forEach((prayer, index) => { - const x2 = index % 5; - const y2 = Math.floor(index / 5); - - if (prayer.isActive || prayer.isLit) { - Viewport.viewport.context.beginPath(); - Viewport.viewport.context.fillStyle = "#D1BB7773"; - Viewport.viewport.context.arc( - x + 10 * scale + (x2 + 0.5) * 36.8 * scale, - y + (16 + (y2 + 0.5) * 37) * scale, - 18 * scale, - 0, - 2 * Math.PI, - ); - Viewport.viewport.context.fill(); - } - if (Viewport.viewport.player.stats.prayer < prayer.levelRequirement()) { - Viewport.viewport.context.beginPath(); - Viewport.viewport.context.fillStyle = "#00000073"; - Viewport.viewport.context.arc( - x + 10 * scale + (x2 + 0.5) * 36.8 * scale, - y + (16 + (y2 + 0.5) * 37) * scale, - 18 * scale, - 0, - 2 * Math.PI, - ); - Viewport.viewport.context.fill(); - } - }); - } -} diff --git a/src/sdk/controlpanels/QuestsControls.ts b/src/sdk/controlpanels/QuestsControls.ts deleted file mode 100644 index 4a4b6a24..00000000 --- a/src/sdk/controlpanels/QuestsControls.ts +++ /dev/null @@ -1,13 +0,0 @@ -import InventoryPanel from "../../assets/images/panels/inventory.png"; -import QuestsTab from "../../assets/images/tabs/quests.png"; -import { BaseControls } from "./BaseControls"; - -export class QuestsControls extends BaseControls { - get panelImageReference() { - return InventoryPanel; - } - - get tabImageReference() { - return QuestsTab; - } -} diff --git a/src/sdk/controlpanels/SettingsControls.ts b/src/sdk/controlpanels/SettingsControls.ts deleted file mode 100644 index a7a719d4..00000000 --- a/src/sdk/controlpanels/SettingsControls.ts +++ /dev/null @@ -1,353 +0,0 @@ -import { BaseControls } from "./BaseControls"; - -import InventoryPanel from "../../assets/images/panels/inventory.png"; -import SettingsTab from "../../assets/images/tabs/settings.png"; - -import AudioButton from "../../assets/images/interface/sound_effect_volume.png"; -import AreaAudioButton from "../../assets/images/interface/area_sound_volume.png"; - -import DisabledOverlay from "../../assets/images/interface/disabled_option_overlay.png"; - -import ButtonRedUpIcon from "../../assets/images/interface/button_red_up.png"; -import ButtonGreenDownIcon from "../../assets/images/interface/button_green_down.png"; -import ButtonActiveIcon from "../../assets/images/interface/button_active.png"; -import ButtonInactiveIcon from "../../assets/images/interface/button_inactive.png"; - -import InfernoIcon from "../../assets/images/settings/inferno.png"; -import VerzikIcon from "../../assets/images/settings/verzik.png"; -import XarpusIcon from "../../assets/images/settings/xarpus.png"; - -import InventoryTab from "../../assets/images/controlTabs/inventory.png"; -import SpellbookTab from "../../assets/images/controlTabs/spellbook.png"; -import PrayerTab from "../../assets/images/controlTabs/prayer.png"; -import EquipmentTab from "../../assets/images/controlTabs/equipment.png"; -import CombatTab from "../../assets/images/controlTabs/style.png"; - -import { Settings } from "../Settings"; -import { BrowserUtils } from "../utils/BrowserUtils"; -import { ControlPanelController } from "../ControlPanelController"; -import { ImageLoader } from "../utils/ImageLoader"; -import { Viewport } from "../Viewport"; - -export class SettingsControls extends BaseControls { - get panelImageReference() { - return InventoryPanel; - } - - get tabImageReference() { - return SettingsTab; - } - - soundImage: HTMLImageElement = ImageLoader.createImage(AudioButton); - areaSoundImage: HTMLImageElement = ImageLoader.createImage(AreaAudioButton); - disabledOverlay: HTMLImageElement = ImageLoader.createImage(DisabledOverlay); - redUpImage: HTMLImageElement = ImageLoader.createImage(ButtonRedUpIcon); - greenDownImage: HTMLImageElement = ImageLoader.createImage(ButtonGreenDownIcon); - activeButtonImage: HTMLImageElement = ImageLoader.createImage(ButtonActiveIcon); - inactiveButtonImage: HTMLImageElement = ImageLoader.createImage(ButtonInactiveIcon); - infernoImage: HTMLImageElement = ImageLoader.createImage(InfernoIcon); - verzikImage: HTMLImageElement = ImageLoader.createImage(VerzikIcon); - xarpusImage: HTMLImageElement = ImageLoader.createImage(XarpusIcon); - inventoryImage: HTMLImageElement = ImageLoader.createImage(InventoryTab); - spellbookImage: HTMLImageElement = ImageLoader.createImage(SpellbookTab); - prayerImage: HTMLImageElement = ImageLoader.createImage(PrayerTab); - equipmentImage: HTMLImageElement = ImageLoader.createImage(EquipmentTab); - combatImage: HTMLImageElement = ImageLoader.createImage(CombatTab); - bindingKey?: string; - - constructor() { - super(); - - this.bindingKey = null; - - document.addEventListener("keydown", (event) => { - const key = event.key; - if (this.bindingKey) { - event.preventDefault(); - - if (this.bindingKey === "inventory") { - Settings.inventory_key = key; - } else if (this.bindingKey === "spellbook") { - Settings.spellbook_key = key; - } else if (this.bindingKey === "prayer") { - Settings.prayer_key = key; - } else if (this.bindingKey === "equipment") { - Settings.equipment_key = key; - } else if (this.bindingKey === "combat") { - Settings.combat_key = key; - } - this.bindingKey = null; - setTimeout(() => { - Settings.is_keybinding = false; - }, 20); - Settings.persistToStorage(); - } - }); - } - - get isAvailable(): boolean { - return true; - } - - get appearsOnLeftInMobile(): boolean { - return false; - } - - get keyBinding() { - return BrowserUtils.getQueryVar("settings_key"); - } - - panelClickDown(x: number, y: number) { - const scale = Settings.controlPanelScale; - - x = x / scale; - y = y / scale; - - if (x > 20 && x < 56 && y > 20 && y < 56) { - Settings.playsAudio = !Settings.playsAudio; - } else if (x > 20 && x < 56 && y > 60 && y < 86) { - Settings.playsAreaAudio = !Settings.playsAreaAudio; - } else if (x > 74 && x < 89 && y > 20 && y < 36) { - Settings.maxUiScale += 0.05; - } else if (x > 75 && x < 89 && y > 51 && y < 67) { - Settings.maxUiScale -= 0.05; - } else if (x > 100 && x < 115 && y > 20 && y < 36) { - Settings.inputDelay += 20; - } else if (x > 100 && x < 115 && y > 51 && y < 67) { - Settings.inputDelay -= 20; - } else if (x > 20 && x < 60 && y > 100 && y < 140) { - Settings.displayPlayerLoS = !Settings.displayPlayerLoS; - } else if (x > 80 && x < 120 && y > 100 && y < 140) { - Settings.displayMobLoS = !Settings.displayMobLoS; - } else if (x > 140 && x < 180 && y > 120 && y < 160) { - // Settings.lockPOV = !Settings.lockPOV; - } else if (x > 140 && x < 180 && y > 70 && y < 110) { - Settings.displayFeedback = !Settings.displayFeedback; - } else if (x > 140 && x < 180 && y > 20 && y < 60) { - Settings.metronome = !Settings.metronome; - } else if (x > 20 && x < 60 && y > 170 && y < 210) { - Settings.is_keybinding = true; - this.bindingKey = "inventory"; - } else if (x > 80 && x < 120 && y > 170 && y < 210) { - Settings.is_keybinding = true; - this.bindingKey = "spellbook"; - } else if (x > 140 && x < 180 && y > 170 && y < 210) { - Settings.is_keybinding = true; - this.bindingKey = "prayer"; - } else if (x > 20 && x < 60 && y > 220 && y < 260) { - Settings.is_keybinding = true; - this.bindingKey = "equipment"; - } else if (x > 80 && x < 120 && y > 220 && y < 260) { - Settings.is_keybinding = true; - this.bindingKey = "combat"; - } else if (x > 140 && x < 180 && y > 220 && y < 260) { - Settings.menuVisible = !Settings.menuVisible; - - if (Settings.menuVisible) { - document.getElementById("right_panel").classList.remove("hidden"); - } else { - document.getElementById("right_panel").classList.add("hidden"); - } - Viewport.viewport.calculateViewport(); - } - - Settings.inputDelay = Math.max(0, Settings.inputDelay); - Settings.maxUiScale = Math.max(0.5, Math.min(1.5, Settings.maxUiScale)); - Settings.persistToStorage(); - } - - drawToggle(context: CanvasRenderingContext2D, x, y, image: HTMLImageElement, value: boolean) { - context.drawImage(image, x, y, image.width * Settings.controlPanelScale, image.height * Settings.controlPanelScale); - if (!value) { - context.drawImage( - this.disabledOverlay, - x, - y, - image.width * Settings.controlPanelScale, - image.height * Settings.controlPanelScale, - ); - } - } - - draw(context, ctrl: ControlPanelController, x: number, y: number) { - super.draw(context, ctrl, x, y); - const scale = Settings.controlPanelScale; - - this.drawToggle(context, x + 20 * scale, y + 20 * scale, this.soundImage, Settings.playsAudio); - this.drawToggle(context, x + 20 * scale, y + 60 * scale, this.areaSoundImage, Settings.playsAreaAudio); - - context.drawImage( - this.redUpImage, - x + 74 * scale, - y + 20 * scale, - this.redUpImage.width * scale, - this.redUpImage.height * scale, - ); - context.fillStyle = "#FFFF00"; - context.font = 16 * scale + "px OSRS"; - context.textAlign = "center"; - context.fillText(String(Math.round((Settings.maxUiScale - 1.0) * 100)) + "%", x + 79 * scale, y + 48 * scale); - context.drawImage( - this.greenDownImage, - x + 74 * scale, - y + 51 * scale, - this.greenDownImage.width * scale, - this.greenDownImage.height * scale, - ); - context.fillText("UI", x + 80 * scale, y + 81 * scale); - - context.drawImage( - this.redUpImage, - x + 100 * scale, - y + 20 * scale, - this.redUpImage.width * scale, - this.redUpImage.height * scale, - ); - context.fillStyle = "#FFFF00"; - context.font = 16 * scale + "px OSRS"; - context.textAlign = "center"; - context.fillText(String(Settings.inputDelay), x + 106 * scale, y + 48 * scale); - context.drawImage( - this.greenDownImage, - x + 100 * scale, - y + 51 * scale, - this.greenDownImage.width * scale, - this.greenDownImage.height * scale, - ); - context.fillText("Lag", x + 107 * scale, y + 81 * scale); - - context.drawImage( - Settings.displayPlayerLoS ? this.activeButtonImage : this.inactiveButtonImage, - x + 20 * scale, - y + 100 * scale, - this.activeButtonImage.width * scale, - this.activeButtonImage.height * scale, - ); - context.fillText("P LoS", x + 40 * scale, y + 125 * scale); - - context.drawImage( - Settings.displayMobLoS ? this.activeButtonImage : this.inactiveButtonImage, - x + 80 * scale, - y + 100 * scale, - this.activeButtonImage.width * scale, - this.activeButtonImage.height * scale, - ); - context.fillText("M LoS", x + 100 * scale, y + 125 * scale); - - // context.drawImage(Settings.lockPOV ? this.activeButtonImage : this.inactiveButtonImage, x + 140 * scale, y + 120 * scale, this.activeButtonImage.width * scale, this.activeButtonImage.height * scale) - // context.fillText('VP Lock', x + 160 * scale, y + 145 * scale) - - context.drawImage( - Settings.displayFeedback ? this.activeButtonImage : this.inactiveButtonImage, - x + 140 * scale, - y + 70 * scale, - this.activeButtonImage.width * scale, - this.activeButtonImage.height * scale, - ); - context.fillText("Pray Ind.", x + 160 * scale, y + 95 * scale); - - context.drawImage( - Settings.metronome ? this.activeButtonImage : this.inactiveButtonImage, - x + 140 * scale, - y + 20 * scale, - this.activeButtonImage.width * scale, - this.activeButtonImage.height * scale, - ); - context.fillText("Metronome", x + 160 * scale, y + 45 * scale); - - context.drawImage( - this.bindingKey === "inventory" ? this.activeButtonImage : this.inactiveButtonImage, - x + 22 * scale, - y + 170 * scale, - this.activeButtonImage.width * scale, - this.activeButtonImage.height * scale, - ); - context.drawImage( - this.inventoryImage, - x + 25 * scale, - y + 172 * scale, - this.inventoryImage.width * scale, - this.inventoryImage.height * scale, - ); - context.fillText(Settings.inventory_key, x + (25 + 30) * scale, y + (172 + 30) * scale); - - context.drawImage( - this.bindingKey === "spellbook" ? this.activeButtonImage : this.inactiveButtonImage, - x + 82 * scale, - y + 170 * scale, - this.activeButtonImage.width * scale, - this.activeButtonImage.height * scale, - ); - context.drawImage( - this.spellbookImage, - x + 85 * scale, - y + 172 * scale, - this.spellbookImage.width * scale, - this.spellbookImage.height * scale, - ); - context.fillText(Settings.spellbook_key, x + (85 + 30) * scale, y + (172 + 30) * scale); - - context.drawImage( - this.bindingKey === "prayer" ? this.activeButtonImage : this.inactiveButtonImage, - x + 142 * scale, - y + 170 * scale, - this.activeButtonImage.width * scale, - this.activeButtonImage.height * scale, - ); - context.drawImage( - this.prayerImage, - x + 145 * scale, - y + 172 * scale, - this.prayerImage.width * scale, - this.prayerImage.height * scale, - ); - context.fillText(Settings.prayer_key, x + (145 + 30) * scale, y + (172 + 30) * scale); - - context.drawImage( - this.bindingKey === "equipment" ? this.activeButtonImage : this.inactiveButtonImage, - x + 22 * scale, - y + 220 * scale, - this.activeButtonImage.width * scale, - this.activeButtonImage.height * scale, - ); - context.drawImage( - this.equipmentImage, - x + 25 * scale, - y + 222 * scale, - this.equipmentImage.width * scale, - this.equipmentImage.height * scale, - ); - context.fillText(Settings.equipment_key, x + (25 + 30) * scale, y + (222 + 30) * scale); - - context.drawImage( - this.bindingKey === "combat" ? this.activeButtonImage : this.inactiveButtonImage, - x + 82 * scale, - y + 220 * scale, - this.activeButtonImage.width * scale, - this.activeButtonImage.height * scale, - ); - context.drawImage( - this.combatImage, - x + 85 * scale, - y + 222 * scale, - this.combatImage.width * scale, - this.combatImage.height * scale, - ); - context.fillText(Settings.combat_key, x + (85 + 30) * scale, y + (222 + 30) * scale); - - context.drawImage( - Settings.menuVisible ? this.activeButtonImage : this.inactiveButtonImage, - x + 142 * scale, - y + 220 * scale, - this.activeButtonImage.width * scale, - this.activeButtonImage.height * scale, - ); - context.fillText("Menu", x + 163 * scale, y + 241 * scale); - - if (this.bindingKey === null) { - context.fillText("Key Bindings", x + 100 * scale, y + (133 + 30) * scale); - } else { - context.fillText("Press Key To Bind", x + 100 * scale, y + (133 + 30) * scale); - } - } -} diff --git a/src/sdk/controlpanels/StandardSpellbookControls.ts b/src/sdk/controlpanels/StandardSpellbookControls.ts deleted file mode 100644 index e6fb7611..00000000 --- a/src/sdk/controlpanels/StandardSpellbookControls.ts +++ /dev/null @@ -1,13 +0,0 @@ -import InventoryPanel from "../../assets/images/panels/inventory.png"; -import StandardSpellbookTab from "../../assets/images/tabs/standard_spellbook.png"; -import { BaseControls } from "./BaseControls"; - -export class StandardSpellbookControls extends BaseControls { - get panelImageReference() { - return InventoryPanel; - } - - get tabImageReference() { - return StandardSpellbookTab; - } -} diff --git a/src/sdk/controlpanels/StatsControls.ts b/src/sdk/controlpanels/StatsControls.ts deleted file mode 100644 index 26e634a4..00000000 --- a/src/sdk/controlpanels/StatsControls.ts +++ /dev/null @@ -1,328 +0,0 @@ -import StatsPanel from "../../assets/images/panels/stats.png"; -import StatsTab from "../../assets/images/tabs/stats.png"; -import { ControlPanelController } from "../ControlPanelController"; -import { Settings } from "../Settings"; -import { Viewport } from "../Viewport"; -import { BaseControls } from "./BaseControls"; - -export class StatsControls extends BaseControls { - get panelImageReference() { - return StatsPanel; - } - - get tabImageReference() { - return StatsTab; - } - - get isAvailable(): boolean { - return true; - } - - levelPrompt(skill: string): number { - const newLvl = parseInt(prompt("What level would you like to set your " + skill + "?", "99")); - if (isNaN(newLvl)) { - return -1; - } - if (newLvl > 0 && newLvl < 100) { - return newLvl; - } - return -1; - } - - panelClickUp(x: number, y: number) { - const scale = Settings.controlPanelScale; - - x = x / scale; - y = y / scale; - - if (x > 9 && x < 73) { - if (y > 12 && y < 44) { - const newLvl = this.levelPrompt("attack"); - if (newLvl > 0) { - Viewport.viewport.player.stats.attack = newLvl; - Viewport.viewport.player.currentStats.attack = newLvl; - Settings.player_stats = Viewport.viewport.player.stats; - Settings.persistToStorage(); - } - } else if (y > 44 && y < 76) { - // str - - const newLvl = this.levelPrompt("strength"); - if (newLvl > 0) { - Viewport.viewport.player.stats.strength = newLvl; - Viewport.viewport.player.currentStats.strength = newLvl; - Settings.player_stats = Viewport.viewport.player.stats; - Settings.persistToStorage(); - } - } else if (y > 76 && y < 108) { - // def - const newLvl = this.levelPrompt("defence"); - if (newLvl > 0) { - Viewport.viewport.player.stats.defence = newLvl; - Viewport.viewport.player.currentStats.defence = newLvl; - Settings.player_stats = Viewport.viewport.player.stats; - Settings.persistToStorage(); - } - } else if (y > 108 && y < 140) { - // ranged - const newLvl = this.levelPrompt("range"); - if (newLvl > 0) { - Viewport.viewport.player.stats.range = newLvl; - Viewport.viewport.player.currentStats.range = newLvl; - Settings.player_stats = Viewport.viewport.player.stats; - Settings.persistToStorage(); - } - } else if (y > 140 && y < 172) { - //prayer - const newLvl = this.levelPrompt("prayer"); - if (newLvl > 0) { - Viewport.viewport.player.stats.prayer = newLvl; - Viewport.viewport.player.currentStats.prayer = newLvl; - Settings.player_stats = Viewport.viewport.player.stats; - Settings.persistToStorage(); - } - } else if (y > 172 && y < 204) { - //magic - const newLvl = this.levelPrompt("magic"); - if (newLvl > 0) { - Viewport.viewport.player.stats.magic = newLvl; - Viewport.viewport.player.currentStats.magic = newLvl; - Settings.player_stats = Viewport.viewport.player.stats; - Settings.persistToStorage(); - } - } - } else if (x > 74 && x < 138) { - if (y > 12 && y < 44) { - // hp - const newLvl = this.levelPrompt("hitpoint"); - if (newLvl > 0) { - Viewport.viewport.player.stats.hitpoint = newLvl; - Viewport.viewport.player.currentStats.hitpoint = newLvl; - Settings.player_stats = Viewport.viewport.player.stats; - Settings.persistToStorage(); - } - } else if (y > 44 && y < 76) { - // agility - const newLvl = this.levelPrompt("agility"); - if (newLvl > 0) { - Viewport.viewport.player.stats.agility = newLvl; - Viewport.viewport.player.currentStats.agility = newLvl; - Settings.player_stats = Viewport.viewport.player.stats; - Settings.persistToStorage(); - } - } - } - } - - get appearsOnLeftInMobile(): boolean { - return false; - } - - draw(context, ctrl: ControlPanelController, x: number, y: number) { - super.draw(context, ctrl, x, y); - - const scale = Settings.controlPanelScale; - - Viewport.viewport.context.font = 16 * scale + "px Stats_11"; - - Viewport.viewport.context.fillStyle = "#000"; - Viewport.viewport.context.fillText( - String(Viewport.viewport.player.currentStats.attack), - x + 49 * scale, - y + 22 * scale, - ); - Viewport.viewport.context.fillStyle = "#FFFF00"; - Viewport.viewport.context.fillText( - String(Viewport.viewport.player.currentStats.attack), - x + 48 * scale, - y + 21 * scale, - ); - - Viewport.viewport.context.fillStyle = "#000"; - Viewport.viewport.context.fillText(String(Viewport.viewport.player.stats.attack), x + 61 * scale, y + 36 * scale); - Viewport.viewport.context.fillStyle = "#FFFF00"; - Viewport.viewport.context.fillText(String(Viewport.viewport.player.stats.attack), x + 60 * scale, y + 35 * scale); - - Viewport.viewport.context.fillStyle = "#000"; - Viewport.viewport.context.fillText( - String(Viewport.viewport.player.currentStats.strength), - x + 49 * scale, - y + (22 + 32) * scale, - ); - Viewport.viewport.context.fillStyle = "#FFFF00"; - Viewport.viewport.context.fillText( - String(Viewport.viewport.player.currentStats.strength), - x + 48 * scale, - y + (21 + 32) * scale, - ); - - Viewport.viewport.context.fillStyle = "#000"; - Viewport.viewport.context.fillText( - String(Viewport.viewport.player.stats.strength), - x + 61 * scale, - y + (36 + 32) * scale, - ); - Viewport.viewport.context.fillStyle = "#FFFF00"; - Viewport.viewport.context.fillText( - String(Viewport.viewport.player.stats.strength), - x + 60 * scale, - y + (35 + 32) * scale, - ); - - Viewport.viewport.context.fillStyle = "#000"; - Viewport.viewport.context.fillText( - String(Viewport.viewport.player.currentStats.defence), - x + 49 * scale, - y + (22 + 64) * scale, - ); - Viewport.viewport.context.fillStyle = "#FFFF00"; - Viewport.viewport.context.fillText( - String(Viewport.viewport.player.currentStats.defence), - x + 48 * scale, - y + (21 + 64) * scale, - ); - - Viewport.viewport.context.fillStyle = "#000"; - Viewport.viewport.context.fillText( - String(Viewport.viewport.player.stats.defence), - x + 61 * scale, - y + (36 + 64) * scale, - ); - Viewport.viewport.context.fillStyle = "#FFFF00"; - Viewport.viewport.context.fillText( - String(Viewport.viewport.player.stats.defence), - x + 60 * scale, - y + (35 + 64) * scale, - ); - - Viewport.viewport.context.fillStyle = "#000"; - Viewport.viewport.context.fillText( - String(Viewport.viewport.player.currentStats.range), - x + 49 * scale, - y + (22 + 96) * scale, - ); - Viewport.viewport.context.fillStyle = "#FFFF00"; - Viewport.viewport.context.fillText( - String(Viewport.viewport.player.currentStats.range), - x + 48 * scale, - y + (21 + 96) * scale, - ); - - Viewport.viewport.context.fillStyle = "#000"; - Viewport.viewport.context.fillText( - String(Viewport.viewport.player.stats.range), - x + 61 * scale, - y + (36 + 96) * scale, - ); - Viewport.viewport.context.fillStyle = "#FFFF00"; - Viewport.viewport.context.fillText( - String(Viewport.viewport.player.stats.range), - x + 60 * scale, - y + (35 + 96) * scale, - ); - - Viewport.viewport.context.fillStyle = "#000"; - Viewport.viewport.context.fillText( - String(Viewport.viewport.player.currentStats.prayer), - x + 49 * scale, - y + (22 + 128) * scale, - ); - Viewport.viewport.context.fillStyle = "#FFFF00"; - Viewport.viewport.context.fillText( - String(Viewport.viewport.player.currentStats.prayer), - x + 48 * scale, - y + (21 + 128) * scale, - ); - - Viewport.viewport.context.fillStyle = "#000"; - Viewport.viewport.context.fillText( - String(Viewport.viewport.player.stats.prayer), - x + 61 * scale, - y + (36 + 128) * scale, - ); - Viewport.viewport.context.fillStyle = "#FFFF00"; - Viewport.viewport.context.fillText( - String(Viewport.viewport.player.stats.prayer), - x + 60 * scale, - y + (35 + 128) * scale, - ); - - Viewport.viewport.context.fillStyle = "#000"; - Viewport.viewport.context.fillText( - String(Viewport.viewport.player.currentStats.magic), - x + 49 * scale, - y + (22 + 160) * scale, - ); - Viewport.viewport.context.fillStyle = "#FFFF00"; - Viewport.viewport.context.fillText( - String(Viewport.viewport.player.currentStats.magic), - x + 48 * scale, - y + (21 + 160) * scale, - ); - - Viewport.viewport.context.fillStyle = "#000"; - Viewport.viewport.context.fillText( - String(Viewport.viewport.player.stats.magic), - x + 61 * scale, - y + (36 + 160) * scale, - ); - Viewport.viewport.context.fillStyle = "#FFFF00"; - Viewport.viewport.context.fillText( - String(Viewport.viewport.player.stats.magic), - x + 60 * scale, - y + (35 + 160) * scale, - ); - - Viewport.viewport.context.fillStyle = "#000"; - Viewport.viewport.context.fillText( - String(Viewport.viewport.player.currentStats.hitpoint), - x + (49 + 63) * scale, - y + 22 * scale, - ); - Viewport.viewport.context.fillStyle = "#FFFF00"; - Viewport.viewport.context.fillText( - String(Viewport.viewport.player.currentStats.hitpoint), - x + (48 + 63) * scale, - y + 21 * scale, - ); - - Viewport.viewport.context.fillStyle = "#000"; - Viewport.viewport.context.fillText( - String(Viewport.viewport.player.stats.hitpoint), - x + (61 + 63) * scale, - y + 36 * scale, - ); - Viewport.viewport.context.fillStyle = "#FFFF00"; - Viewport.viewport.context.fillText( - String(Viewport.viewport.player.stats.hitpoint), - x + (60 + 63) * scale, - y + 35 * scale, - ); - - Viewport.viewport.context.fillStyle = "#000"; - Viewport.viewport.context.fillText( - String(Viewport.viewport.player.currentStats.agility), - x + (49 + 63) * scale, - y + (22 + 32) * scale, - ); - Viewport.viewport.context.fillStyle = "#FFFF00"; - Viewport.viewport.context.fillText( - String(Viewport.viewport.player.currentStats.agility), - x + (48 + 63) * scale, - y + (21 + 32) * scale, - ); - - Viewport.viewport.context.fillStyle = "#000"; - Viewport.viewport.context.fillText( - String(Viewport.viewport.player.stats.agility), - x + (61 + 63) * scale, - y + (36 + 32) * scale, - ); - Viewport.viewport.context.fillStyle = "#FFFF00"; - Viewport.viewport.context.fillText( - String(Viewport.viewport.player.stats.agility), - x + (60 + 63) * scale, - y + (35 + 32) * scale, - ); - } -} diff --git a/src/sdk/gear/Ammo.ts b/src/sdk/gear/Ammo.ts deleted file mode 100644 index 6b38027a..00000000 --- a/src/sdk/gear/Ammo.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { Equipment, EquipmentTypes } from "../Equipment"; -import { Player } from "../Player"; - -export enum AmmoType { - BLESSING = 0, - AMMO = 1, // Temporary, can be broken down later. Only made this enum for the blessing distinction. -} - -export class Ammo extends Equipment { - get type(): EquipmentTypes { - return EquipmentTypes.AMMO; - } - - ammoType(): AmmoType { - return AmmoType.AMMO; - } - - assignToPlayer(player: Player) { - player.equipment.ammo = this; - } - - unassignToPlayer(player: Player) { - player.equipment.ammo = null; - } - - currentEquipment(player: Player): Equipment { - return player.equipment.ammo; - } -} diff --git a/src/sdk/gear/Cape.ts b/src/sdk/gear/Cape.ts deleted file mode 100644 index 14ceedc5..00000000 --- a/src/sdk/gear/Cape.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Equipment, EquipmentTypes } from "../Equipment"; -import { Player } from "../Player"; - -export class Cape extends Equipment { - get type(): EquipmentTypes { - return EquipmentTypes.AMMO; - } - - assignToPlayer(player: Player) { - player.equipment.cape = this; - } - unassignToPlayer(player: Player) { - player.equipment.cape = null; - } - - currentEquipment(player: Player): Equipment { - return player.equipment.cape; - } -} diff --git a/src/sdk/gear/Chest.ts b/src/sdk/gear/Chest.ts deleted file mode 100644 index 26a1e7ff..00000000 --- a/src/sdk/gear/Chest.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Equipment, EquipmentTypes } from "../Equipment"; -import { Player } from "../Player"; - -export class Chest extends Equipment { - get type(): EquipmentTypes { - return EquipmentTypes.CHEST; - } - assignToPlayer(player: Player) { - player.equipment.chest = this; - } - - unassignToPlayer(player: Player) { - player.equipment.chest = null; - } - currentEquipment(player: Player): Equipment { - return player.equipment.chest; - } -} diff --git a/src/sdk/gear/Feet.ts b/src/sdk/gear/Feet.ts deleted file mode 100644 index 387b9f58..00000000 --- a/src/sdk/gear/Feet.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Equipment, EquipmentTypes } from "../Equipment"; -import { Player } from "../Player"; - -export class Feet extends Equipment { - get type(): EquipmentTypes { - return EquipmentTypes.FEET; - } - - assignToPlayer(player: Player) { - player.equipment.feet = this; - } - unassignToPlayer(player: Player) { - player.equipment.feet = null; - } - - currentEquipment(player: Player): Equipment { - return player.equipment.feet; - } -} diff --git a/src/sdk/gear/Food.ts b/src/sdk/gear/Food.ts deleted file mode 100644 index 29fb04c8..00000000 --- a/src/sdk/gear/Food.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { Item } from "../Item"; -import { ImageLoader } from "../utils/ImageLoader"; -import { Player } from "../Player"; - -export class Food extends Item { - healAmount = 0; - inventorySprite: HTMLImageElement = ImageLoader.createImage(this.inventoryImage); - - constructor() { - super(); - - this.defaultAction = "Eat"; - } - - eat(player: Player) { - player.interruptCombat(); - if (player.currentStats.hitpoint < player.stats.hitpoint) { - player.currentStats.hitpoint += this.healAmount; - player.currentStats.hitpoint = Math.min(player.currentStats.hitpoint, player.stats.hitpoint); - } - } - - get weight(): number { - return 0.226; - } - - updateInventorySprite() { - // Override me - } - - get hasInventoryLeftClick(): boolean { - return true; - } - inventoryLeftClick(player: Player) { - player.eats.eatFood(this); - } -} diff --git a/src/sdk/gear/Gloves.ts b/src/sdk/gear/Gloves.ts deleted file mode 100644 index f13ae645..00000000 --- a/src/sdk/gear/Gloves.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Equipment, EquipmentTypes } from "../Equipment"; -import { Player } from "../Player"; - -export class Gloves extends Equipment { - get type(): EquipmentTypes { - return EquipmentTypes.GLOVES; - } - - assignToPlayer(player: Player) { - player.equipment.gloves = this; - } - - unassignToPlayer(player: Player) { - player.equipment.gloves = null; - } - currentEquipment(player: Player): Equipment { - return player.equipment.gloves; - } -} diff --git a/src/sdk/gear/Helmet.ts b/src/sdk/gear/Helmet.ts deleted file mode 100644 index a0bed13b..00000000 --- a/src/sdk/gear/Helmet.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Equipment, EquipmentTypes } from "../Equipment"; -import { Player } from "../Player"; - -export class Helmet extends Equipment { - get type(): EquipmentTypes { - return EquipmentTypes.HELMET; - } - - assignToPlayer(player: Player) { - player.equipment.helmet = this; - } - unassignToPlayer(player: Player) { - player.equipment.helmet = null; - } - - currentEquipment(player: Player): Equipment { - return player.equipment.helmet; - } -} diff --git a/src/sdk/gear/Legs.ts b/src/sdk/gear/Legs.ts deleted file mode 100644 index 387e7576..00000000 --- a/src/sdk/gear/Legs.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Equipment, EquipmentTypes } from "../Equipment"; -import { Player } from "../Player"; - -export class Legs extends Equipment { - get type(): EquipmentTypes { - return EquipmentTypes.LEGS; - } - - assignToPlayer(player: Player) { - player.equipment.legs = this; - } - - unassignToPlayer(player: Player) { - player.equipment.legs = null; - } - currentEquipment(player: Player): Equipment { - return player.equipment.legs; - } -} diff --git a/src/sdk/gear/Necklace.ts b/src/sdk/gear/Necklace.ts deleted file mode 100644 index bf16333c..00000000 --- a/src/sdk/gear/Necklace.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Equipment, EquipmentTypes } from "../Equipment"; -import { Player } from "../Player"; - -export class Necklace extends Equipment { - get type(): EquipmentTypes { - return EquipmentTypes.NECK; - } - - assignToPlayer(player: Player) { - player.equipment.necklace = this; - } - - unassignToPlayer(player: Player) { - player.equipment.necklace = null; - } - currentEquipment(player: Player): Equipment { - return player.equipment.necklace; - } -} diff --git a/src/sdk/gear/Offhand.ts b/src/sdk/gear/Offhand.ts deleted file mode 100644 index a097a335..00000000 --- a/src/sdk/gear/Offhand.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { Equipment, EquipmentTypes } from "../Equipment"; -import { Player } from "../Player"; - -export class Offhand extends Equipment { - get type(): EquipmentTypes { - return EquipmentTypes.OFFHAND; - } - - inventoryLeftClick(player: Player) { - const currentWeapon = player.equipment.weapon || null; - const currentOffhand = player.equipment.offhand || null; - - let openInventorySlots = player.openInventorySlots(); - openInventorySlots.unshift(player.inventory.indexOf(this)); - - let neededInventorySlots = 0; - if (currentWeapon && currentWeapon.isTwoHander) { - neededInventorySlots++; - } - - if (neededInventorySlots > openInventorySlots.length) { - return; - } - - this.assignToPlayer(player); - if (currentOffhand) { - player.inventory[openInventorySlots.shift()] = currentOffhand; - } else { - player.inventory[openInventorySlots.shift()] = null; - openInventorySlots = player.openInventorySlots(); - } - - if (currentWeapon && currentWeapon.isTwoHander) { - player.inventory[openInventorySlots.shift()] = currentWeapon; - player.equipment.weapon = null; - } - - player.equipmentChanged(); - } - - assignToPlayer(player: Player) { - player.equipment.offhand = this; - } - unassignToPlayer(player: Player) { - player.equipment.offhand = null; - } - - currentEquipment(player: Player): Equipment { - return player.equipment.offhand; - } -} diff --git a/src/sdk/gear/Potion.ts b/src/sdk/gear/Potion.ts deleted file mode 100644 index 8e70d5b6..00000000 --- a/src/sdk/gear/Potion.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { Item } from "../Item"; -import { ImageLoader } from "../utils/ImageLoader"; -import Vial from "../../assets/images/potions/Vial.png"; -import { Player } from "../Player"; - -import PotionSound from "../../assets/sounds/liquid_2401.ogg"; -import { Sound, SoundCache } from "../utils/SoundCache"; - -export class Potion extends Item { - inventorySprite: HTMLImageElement = ImageLoader.createImage(this.inventoryImage); - vial: HTMLImageElement = ImageLoader.createImage(Vial); - doses = 4; - - constructor() { - super(); - this.defaultAction = "Drink"; - } - drink(player: Player) { - player.interruptCombat(); - } - - get weight(): number { - return 0.226; - } - - updateInventorySprite() { - // Override me - } - - get hasInventoryLeftClick(): boolean { - return true; - } - inventoryLeftClick(player: Player) { - let didDrink = false; - if (this.doses > 0) { - didDrink = player.eats.drinkPotion(this); - } - if (this.doses === 0) { - this.consumeItem(player); - } - if (didDrink) { - SoundCache.play(new Sound(PotionSound, 0.1)); - } - this.updateInventorySprite(); - } -} diff --git a/src/sdk/gear/Ring.ts b/src/sdk/gear/Ring.ts deleted file mode 100644 index 7dd0aee9..00000000 --- a/src/sdk/gear/Ring.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Equipment, EquipmentTypes } from "../Equipment"; -import { Player } from "../Player"; - -export class Ring extends Equipment { - get type(): EquipmentTypes { - return EquipmentTypes.RING; - } - - assignToPlayer(player: Player) { - player.equipment.ring = this; - } - unassignToPlayer(player: Player) { - player.equipment.ring = null; - } - - currentEquipment(player: Player): Equipment { - return player.equipment.ring; - } -} diff --git a/src/sdk/gear/Weapon.ts b/src/sdk/gear/Weapon.ts deleted file mode 100644 index 8f755b27..00000000 --- a/src/sdk/gear/Weapon.ts +++ /dev/null @@ -1,306 +0,0 @@ -"use strict"; - -import { BasePrayer } from "../BasePrayer"; -import { Unit, UnitTypes } from "../Unit"; -import { ImageLoader } from "../utils/ImageLoader"; -import { Equipment } from "../Equipment"; -import { Player } from "../Player"; -import { Projectile, ProjectileOptions } from "../weapons/Projectile"; -import { find } from "lodash"; -import { SetEffect, SetEffectTypes } from "../SetEffect"; -import { ItemName } from "../ItemName"; -import { AttackStylesController, AttackStyle, AttackStyleTypes } from "../AttackStylesController"; -import { Random } from "../Random"; -import { Sound, SoundCache } from "../utils/SoundCache"; -import { PlayerAnimationIndices } from "../rendering/GLTFAnimationConstants"; -import { XpDrop } from "../XpDrop"; - -interface EffectivePrayers { - magic?: BasePrayer; - range?: BasePrayer; - attack?: BasePrayer; - strength?: BasePrayer; - defence?: BasePrayer; - overhead?: BasePrayer; -} - -export interface AttackBonuses { - styleBonus?: number; - isAccurate?: boolean; - // aggressive/controlled - styleStrengthBonus?: number; - voidMultiplier?: number; - gearMeleeMultiplier?: number; - gearMageMultiplier?: number; - gearRangeMultiplier?: number; - attackStyle?: string; - magicBaseSpellDamage?: number; - overallMultiplier?: number; - effectivePrayers?: EffectivePrayers; - isSpecialAttack?: boolean; -} - -export class Weapon extends Equipment { - damage: number; - damageRoll: number; - lastHitHit = false; - override selected = false; - override inventorySprite: HTMLImageElement = ImageLoader.createImage(this.inventoryImage); - - constructor(protected projectileOptions: ProjectileOptions = {}) { - super(); - } - - attackStyles() { - return []; - } - - compatibleAmmo(): ItemName[] { - return []; - } - - attackStyleCategory(): AttackStyleTypes { - return null; - } - - defaultStyle(): AttackStyle { - return AttackStyle.RAPID; - } - - attackStyle() { - return AttackStylesController.controller.getAttackStyleForType(this.attackStyleCategory(), this); - } - - override assignToPlayer(player: Player) { - player.equipment.weapon = this; - player.interruptCombat(); - } - - override unassignToPlayer(player: Player) { - player.equipment.weapon = null; - } - override currentEquipment(player: Player): Equipment { - return player.equipment.weapon; - } - - hasSpecialAttack(): boolean { - return false; - } - specialAttackDrain(): number { - return 50; - } - - specialAttack(from: Unit, to: Unit, bonuses: AttackBonuses = {}, options: ProjectileOptions = {}) { - // Override me - } - - override inventoryLeftClick(player: Player) { - const currentWeapon = player.equipment.weapon || null; - const currentOffhand = player.equipment.offhand || null; - - let openInventorySlots = player.openInventorySlots(); - openInventorySlots.unshift(player.inventory.indexOf(this)); - - let neededInventorySlots = 0; - if (this.isTwoHander && currentWeapon) { - neededInventorySlots++; - } - if (this.isTwoHander && currentOffhand) { - neededInventorySlots++; - } - if (currentWeapon) { - neededInventorySlots--; - } - - if (neededInventorySlots > openInventorySlots.length) { - return; - } - this.assignToPlayer(player); - if (currentWeapon) { - player.inventory[openInventorySlots.shift()] = currentWeapon; - } else { - player.inventory[openInventorySlots.shift()] = null; - openInventorySlots = player.openInventorySlots(); - } - if (this.isTwoHander && currentOffhand) { - player.inventory[openInventorySlots.shift()] = currentOffhand; - player.equipment.offhand = null; - } - player.equipmentChanged(); - } - - cast(from: Unit, to: Unit) { - // Override me - } - - rollDamage(from: Unit, to: Unit, bonuses: AttackBonuses) { - this.damageRoll = Math.floor(this._rollAttack(from, to, bonuses)); - this.damage = Math.min(this.damageRoll, to.currentStats.hitpoint); - } - - calculateHitDelay(distance: number) { - return 999; - } - - // Return value: If the attack was performed or not. If the attack was not performed, do not reset timers. - attack(from: Unit, to: Unit, bonuses: AttackBonuses = {}, options: ProjectileOptions = {}): boolean { - this._calculatePrayerEffects(from, to, bonuses); - bonuses.styleBonus = bonuses.styleBonus || 0; - bonuses.voidMultiplier = bonuses.voidMultiplier || 1; - bonuses.gearMeleeMultiplier = bonuses.gearMeleeMultiplier || 1; - bonuses.gearMageMultiplier = bonuses.gearMageMultiplier || 1; - bonuses.gearRangeMultiplier = bonuses.gearRangeMultiplier || 1; - bonuses.overallMultiplier = bonuses.overallMultiplier || 1.0; - - this.rollDamage(from, to, bonuses); - - if (this.damage === -1) { - return false; - } - - if (to.setEffects) { - find(to.setEffects, (effect: typeof SetEffect) => { - if (effect.effectName() === SetEffectTypes.JUSTICIAR) { - const tosDefenceBonus = to.bonuses.defence[bonuses.attackStyle]; - if (tosDefenceBonus !== undefined) { - // hack? - const justiciarDamageReduction = Math.max(tosDefenceBonus / 3000, 0); - this.damage -= Math.ceil(justiciarDamageReduction * this.damage); - } - } - }); - } - - // Protection prayers - if (this.isBlockable(from, to, bonuses)) { - this.damage = 0; - } - - // sanitize damage output - this.damage = Math.floor(Math.max(Math.min(to.currentStats.hitpoint, this.damage, 100), 0)); - - if (to.equipment.ring && to.equipment.ring.itemName === ItemName.RING_OF_SUFFERING_I && this.damage > 0) { - from.addProjectile( - new Projectile(this, Math.floor(this.damage * 0.1) + 1, to, from, "recoil", { reduceDelay: 15, hidden: true }), - ); - } - - this.grantXp(from, to); - this.registerProjectile(from, to, bonuses, options); - return true; - } - - _rollAttack(from: Unit, to: Unit, bonuses: AttackBonuses) { - this.lastHitHit = false; - return Random.get() > this._hitChance(from, to, bonuses) ? 0 : this._calculateHitDamage(from, to, bonuses); - } - - _calculateHitDamage(from: Unit, to: Unit, bonuses: AttackBonuses) { - this.lastHitHit = true; - return Math.floor(Random.get() * (this._maxHit(from, to, bonuses) + 1)); - } - - _attackRoll(from: Unit, to: Unit, bonuses: AttackBonuses) { - return 0; // weapons implement this at the type tier - } - _defenceRoll(from: Unit, to: Unit, bonuses: AttackBonuses) { - return 0; // weapons implement this at the type tier - } - _maxHit(from: Unit, to: Unit, bonuses: AttackBonuses) { - return 0; // weapons implement this at the type tier - } - - _hitChance(from: Unit, to: Unit, bonuses: AttackBonuses) { - const attackRoll = this._attackRoll(from, to, bonuses); - const defenceRoll = this._defenceRoll(from, to, bonuses); - const hitChance = - attackRoll > defenceRoll ? 1 - (defenceRoll + 2) / (2 * attackRoll + 1) : attackRoll / (2 * defenceRoll + 1); - return hitChance; - } - - isBlockable(from: Unit, to: Unit, bonuses: AttackBonuses): boolean { - return false; // weapons implement this at the type tier - } - - grantXp(from: Unit, to: Unit) { - if (from.type === UnitTypes.PLAYER && this.damage > 0) { - AttackStylesController.controller - .getWeaponXpDrops(this.attackStyle(), this.damage, to.xpBonusMultiplier) - .forEach(({ skill, xp }) => { - from.grantXp(new XpDrop(skill, xp)); - }); - } - } - - _calculatePrayerEffects(from: Unit, to: Unit, bonuses: AttackBonuses) { - // weapons implement this at the type tier - } - - registerProjectile(from: Unit, to: Unit, bonuses: AttackBonuses, options: ProjectileOptions = {}) { - to.addProjectile( - new Projectile(this, this.damage, from, to, bonuses.attackStyle, { - sound: this.attackSound, - hitSound: this.attackLandingSound, - model: this.projectileModel, - ...this.projectileOptions, - ...options, - }), - ); - } - - get image(): HTMLImageElement { - return null; - } - - get attackRange(): number { - return 0; - } - - get attackSpeed(): number { - return 10; - } - - get aoe() { - return [{ x: 0, y: 0 }]; - } - - // Returns true if this attack is an area-based attack that doesn't require line of sight to - // the target (including if the target is underneath). - get isAreaAttack() { - return false; - } - - // Returns true if this attack is a melee attack (and therefore cannot attack on corners). - get isMeleeAttack() { - return false; - } - - get isTwoHander(): boolean { - return false; - } - - static isMeleeAttackStyle(style: string) { - return style === "crush" || style === "slash" || style === "stab"; - } - - get attackSound(): Sound | null { - // Override me - return null; - } - - get specialAttackSound(): Sound | null { - return null; - } - - get attackLandingSound(): Sound | null { - return null; - } - - get projectileModel(): string | null { - return null; - } - - get idleAnimationId() { - return PlayerAnimationIndices.Idle; - } -} diff --git a/src/sdk/rendering/Actor.ts b/src/sdk/rendering/Actor.ts deleted file mode 100644 index d4bd6b7a..00000000 --- a/src/sdk/rendering/Actor.ts +++ /dev/null @@ -1,44 +0,0 @@ -import * as THREE from "three"; - -import { Renderable } from "../Renderable"; -import { Model } from "./Model"; - -export class Actor { - private model: Model; - - constructor(private unit: Renderable) { - this.model = unit.get3dModel(); - } - - draw(scene: THREE.Scene, clockDelta: number, tickPercent: number) { - if (!this.model) { - return; - } - const worldLocation = this.unit.getPerceivedLocation(tickPercent); - const rotationRadians = this.unit.getPerceivedRotation(tickPercent); - const pitchRadians = this.unit.getPerceivedPitch(tickPercent); - const modelOffsets = this.unit.getPerceivedOffsets(tickPercent); - this.model.draw( - scene, - clockDelta, - tickPercent, - worldLocation, - rotationRadians, - pitchRadians, - this.unit.visible(tickPercent), - modelOffsets, - ); - } - - shouldRemove() { - return this.unit.shouldDestroy(); - } - - getModel(): Model | null { - return this.model; - } - - destroy(scene: THREE.Scene) { - this.model?.destroy(scene); - } -} diff --git a/src/sdk/rendering/BasicModel.ts b/src/sdk/rendering/BasicModel.ts deleted file mode 100644 index 88f2f76e..00000000 --- a/src/sdk/rendering/BasicModel.ts +++ /dev/null @@ -1,94 +0,0 @@ -import * as THREE from "three"; -import { Model } from "./Model"; -import { Renderable } from "../Renderable"; -import { Location, Location3 } from "../Location"; - -export enum BasicModelShape { - BOX, - SPHERE, -} - -export class BasicModel implements Model { - private geometry: THREE.BufferGeometry; - private material: THREE.MeshStandardMaterial; - private mesh: THREE.Mesh; - - static forRenderable(r: Renderable) { - return new BasicModel(r.size, r.height, r.colorHex, r); - } - - static forRenderableCentered(r: Renderable) { - return new BasicModel(r.size, r.height, r.colorHex, r, { - x: r.size / 2, - z: -r.size / 2, - }); - } - - // centered sphere - static sphereForRenderable(r: Renderable) { - return new BasicModel(r.size, r.height, r.colorHex, r, { x: r.size / 2, z: -r.size / 2 }, BasicModelShape.SPHERE); - } - - constructor( - private size: number, - height: number, - color: number, - unit: Renderable | null, - private drawOffset: { x?: number; y?: number; z?: number } = {}, - private shape: BasicModelShape = BasicModelShape.BOX, - ) { - this.geometry = - shape === BasicModelShape.BOX - ? new THREE.BoxGeometry(size, height, size) - : new THREE.SphereGeometry(size / 2, 8, 8); - this.material = new THREE.MeshStandardMaterial({ color }); - this.mesh = new THREE.Mesh(this.geometry, this.material); - this.mesh.userData.clickable = unit !== null && unit.selectable; - this.mesh.userData.unit = unit; - } - - draw( - scene: THREE.Scene, - clockDelta: number, - tickPercent: number, - location: Location3, - rotation: number, - pitch: number, - visible: boolean, - ) { - if (this.mesh.parent !== scene) { - scene.add(this.mesh); - } - const size = this.size; - const { x, y, z } = location; - - this.mesh.visible = visible; - - // conversion from Location3 to Vector3 - this.mesh.position.x = x + size / 2; - this.mesh.position.y = z + size / 2; - this.mesh.position.z = y - size / 2; - this.mesh.position.add({ - x: this.drawOffset.x || 0, - y: this.drawOffset.y || 0, - z: this.drawOffset.z || 0, - }); - - this.mesh.setRotationFromAxisAngle(new THREE.Vector3(0, 1, 0), rotation); - } - - destroy(scene: THREE.Scene) { - if (this.mesh.parent === scene) { - scene.remove(this.mesh); - } - } - - getWorldPosition(): THREE.Vector3 { - return this.mesh.getWorldPosition(new THREE.Vector3()); - } - - async preload() { - // do nothing - return; - } -} diff --git a/src/sdk/rendering/CanvasSpriteModel.ts b/src/sdk/rendering/CanvasSpriteModel.ts deleted file mode 100644 index 00ac7d7f..00000000 --- a/src/sdk/rendering/CanvasSpriteModel.ts +++ /dev/null @@ -1,124 +0,0 @@ -import * as THREE from "three"; -import { Model } from "./Model"; -import { Renderable } from "../Renderable"; -import { Location } from "../Location"; -import { drawLineNormally, drawLineOnTop } from "./RenderUtils"; - -const CANVAS_TILE_SIZE = 20; - -const OUTLINE_NORMAL = 0xffffff; -const OUTLINE_SELECTED = 0xff0000; - -/** - * Render the model using a sprite derived from the 2d representation of the renderable. - */ -export class CanvasSpriteModel implements Model { - static forRenderable(r: Renderable) { - return new CanvasSpriteModel(r); - } - - private sprite: THREE.Sprite; - private texture: THREE.Texture; - - private canvas: OffscreenCanvas; - private context: OffscreenCanvasRenderingContext2D; - - private outline: THREE.LineSegments; - private outlineMaterial: THREE.LineBasicMaterial; - - constructor(private renderable: Renderable) { - const { size } = renderable; - this.canvas = new OffscreenCanvas(size * CANVAS_TILE_SIZE, size * CANVAS_TILE_SIZE); - this.context = this.canvas.getContext("2d"); - this.texture = new THREE.Texture(this.canvas); - this.texture.needsUpdate = true; - this.texture.colorSpace = THREE.LinearSRGBColorSpace; - const material = new THREE.SpriteMaterial({ - alphaTest: 0.5, - map: this.texture, - transparent: true, - color: 0xffffff, - }); - - this.sprite = new THREE.Sprite(material); - this.sprite.scale.set(size, size, size); - // trial and error to get the sprite to sit on top of the tile. could probably be set per-mob - this.sprite.center.y = 0.075; - this.sprite.userData.clickable = renderable.selectable; - this.sprite.userData.unit = renderable; - - this.outlineMaterial = new THREE.LineBasicMaterial({ - color: OUTLINE_NORMAL, - }); - const points = [ - new THREE.Vector3(0, 0, 0), - new THREE.Vector3(size, 0, 0), - new THREE.Vector3(size, 0, 0), - new THREE.Vector3(size, 0, -size), - new THREE.Vector3(size, 0, -size), - new THREE.Vector3(0, 0, -size), - new THREE.Vector3(0, 0, -size), - new THREE.Vector3(0, 0, 0), - ]; - const geometry = new THREE.BufferGeometry().setFromPoints(points); - this.outline = new THREE.LineSegments(geometry, this.outlineMaterial); - } - - draw( - scene: THREE.Scene, - clockDelta: number, - tickPercent: number, - location: Location, - rotation: number, - pitch: number, - visible: boolean, - ) { - if (this.sprite.parent !== scene) { - scene.add(this.sprite); - scene.add(this.outline); - } - const size = this.renderable.size; - this.context.clearRect(0, 0, this.canvas.width, this.canvas.height); - this.renderable.draw( - tickPercent, - this.context, - { x: 0, y: size - 1 }, - CANVAS_TILE_SIZE, - false, // do not draw under-tile - ); - this.texture.needsUpdate = true; - - this.outlineMaterial.color.setHex(this.renderable.selected ? OUTLINE_SELECTED : OUTLINE_NORMAL); - if (this.renderable.selected) { - drawLineOnTop(this.outline); - } else { - drawLineNormally(this.outline); - } - this.sprite.visible = visible; - this.outline.visible = visible; - - const { x, y } = location; - this.outline.position.x = x; - this.outline.position.y = -0.49; - this.outline.position.z = y; - this.sprite.position.x = x + size / 2; - this.sprite.position.y = -0.5; - this.sprite.position.z = y - size / 2; - } - - destroy(scene: THREE.Scene) { - if (this.sprite.parent === scene) { - scene.remove(this.sprite); - scene.remove(this.outline); - } - } - - getWorldPosition(): THREE.Vector3 { - return this.sprite.getWorldPosition(new THREE.Vector3()); - } - - async preload() { - // do nothing - return; - } -} diff --git a/src/sdk/rendering/EmptyModel.ts b/src/sdk/rendering/EmptyModel.ts deleted file mode 100644 index 6d54e72c..00000000 --- a/src/sdk/rendering/EmptyModel.ts +++ /dev/null @@ -1,27 +0,0 @@ -import * as THREE from "three"; -import { Model } from "./Model"; -import { Renderable } from "../Renderable"; -import { Location } from "../Location"; - -export class EmptyModel implements Model { - static forRenderable(r: Renderable) { - return new EmptyModel(); - } - - draw(scene: THREE.Scene, clockDelta: number, tickPercent: number, location: Location) { - // do nothing - } - - destroy(scene: THREE.Scene) { - // do nothing - } - - getWorldPosition(): THREE.Vector3 { - return new THREE.Vector3(0, 0, 0); - } - - async preload() { - // do nothing - return; - } -} diff --git a/src/sdk/rendering/GLTFAnimationConstants.ts b/src/sdk/rendering/GLTFAnimationConstants.ts deleted file mode 100644 index e8a182f7..00000000 --- a/src/sdk/rendering/GLTFAnimationConstants.ts +++ /dev/null @@ -1,15 +0,0 @@ -// this just happens to be the order that we exported the models animations in - see ASSETS.md -export enum PlayerAnimationIndices { - Idle = 0, - Walk = 1, - Run = 2, - Rotate180 = 3, - StrafeLeft = 4, - StrafeRight = 5, - FireBow = 6, - FireBlowpipe = 7, - ThrowChinchompa = 8, - ScytheIdle = 9, - ScytheSwing = 10, - SwordSlash = 11, -} diff --git a/src/sdk/rendering/GLTFModel.ts b/src/sdk/rendering/GLTFModel.ts deleted file mode 100644 index 1e422108..00000000 --- a/src/sdk/rendering/GLTFModel.ts +++ /dev/null @@ -1,410 +0,0 @@ -import * as THREE from "three"; - -import { GLTF, GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js"; -import { MeshoptDecoder } from "three/examples/jsm/libs/meshopt_decoder.module"; - -import { Model } from "./Model"; -import { Renderable, RenderableListener } from "../Renderable"; -import { Location, Location3 } from "../Location"; -import { Viewport } from "../Viewport"; -import { Viewport3d } from "../Viewport3d"; -import { drawLineNormally, drawLineOnTop } from "./RenderUtils"; - -const OUTLINE_NORMAL = 0xffffff; -const OUTLINE_TRUE_TILE = 0x00ffff; -const OUTLINE_SELECTED = 0xff0000; - -// global loader across models -const loader = new GLTFLoader(); -loader.setMeshoptDecoder(MeshoptDecoder); - -// cache a copy of each model -const globalModelCache: {[name: string]: GLTF} = {}; - -/** - * Render the model using one or more GLTF models. If there are multiple models, they are drawn superimposed on the same spot and are expected - * to have the same animation set. - */ -export class GLTFModel implements Model, RenderableListener { - static forRenderable( - r: Renderable, - model: string, - scale: number, - verticalOffset = -0.49, - originOffset: Location = { x: 0, y: 0 }, - ) { - return new GLTFModel(r, [model], scale, verticalOffset, originOffset); - } - - static forRenderableMulti( - r: Renderable, - models: string[], - scale: number, - verticalOffset = -0.49, - originOffset: Location = { x: 0, y: 0 }, - ) { - return new GLTFModel(r, models, scale, verticalOffset, originOffset); - } - - private outline: THREE.LineSegments; - private outlineMaterial: THREE.LineBasicMaterial; - - private trueTile: THREE.LineSegments; - - private hullGeometry: THREE.CylinderGeometry; - private clickHull: THREE.Mesh; - - // parent object for all models loaded into this - private loadedModel: THREE.Object3D | null = null; - private hasInitialisedModel = false; - private mixers: THREE.AnimationMixer[] = []; - - private lastPoseId = -1; - private playingAnimationId = -1; - private playingAnimationCanBlend = false; - private playingAnimationPromiseResolve = null; - // first index is the model ID, second index is the animation ID. - private animations: THREE.AnimationAction[][] = []; - - // models are loaded and inserted into `loadedModel` in indeterminate orders, so we save the index of each model - private modelOrder: number[] = []; - - constructor( - private renderable: Renderable, - private models: string[], - private scale: number, - private verticalOffset, - private originOffset, - ) { - const { size } = renderable; - - this.outlineMaterial = new THREE.LineBasicMaterial({ - color: OUTLINE_NORMAL, - }); - const points = [ - new THREE.Vector3(0, 0, 0), - new THREE.Vector3(size, 0, 0), - new THREE.Vector3(size, 0, 0), - new THREE.Vector3(size, 0, -size), - new THREE.Vector3(size, 0, -size), - new THREE.Vector3(0, 0, -size), - new THREE.Vector3(0, 0, -size), - new THREE.Vector3(0, 0, 0), - ]; - const outlineGeometry = new THREE.BufferGeometry().setFromPoints(points); - this.outline = new THREE.LineSegments(outlineGeometry, this.outlineMaterial); - this.outline.visible = renderable.drawOutline; - const trueTileGeometry = new THREE.BufferGeometry().setFromPoints(points); - this.trueTile = new THREE.LineSegments( - trueTileGeometry, - new THREE.LineBasicMaterial({ - color: OUTLINE_TRUE_TILE, - }), - ); - this.trueTile.visible = renderable.drawTrueTile; - - const hullMaterial = new THREE.MeshBasicMaterial({ color: 0x00000000 }); - hullMaterial.transparent = true; - // size of hull get set once the model loads - this.hullGeometry = new THREE.CylinderGeometry(1, 1, 1, 6); - this.clickHull = new THREE.Mesh(this.hullGeometry, hullMaterial); - this.clickHull.userData.clickable = renderable.selectable; - this.clickHull.userData.unit = renderable; - this.clickHull.visible = false; - } - - async animationChanged(id, blend) { - return this.startPlayingAnimation(id, blend); - } - - modelChanged() { - if (!this.loadedModel) { - return; - } - // TODO: handle model order that gets out of whack - // TODO: what if get3dModel() now returns something other than GLTFModel? Bad times... - const newModels = (this.renderable.get3dModel() as GLTFModel).models; - const toRemove = this.models.filter((model) => !newModels.includes(model)); - const toAdd = newModels.filter((model) => !this.models.includes(model)); - toRemove.forEach((name) => this.loadedModel.remove(this.loadedModel.getObjectByName(name))); - this.models = newModels; - // (index is wrong here...) - toAdd.forEach((name, index) => this.loadAndAddSingleModel(this.loadedModel, name, index)); - } - - stopCurrentAnimation() { - // needed otherwise the animations bleed into each other - this.mixers.forEach((mixer) => mixer.stopAllAction()); - } - - /** - * - * @param id id (in the animation file) to play - * @param blend blend the new animation with the pose animation - */ - startPlayingAnimation(id: number, blend = false) { - if (!blend) { - this.stopCurrentAnimation(); - this.animations.forEach((animationsForModel) => { - animationsForModel.forEach((animation) => animation.setEffectiveWeight(1.0)); - }); - } else { - this.animations.forEach((animationsForModel) => { - animationsForModel.forEach((animation) => animation.setEffectiveWeight(0.5)); - }); - } - this.playingAnimationId = id; - this.playingAnimationCanBlend = blend; - this.animations.forEach((animationsForModel) => { - // play the animation for each part of the body - const newAnimation = animationsForModel[id]; - newAnimation.setEffectiveWeight(blend ? 1 : 1.0); - newAnimation.stop().setLoop(THREE.LoopOnce, 1).play(); - }); - // reset the timer of the mixers because it seems to bug out and show the first frame sometimes - // suspect that it has to do with the mixer time exceeding the length of the animation? - this.mixers.forEach((mixerForModel) => mixerForModel.setTime(0)); - return new Promise((resolve) => { - this.playingAnimationPromiseResolve = resolve; - return; - }); - } - - onAnimationFinished(action?: THREE.AnimationAction) { - this.stopCurrentAnimation(); - const nextAnimIndex = this.renderable.animationIndex; - - this.animations.forEach((animationsForModel, i) => { - const newAnimation = animationsForModel[nextAnimIndex]; - if (this.playingAnimationCanBlend) { - newAnimation.setEffectiveWeight(1.0); - } - // play the fallback/pose animation - newAnimation.stop().setLoop(THREE.LoopRepeat, Number.POSITIVE_INFINITY).play(); - }); - this.playingAnimationId = -1; - this.playingAnimationCanBlend = false; - if (this.playingAnimationPromiseResolve) { - this.playingAnimationPromiseResolve(); - this.playingAnimationPromiseResolve = null; - } - } - - onPoseChanged(newPoseId) { - this.animations.forEach((animationsForModel, i) => { - const lastAnimation = animationsForModel[this.lastPoseId]; - if (lastAnimation) { - lastAnimation.stop(); - } - if (this.playingAnimationId >= 0 && !this.playingAnimationCanBlend) { - return; - } - const newAnimation = animationsForModel[newPoseId]; - // play the fallback/pose animation - newAnimation.stop().setLoop(THREE.LoopRepeat, Number.POSITIVE_INFINITY).play(); - }); - } - - loadAndAddSingleModel(target, model, index) { - const processGltf = (gltf: GLTF, clone = false) => { - const scale = this.scale; - gltf.scene.name = model; - - gltf.scene.traverse((o: any) => { - if (o.isMesh) { - o.material.name = model; - } - }); - // make adjustments - gltf.scene.scale.set(scale, scale, scale); - const { animations } = gltf; - let { scene } = gltf; - if (clone) { - scene = scene.clone(); - } - target.add(scene); - const size = new THREE.Vector3(); - new THREE.Box3().setFromObject(scene).getSize(size); - const clickboxHeight = this.renderable.clickboxHeight ?? Math.max(this.renderable.size, 0.4 * size.y); - const clickboxRadius = this.renderable.clickboxRadius ?? this.renderable.size * 0.4; - this.hullGeometry.scale(clickboxRadius, clickboxHeight, clickboxRadius); - this.hullGeometry.translate(0, clickboxHeight / 2 - 0.49, 0); - // load and start animating - if (animations.length === 0) { - return; - } - const mixer = new THREE.AnimationMixer(scene); - this.mixers.push(mixer); - this.animations.push( - animations.map((animation) => { - const action = mixer.clipAction(animation); - action.clampWhenFinished = true; - action.zeroSlopeAtEnd = false; - action.zeroSlopeAtStart = false; - return action; - }), - ); - this.onAnimationFinished(); - // add listener to first mixer only - if (this.mixers.length === 1) { - mixer.addEventListener("finished", (e) => { - this.onAnimationFinished(e.action); - }); - } - this.modelOrder.push(index); - } - if (model in globalModelCache) { - // prevents reloading the model from file - processGltf(globalModelCache[model], true); - } else { - loader.load(model, (gltf: GLTF) => { - globalModelCache[model] = gltf; - processGltf(gltf); - }); - } - } - - initialiseWholeModel() { - const preparingMesh = new THREE.Object3D(); - this.models.forEach((model, index) => this.loadAndAddSingleModel(preparingMesh, model, index)); - this.loadedModel = preparingMesh; - } - - draw( - scene: THREE.Scene, - clockDelta: number, - tickPercent: number, - location: Location3, - rotation: number, - pitch: number, - visible: boolean, - modelOffsets: Location3[], - ) { - if (!this.hasInitialisedModel) { - this.initialiseWholeModel(); - this.hasInitialisedModel = true; - } - if (this.loadedModel && this.loadedModel.parent !== scene) { - scene.add(this.loadedModel); - this.renderable.setAnimationListener(this); - } - if (this.outline.parent !== scene) { - scene.add(this.outline); - scene.add(this.trueTile); - scene.add(this.clickHull); - } - - this.outline.visible = this.renderable.drawOutline && visible; - if (this.loadedModel) { - this.loadedModel.visible = visible; - } - this.outlineMaterial.color.setHex(this.renderable.selected ? OUTLINE_SELECTED : OUTLINE_NORMAL); - if (this.renderable.selected) { - drawLineOnTop(this.outline); - } else { - drawLineNormally(this.outline); - } - if (this.renderable.animationIndex !== this.lastPoseId) { - // start a new pose if the pose index changes and we're not currently playing an animation - this.onPoseChanged(this.renderable.animationIndex); - this.lastPoseId = this.renderable.animationIndex; - } - - const { x, y, z } = location; - this.outline.position.x = x; - this.outline.position.y = -0.49; - this.outline.position.z = y; - this.outline.visible = this.renderable.drawOutline; - if (this.renderable.drawTrueTile) { - const { x: trueX, y: trueY } = this.renderable.getTrueLocation(); - this.trueTile.position.x = trueX; - this.trueTile.position.y = -0.495; - this.trueTile.position.z = trueY; - } - this.trueTile.visible = this.renderable.drawTrueTile; - - this.clickHull.position.x = x + this.renderable.size / 2; - this.clickHull.position.z = y - this.renderable.size / 2; - - if (this.loadedModel) { - this.mixers.forEach((mixer) => mixer.update(clockDelta)); - - const { size } = this.renderable; - const adjustedRotation = rotation + Math.PI / 2; - this.loadedModel.position.x = x + size / 2 + this.originOffset.x; - this.loadedModel.position.y = z + this.verticalOffset; - this.loadedModel.position.z = y - size / 2 + this.originOffset.y; - this.loadedModel.rotation.order = "YXZ"; - this.loadedModel.rotation.set(pitch, adjustedRotation, 0); - - this.loadedModel.children.forEach((child, idx) => { - const insertionIdx = this.modelOrder[idx]; - if (modelOffsets[insertionIdx]) { - const offset = modelOffsets[insertionIdx]; - child.position.set(offset.x, offset.z, offset.y); - } else { - child.position.set(0, 0, 0); - } - }); - } - } - - destroy(scene: THREE.Scene) { - if (this.loadedModel && this.loadedModel.parent === scene) { - scene.remove(this.loadedModel); - this.renderable.clearAnimationListener(); - } - if (this.outline.parent === scene) { - scene.remove(this.outline); - scene.remove(this.trueTile); - scene.remove(this.clickHull); - } - } - - getWorldPosition(): THREE.Vector3 { - return this.outline.getWorldPosition(new THREE.Vector3()); - } - - private static until(condition: () => boolean) { - const poll = (res) => { - if (condition()) { - res(); - } else { - setTimeout(() => poll(res), 50); - } - }; - return new Promise(poll); - } - - async preload() { - await Promise.all(this.models.map((model) => GLTFModel.preload(model))); - return; - } - - static async preload(model: string) { - const gltf = await loader.loadAsync(model); - const scene = (Viewport.viewport.getDelegate() as Viewport3d).scene; - const camera = new THREE.PerspectiveCamera(); - gltf.scene.scale.set(0.01, 0.01, 0.01); - gltf.scene.position.set(20, 0, 20); - - scene.add(gltf.scene); - camera.position.set(10, 10, 10); - camera.lookAt(gltf.scene.position); - - const renderer = new THREE.WebGLRenderer({ - canvas: new OffscreenCanvas(1, 1), - }); - renderer.setSize(1, 1, false); - let didRender = false; - requestAnimationFrame(() => { - renderer.render(scene, camera); - didRender = true; - }); - await GLTFModel.until(() => didRender); - scene.remove(gltf.scene); - renderer.dispose(); - renderer.forceContextLoss(); - return; - } -} diff --git a/src/sdk/rendering/Model.ts b/src/sdk/rendering/Model.ts deleted file mode 100644 index f6947f73..00000000 --- a/src/sdk/rendering/Model.ts +++ /dev/null @@ -1,22 +0,0 @@ -import * as THREE from "three"; - -import { Location3 } from "../Location"; - -export interface Model { - draw( - scene: THREE.Scene, - clockDelta: number, - tickPercent: number, - location: Location3, - angleRadians: number, - pitchRadians: number, - visible: boolean, - modelOffsets: Location3[], - ); - - destroy(scene: THREE.Scene); - - getWorldPosition(): THREE.Vector3; - - preload(): Promise; -} diff --git a/src/sdk/rendering/PointingModel.ts b/src/sdk/rendering/PointingModel.ts deleted file mode 100644 index 3d99676d..00000000 --- a/src/sdk/rendering/PointingModel.ts +++ /dev/null @@ -1,75 +0,0 @@ -import * as THREE from "three"; -import { Model } from "./Model"; -import { Renderable } from "../Renderable"; -import { Location3 } from "../Location"; - -export class PointingModel implements Model { - static forRenderable(r: Renderable) { - return new PointingModel(r.size, r.height, r.colorHex, r); - } - - private geometry: THREE.BufferGeometry; - private material: THREE.MeshStandardMaterial; - - private arrowHelper: THREE.ArrowHelper; - private mainMesh: THREE.Mesh; - - constructor( - private size: number, - height: number, - color: number, - unit: Renderable | null, - private drawOffset: { x?: number; y?: number; z?: number } = {}, - ) { - this.geometry = new THREE.BoxGeometry(size * 0.6, height, size * 0.6); - this.material = new THREE.MeshStandardMaterial({ color }); - this.mainMesh = new THREE.Mesh(this.geometry, this.material); - this.mainMesh.userData.clickable = unit !== null && unit.selectable; - this.mainMesh.userData.unit = unit; - - // west is 0 degrees - this.arrowHelper = new THREE.ArrowHelper(new THREE.Vector3(1, 0, 0), new THREE.Vector3(0, 0, 0), 1, color); - this.mainMesh.add(this.arrowHelper); - } - - draw( - scene: THREE.Scene, - clockDelta: number, - tickPercent: number, - location: Location3, - pitch: number, - rotation: number, - ) { - if (this.mainMesh.parent !== scene) { - scene.add(this.mainMesh); - } - const size = this.size; - const { x, y, z } = location; - - // conversion from Location3 to Vector3 - // lerp because we only move the perceived location in client ticks - const targetPosition = new THREE.Vector3(x + size / 2, z, y - size / 2).add({ - x: this.drawOffset.x || 0, - y: this.drawOffset.y || 0, - z: this.drawOffset.z || 0, - }); - this.mainMesh.position.lerp(targetPosition, 0.25); - - this.mainMesh.setRotationFromAxisAngle(new THREE.Vector3(0, 1, 0), rotation); - } - - destroy(scene: THREE.Scene) { - if (this.mainMesh.parent === scene) { - scene.remove(this.mainMesh); - } - } - - getWorldPosition(): THREE.Vector3 { - return this.mainMesh.getWorldPosition(new THREE.Vector3()); - } - - async preload() { - // do nothing - return; - } -} diff --git a/src/sdk/rendering/RenderUtils.ts b/src/sdk/rendering/RenderUtils.ts deleted file mode 100644 index d01bec60..00000000 --- a/src/sdk/rendering/RenderUtils.ts +++ /dev/null @@ -1,13 +0,0 @@ -import * as THREE from "three"; - -export const drawLineOnTop = (mesh: THREE.Line) => { - mesh.renderOrder = 999; - (mesh.material as THREE.Material).depthTest = false; - (mesh.material as THREE.Material).transparent = true; -}; - -export const drawLineNormally = (mesh: THREE.Line) => { - mesh.renderOrder = 0; - (mesh.material as THREE.Material).depthTest = true; - (mesh.material as THREE.Material).transparent = false; -}; diff --git a/src/sdk/rendering/TileMarkerModel.ts b/src/sdk/rendering/TileMarkerModel.ts deleted file mode 100644 index b4e31e06..00000000 --- a/src/sdk/rendering/TileMarkerModel.ts +++ /dev/null @@ -1,62 +0,0 @@ -import * as THREE from "three"; -import { Model } from "./Model"; -import { Renderable } from "../Renderable"; -import { Location } from "../Location"; -import { drawLineOnTop } from "./RenderUtils"; - -export class TileMarkerModel implements Model { - static forRenderable(r: Renderable, onTop = true) { - return new TileMarkerModel(r, onTop); - } - - private outline: THREE.LineSegments; - - constructor(private renderable: Renderable, onTop = true) { - const { size } = renderable; - const lineMaterial = new THREE.LineBasicMaterial({ - color: renderable.colorHex, - linewidth: 2, - }); - const points = [ - new THREE.Vector3(0, 0, 0), - new THREE.Vector3(size, 0, 0), - new THREE.Vector3(size, 0, 0), - new THREE.Vector3(size, 0, -size), - new THREE.Vector3(size, 0, -size), - new THREE.Vector3(0, 0, -size), - new THREE.Vector3(0, 0, -size), - new THREE.Vector3(0, 0, 0), - ]; - const geometry = new THREE.BufferGeometry().setFromPoints(points); - this.outline = new THREE.LineSegments(geometry, lineMaterial); - if (onTop) { - drawLineOnTop(this.outline); - } - } - - draw(scene: THREE.Scene, clockDelta: number, tickPercent: number, location: Location) { - if (this.outline.parent !== scene) { - scene.add(this.outline); - } - const { x, y } = location; - this.outline.visible = this.renderable.visible(tickPercent); - this.outline.position.x = x; - this.outline.position.y = -0.49; - this.outline.position.z = y; - } - - destroy(scene: THREE.Scene) { - if (this.outline.parent === scene) { - scene.remove(this.outline); - } - } - - getWorldPosition(): THREE.Vector3 { - return this.outline.getWorldPosition(new THREE.Vector3()); - } - - async preload() { - // do nothing - return; - } -} diff --git a/src/sdk/utils/Assets.ts b/src/sdk/utils/Assets.ts deleted file mode 100644 index 3c5f994b..00000000 --- a/src/sdk/utils/Assets.ts +++ /dev/null @@ -1,48 +0,0 @@ -export class Assets { - static assetCount = 0; - static loadingAssetUrls = []; - static onProgressFns: ((loaded: number, total: number) => void)[] = []; - static onLoadFns: (() => void)[] = []; - - static loadedAssets = {}; - /** - * Returns the appropriate URL for an asset and also schedules it for preloading. - */ - static getAssetUrl(asset: string) { - // TODO switch CDN based on build variable - const url = `https://assets-soltrainer.netlify.app/${asset}`; - //const url = `https://oldschool-cdn.com/${asset}`; - if (Assets.loadedAssets[url]) { - return url; - } - Assets.loadingAssetUrls.push(url); - Assets.assetCount++; - Promise.resolve().then(async () => { - console.debug(`Preloading asset: ${url}`); - const response = await fetch(url); - const bytes = await response.arrayBuffer(); - console.debug(`Preloaded asset: ${url}, ${response.statusText}: ${bytes.byteLength}`); - Assets.onProgressFns.forEach((onProgressFns) => - onProgressFns(this.assetCount - this.loadingAssetUrls.length, this.assetCount), - ); - Assets.loadingAssetUrls = this.loadingAssetUrls.filter((u) => u !== url); - Assets.loadedAssets[url] = true; - }); - return url; - } - - static onAssetProgress(progressFn: (loaded: number, total: number) => void) { - Assets.onProgressFns.push(progressFn); - } - - static onAllAssetsLoaded(loadFn: () => void) { - Assets.onLoadFns.push(loadFn); - } - - static checkAssetsLoaded(timer: NodeJS.Timeout) { - if (Assets.loadingAssetUrls.length === 0) { - Assets.onLoadFns.forEach((onLoadFunction) => onLoadFunction()); - clearInterval(timer); - } - } -} diff --git a/src/sdk/utils/BrowserUtils.ts b/src/sdk/utils/BrowserUtils.ts deleted file mode 100644 index 83d8e68d..00000000 --- a/src/sdk/utils/BrowserUtils.ts +++ /dev/null @@ -1,16 +0,0 @@ -export class BrowserUtils { - static getQueryVar(varName: string): string { - // Grab and unescape the query string - appending an '&' keeps the RegExp simple - // for the sake of this example. - const queryStr = unescape(window.location.search) + "&"; - - // Dynamic replacement RegExp - const regex = new RegExp(".*?[&\\?]" + varName + "=(.*?)&.*"); - - // Apply RegExp to the query string - const val = queryStr.replace(regex, "$1"); - - // If the string is the same, we didn't find a match - return false - return val === queryStr ? "" : val; - } -} diff --git a/src/sdk/utils/ImageLoader.ts b/src/sdk/utils/ImageLoader.ts deleted file mode 100644 index f9aed3ec..00000000 --- a/src/sdk/utils/ImageLoader.ts +++ /dev/null @@ -1,43 +0,0 @@ -export class ImageLoader { - static onLoadFns: (() => void)[] = []; - static pendingImages = 0; - static completedImages = 0; - static hasLoaded = false; - - static imageCache = {}; - - static createImage(src: string): HTMLImageElement { - if (!src) { - return null; - } - - if (this.imageCache[src]) { - return this.imageCache[src]; - } - - ImageLoader.pendingImages++; - const img = new Image(); - img.src = src; - img.addEventListener("load", () => { - ImageLoader.completedImages++; - }); - img.addEventListener("error", () => { - img.src = ""; - img.src = src + "?retry=" + String(Math.random()); - ImageLoader.completedImages++; - }); - this.imageCache[src] = img; - return img; - } - - static onAllImagesLoaded(loadFn: () => void) { - ImageLoader.onLoadFns.push(loadFn); - } - - static checkImagesLoaded(timer: NodeJS.Timeout) { - if (ImageLoader.pendingImages === ImageLoader.completedImages) { - ImageLoader.onLoadFns.forEach((onLoadFunction) => onLoadFunction()); - clearInterval(timer); - } - } -} diff --git a/src/sdk/utils/SoundCache.ts b/src/sdk/utils/SoundCache.ts deleted file mode 100644 index be2d7474..00000000 --- a/src/sdk/utils/SoundCache.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { Settings } from "../Settings"; - -const LOADING_SOUND = null; - -export class Sound { - constructor( - public src, - public volume = 1, - ) {} -} - -export class SoundCache { - static soundCache = {}; - - static context = window.AudioContext ? new AudioContext() : null; - static cachedSounds: { [src: string]: AudioBuffer } = {}; - - static getCachedSound(src: string): HTMLAudioElement { - if (!src) { - return null; - } - - if (this.soundCache[src]) { - return this.soundCache[src]; - } - - return (this.soundCache[src] = new Audio(src)); - } - - static async preload(src: string): Promise { - if (!SoundCache.context) { - return null; - } - if (SoundCache.cachedSounds[src] === LOADING_SOUND) { - return null; - } - SoundCache.cachedSounds[src] = LOADING_SOUND; - const response = await window.fetch(src); - const buffer = await response.arrayBuffer(); - const audioBuffer = await SoundCache.context.decodeAudioData(buffer); - SoundCache.cachedSounds[src] = audioBuffer; - return audioBuffer; - } - - static play({ src, volume }: Sound, isAreaSound = false) { - if (!SoundCache.context) { - return null; - } - if (this.cachedSounds[src] === undefined) { - (async () => { - const sound = await this.preload(src); - // play after loading - if (sound) { - SoundCache.play({ src, volume }); - } - })(); - return; - } - if (!this.cachedSounds[src]) { - return; - } - if ((!isAreaSound && !Settings.playsAudio) || (isAreaSound && !Settings.playsAreaAudio)) { - return; - } - const source = SoundCache.context.createBufferSource(); - source.buffer = this.cachedSounds[src]; - let connect: AudioNode = SoundCache.context.destination; - if (volume !== 1) { - const gainNode = SoundCache.context.createGain(); - gainNode.gain.value = volume; - source.connect(gainNode); - gainNode.connect(SoundCache.context.destination); - connect = gainNode; - } - source.connect(connect); - source.start(); - } -} diff --git a/src/sdk/utils/Text.ts b/src/sdk/utils/Text.ts deleted file mode 100644 index ec105354..00000000 --- a/src/sdk/utils/Text.ts +++ /dev/null @@ -1,46 +0,0 @@ -export type TextSegment = { - text: string; - color?: string; -}; - -type InternalTextSegment = { - text: string; - tag: string | null; - inTag: boolean; -}; - -export const parseText = (text: string): TextSegment[] => { - const segments: InternalTextSegment[] = []; - let currentSegment: InternalTextSegment = { text: "", tag: null, inTag: false }; - for (let i = 0; i < text.length; i++) { - if (text[i] === "<" && !currentSegment.inTag) { - if (currentSegment.text) { - segments.push(currentSegment); - } - currentSegment = { text: "", tag: "", inTag: true }; - } else if (text[i] === "/") { - // closing tag - if (currentSegment.text) { - segments.push(currentSegment); - } - } else if (text[i] === ">") { - currentSegment.inTag = false; - } else if (currentSegment.inTag) { - currentSegment.tag += text[i]; - } else { - currentSegment.text += text[i]; - } - } - if (currentSegment.text) { - segments.push(currentSegment); - } - return segments.map(({text, tag}) => { - const color = parseColor(tag); - return { - text, - ...(color && { color }) - }; -}); -}; - -const parseColor = (tag: string) => (tag?.includes("col=") ? tag.split("=")?.[1] : null); diff --git a/src/sdk/utils/__mocks__/Assets.ts b/src/sdk/utils/__mocks__/Assets.ts deleted file mode 100644 index 82479a62..00000000 --- a/src/sdk/utils/__mocks__/Assets.ts +++ /dev/null @@ -1,5 +0,0 @@ -export class Assets { - static getAssetUrl(x: any) { - return x; - } -} diff --git a/src/sdk/utils/__mocks__/SoundCache.ts b/src/sdk/utils/__mocks__/SoundCache.ts deleted file mode 100644 index 3e70e3a7..00000000 --- a/src/sdk/utils/__mocks__/SoundCache.ts +++ /dev/null @@ -1,15 +0,0 @@ -export class Sound { - constructor( - public src, - public volume = 1, - ) {} -} - -export class SoundCache { - static preload() { - return; - } - static play() { - return; - } -} diff --git a/src/sdk/weapons/AoeRangedWeapon.ts b/src/sdk/weapons/AoeRangedWeapon.ts deleted file mode 100644 index ed9e9529..00000000 --- a/src/sdk/weapons/AoeRangedWeapon.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { RangedWeapon } from "./RangedWeapon"; - -// A Range weapon that can hit any unit in the radius, without requiring direct LOS of the target. -// Example: Dinh's Bulwark, Verzik auto attacks. -export class AoeRangedWeapon extends RangedWeapon { - get isAreaAttack() { - return true; - } -} diff --git a/src/sdk/weapons/BarrageSpell.ts b/src/sdk/weapons/BarrageSpell.ts deleted file mode 100644 index 93018413..00000000 --- a/src/sdk/weapons/BarrageSpell.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { Mob } from "../Mob"; -import { Pathing } from "../Pathing"; -import { Unit } from "../Unit"; -import { MagicWeapon } from "./MagicWeapon"; -import { ProjectileOptions } from "./Projectile"; -import { AttackBonuses } from "../gear/Weapon"; -import { XpDrop } from "../XpDrop"; -import { AttackStyle, AttackStyleTypes } from "../AttackStylesController"; - -export class BarrageSpell extends MagicWeapon { - get aoe() { - return [ - { x: 0, y: 0 }, // always freeze middles first - { x: -1, y: -1 }, - { x: -1, y: 0 }, - { x: -1, y: 1 }, - { x: 0, y: -1 }, - { x: 0, y: 1 }, - { x: 1, y: -1 }, - { x: 1, y: 0 }, - { x: 1, y: 1 }, - ]; - } - get attackRange() { - return 10; - } - - get attackSpeed() { - return 5; - } - - get maxConcurrentHits() { - return 9; - } - - attackStyle() { - return AttackStyle.AUTOCAST; - } - - cast(from: Unit, to: Unit) { - from.grantXp(new XpDrop("magic", 52)); - // calculate AoE magic effects - if (this.aoe.length) { - const alreadyCastedOn: Unit[] = [to]; - this.attack(from, to, { magicBaseSpellDamage: 30, attackStyle: "magic" }); - this.aoe.forEach((point) => { - Pathing.mobsAtAoeOffset(from.region, to, point).forEach((mob: Mob) => { - if (alreadyCastedOn.length > this.maxConcurrentHits) { - return; - } - if (alreadyCastedOn.indexOf(mob) > -1) { - return; - } - alreadyCastedOn.push(mob); - this.attack(from, mob, { magicBaseSpellDamage: 30, attackStyle: "magic" }, { hidden: true }); - }); - }); - } else { - this.attack(from, to, { magicBaseSpellDamage: 30, attackStyle: "magic" }); - } - } - - attack(from: Unit, to: Unit, bonuses: AttackBonuses = {}, options: ProjectileOptions = {}): boolean { - options.forceSWTile = true; - return super.attack(from, to, bonuses, options); - } -} diff --git a/src/sdk/weapons/BloodBarrageSpell.ts b/src/sdk/weapons/BloodBarrageSpell.ts deleted file mode 100644 index 36e8edf2..00000000 --- a/src/sdk/weapons/BloodBarrageSpell.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Unit } from "../Unit"; -import { BarrageSpell } from "./BarrageSpell"; -import { ProjectileOptions } from "./Projectile"; -import { AttackBonuses } from "../gear/Weapon"; -import { ItemName } from "../ItemName"; - -export class BloodBarrageSpell extends BarrageSpell { - get itemName(): ItemName { - return ItemName.BLOOD_BARRAGE; - } - - attack(from: Unit, to: Unit, bonuses: AttackBonuses = {}, options: ProjectileOptions = {}): boolean { - super.attack(from, to, bonuses, options); - if (from.currentStats.hitpoint < from.stats.hitpoint) { - from.currentStats.hitpoint += Math.floor(this.damageRoll * 0.25); - from.currentStats.hitpoint = Math.max(Math.min(from.stats.hitpoint, from.currentStats.hitpoint), 0); - } - return true; - } -} diff --git a/src/sdk/weapons/IceBarrageSpell.ts b/src/sdk/weapons/IceBarrageSpell.ts deleted file mode 100644 index 0779fae9..00000000 --- a/src/sdk/weapons/IceBarrageSpell.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Unit } from "../Unit"; -import { BarrageSpell } from "./BarrageSpell"; -import { ProjectileOptions } from "./Projectile"; -import { AttackBonuses } from "../gear/Weapon"; -import { ItemName } from "../ItemName"; - -export class IceBarrageSpell extends BarrageSpell { - get itemName(): ItemName { - return ItemName.ICE_BARRAGE; - } - - attack(from: Unit, to: Unit, bonuses: AttackBonuses = {}, options: ProjectileOptions = {}): boolean { - super.attack(from, to, bonuses, options); - if (this.lastHitHit) { - to.freeze(32); - } - return true; - } -} diff --git a/src/sdk/weapons/MagicWeapon.ts b/src/sdk/weapons/MagicWeapon.ts deleted file mode 100644 index fc3bc573..00000000 --- a/src/sdk/weapons/MagicWeapon.ts +++ /dev/null @@ -1,142 +0,0 @@ -import { Unit, UnitTypes } from "../Unit"; -import { XpDrop } from "../XpDrop"; -import { ProjectileOptions } from "./Projectile"; -import { AttackBonuses, Weapon } from "../gear/Weapon"; -import { EquipmentTypes } from "../Equipment"; -import { PrayerGroups } from "../BasePrayer"; - -export class MagicWeapon extends Weapon { - - constructor(projectileRules?: ProjectileOptions) { - super(projectileRules); - } - - get type() { - return EquipmentTypes.WEAPON; - } - - attack(from: Unit, to: Unit, bonuses: AttackBonuses = {}, options: ProjectileOptions = {}): boolean { - return super.attack(from, to, bonuses, options); - } - - calculateHitDelay(distance: number) { - return Math.floor((1 + distance) / 3) + 1; - } - - isBlockable(from: Unit, to: Unit, bonuses: AttackBonuses) { - this._calculatePrayerEffects(from, to, bonuses); - - if (bonuses.effectivePrayers.overhead && bonuses.effectivePrayers.overhead.feature() === "magic") { - return true; - } - return false; - } - - _calculatePrayerEffects(from: Unit, to: Unit, bonuses: AttackBonuses) { - bonuses.effectivePrayers = {}; - if (from.type !== UnitTypes.MOB && from.prayerController) { - const offensiveMagic = from.prayerController.matchGroup(PrayerGroups.ACCURACY); - if (offensiveMagic) { - bonuses.effectivePrayers.magic = offensiveMagic; - } - } - if (to.type !== UnitTypes.MOB && to.prayerController) { - const defence = to.prayerController.matchGroup(PrayerGroups.DEFENCE); - if (defence) { - bonuses.effectivePrayers.defence = defence; - } - const overhead = to.prayerController.overhead(); - if (overhead) { - bonuses.effectivePrayers.overhead = overhead; - } - } - } - - _magicLevel(from: Unit, to: Unit, bonuses: AttackBonuses) { - let prayerMultiplier = 1; - const magicPrayer = bonuses.effectivePrayers.magic; - - if (magicPrayer) { - if (magicPrayer.name === "Mystic Will") { - prayerMultiplier = 1.05; - } else if (magicPrayer.name === "Mystic Lore") { - prayerMultiplier = 1.1; - } else if (magicPrayer.name === "Mystic Might") { - prayerMultiplier = 1.15; - } else if (magicPrayer.name === "Augury") { - prayerMultiplier = 1.2; - } - } - return Math.floor( - Math.floor(from.currentStats.magic * prayerMultiplier) * bonuses.voidMultiplier + - (bonuses.isAccurate ? 2 : 0) + - 9, - ); - } - - _equipmentBonus(from: Unit, to: Unit, bonuses: AttackBonuses) { - return from.bonuses.attack.magic; - } - - _magicDamageBonusMultiplier(from: Unit, to: Unit, bonuses: AttackBonuses) { - return from.bonuses.other.magicDamage; - } - - _attackRoll(from: Unit, to: Unit, bonuses: AttackBonuses) { - return Math.floor( - this._magicLevel(from, to, bonuses) * (this._equipmentBonus(from, to, bonuses) + 64) * bonuses.gearMageMultiplier, - ); - } - - _defenceRoll(from: Unit, to: Unit, bonuses: AttackBonuses) { - let prayerMultiplier = 1; - const defencePrayer = bonuses.effectivePrayers.defence; - - if (defencePrayer) { - if (defencePrayer.name === "Thick Skin") { - prayerMultiplier = 1.05; - } else if (defencePrayer.name === "Mystic Will") { - prayerMultiplier = 1.05; - } else if (defencePrayer.name === "Rock Skin") { - prayerMultiplier = 1.1; - } else if (defencePrayer.name === "Mystic Lore") { - prayerMultiplier = 1.1; - } else if (defencePrayer.name === "Steel Skin") { - prayerMultiplier = 1.15; - } else if (defencePrayer.name === "Mystic Might") { - prayerMultiplier = 1.15; - } else if (defencePrayer.name === "Chivalry") { - prayerMultiplier = 1.2; - } else if (defencePrayer.name === "Piety") { - prayerMultiplier = 1.25; - } else if (defencePrayer.name === "Rigour") { - prayerMultiplier = 1.25; - } else if (defencePrayer.name === "Augury") { - prayerMultiplier = 1.25; - } - } - - return (9 + to.currentStats.magic * prayerMultiplier) * (to.bonuses.defence.magic + 64); - } - - _maxHit(from: Unit, to: Unit, bonuses: AttackBonuses) { - return Math.floor(this._baseSpellDamage(from, to, bonuses) * this._magicDamageBonusMultiplier(from, to, bonuses)); - // TODO: Most of this isn't implemented - // Spell Base damage +3 if casting bolt spells with chaos gauntlets - // Answer * (1 + magic damage bonus) - // Round the answer down to the nearest integer - // Answer * salve amulet bonus (Salve bonus does not stack with slayer bonus, skip to step 7 if using salve amulet) - // Round the answer down to the nearest integer - // Answer * slayer bonus - // Round the answer down to the nearest integer - // Answer * Tome of fire bonus - // Round the answer down to the nearest integer - // Answer * castle wars bonus - // Round the answer down to the nearest integer - // That is the max hit - } - - _baseSpellDamage(from: Unit, to: Unit, bonuses: AttackBonuses) { - return bonuses.magicBaseSpellDamage; // Jal-Zek specific number for now. - } -} diff --git a/src/sdk/weapons/MeleeWeapon.ts b/src/sdk/weapons/MeleeWeapon.ts deleted file mode 100644 index bdbb11a6..00000000 --- a/src/sdk/weapons/MeleeWeapon.ts +++ /dev/null @@ -1,170 +0,0 @@ -import { AttackStylesController } from "../AttackStylesController"; -import { PrayerGroups } from "../BasePrayer"; -import { EquipmentTypes } from "../Equipment"; -import { Weapon, AttackBonuses } from "../gear/Weapon"; -import { Unit, UnitTypes } from "../Unit"; -import { ProjectileOptions } from "./Projectile"; - -export class MeleeWeapon extends Weapon { - constructor(projectileOptions: ProjectileOptions = {}) { - super({ - hidden: true, - ...projectileOptions - }); - } - get type() { - return EquipmentTypes.WEAPON; - } - - attack(from: Unit, to: Unit, bonuses: AttackBonuses = {}): boolean { - bonuses.attackStyle = bonuses.attackStyle || "slash"; - return super.attack(from, to, bonuses); - } - - _calculatePrayerEffects(from: Unit, to: Unit, bonuses: AttackBonuses) { - bonuses.effectivePrayers = {}; - if (from.type !== UnitTypes.MOB && from.prayerController) { - const offensiveAttack = from.prayerController.matchGroup(PrayerGroups.ACCURACY); - if (offensiveAttack) { - bonuses.effectivePrayers.attack = offensiveAttack; - } - - const offensiveStrength = from.prayerController.matchGroup(PrayerGroups.STRENGTH); - if (offensiveStrength) { - bonuses.effectivePrayers.strength = offensiveStrength; - } - } - - if (to.type !== UnitTypes.MOB && to.prayerController) { - const defence = to.prayerController.matchGroup(PrayerGroups.DEFENCE); - if (defence) { - bonuses.effectivePrayers.defence = defence; - } - const overhead = to.prayerController.overhead(); - if (overhead) { - bonuses.effectivePrayers.overhead = overhead; - } - } - } - - isBlockable(from: Unit, to: Unit, bonuses: AttackBonuses) { - this._calculatePrayerEffects(from, to, bonuses); - - let prayerAttackBlockStyle = bonuses.attackStyle; - if (Weapon.isMeleeAttackStyle(prayerAttackBlockStyle)) { - prayerAttackBlockStyle = "melee"; // because protect melee scans for the style as melee, generalize them - } - - if (bonuses.effectivePrayers.overhead && bonuses.effectivePrayers.overhead.feature() === prayerAttackBlockStyle) { - return true; - } - return false; - } - - _strengthLevel(from: Unit, to: Unit, bonuses: AttackBonuses) { - let prayerMultiplier = 1; - const strengthPrayer = bonuses.effectivePrayers.strength; - - if (strengthPrayer) { - if (strengthPrayer.name === "Burst of Strength") { - prayerMultiplier = 1.05; - } else if (strengthPrayer.name === "Superhuman Strength") { - prayerMultiplier = 1.1; - } else if (strengthPrayer.name === "Ultimate Strength") { - prayerMultiplier = 1.15; - } else if (strengthPrayer.name === "Chivalry") { - prayerMultiplier = 1.18; - } else if (strengthPrayer.name === "Piety") { - prayerMultiplier = 1.23; - } - } - - if (from.type === UnitTypes.PLAYER) { - bonuses.styleStrengthBonus = AttackStylesController.controller.getWeaponStrengthBonus(this.attackStyle()); - } else { - bonuses.styleStrengthBonus = 0; - } - return Math.floor( - (Math.floor(from.currentStats.strength * prayerMultiplier) + bonuses.styleStrengthBonus + 8) * bonuses.voidMultiplier, - ); - } - - _maxHit(from: Unit, to: Unit, bonuses: AttackBonuses) { - return Math.floor( - Math.floor((this._strengthLevel(from, to, bonuses) * (from.bonuses.other.meleeStrength + 64) + 320) / 640) * - bonuses.gearMeleeMultiplier * - bonuses.overallMultiplier, - ); - } - - _attackLevel(from: Unit, to: Unit, bonuses: AttackBonuses) { - const attackPrayer = bonuses.effectivePrayers.attack; - let prayerMultiplier = 1; - if (attackPrayer) { - if (attackPrayer.name === "Clarity of Thought") { - prayerMultiplier = 1.05; - } else if (attackPrayer.name === "Improved Reflexes") { - prayerMultiplier = 1.1; - } else if (attackPrayer.name === "Incredible Reflexes") { - prayerMultiplier = 1.15; - } else if (attackPrayer.name === "Chivalry") { - prayerMultiplier = 1.15; - } else if (attackPrayer.name === "Piety") { - prayerMultiplier = 1.2; - } - } - - return Math.floor( - (Math.floor(from.currentStats.attack * prayerMultiplier) + bonuses.styleBonus + 8) * bonuses.voidMultiplier, - ); - } - - _attackRoll(from: Unit, to: Unit, bonuses: AttackBonuses) { - return Math.floor( - this._attackLevel(from, to, bonuses) * - (from.bonuses.attack[bonuses.attackStyle] + 64) * - bonuses.gearMeleeMultiplier, - ); - } - - _defenceRoll(from: Unit, to: Unit, bonuses: AttackBonuses) { - if (to.type === UnitTypes.MOB || to.type === UnitTypes.ENTITY) { - return (to.currentStats.defence + 9) * (to.bonuses.defence[bonuses.attackStyle] + 64); - } else { - return this._defenceLevel(from, to, bonuses) * (to.bonuses.defence[bonuses.attackStyle] + 64); - } - } - - _defenceLevel(from: Unit, to: Unit, bonuses: AttackBonuses) { - const defencePrayer = bonuses.effectivePrayers.defence; - let prayerMultiplier = 1; - if (defencePrayer) { - if (defencePrayer.name === "Thick Skin") { - prayerMultiplier = 1.05; - } else if (defencePrayer.name === "Mystic Will") { - prayerMultiplier = 1.05; - } else if (defencePrayer.name === "Rock Skin") { - prayerMultiplier = 1.1; - } else if (defencePrayer.name === "Mystic Lore") { - prayerMultiplier = 1.1; - } else if (defencePrayer.name === "Steel Skin") { - prayerMultiplier = 1.15; - } else if (defencePrayer.name === "Mystic Might") { - prayerMultiplier = 1.15; - } else if (defencePrayer.name === "Chivalry") { - prayerMultiplier = 1.2; - } else if (defencePrayer.name === "Piety") { - prayerMultiplier = 1.25; - } else if (defencePrayer.name === "Rigour") { - prayerMultiplier = 1.25; - } else if (defencePrayer.name === "Augury") { - prayerMultiplier = 1.25; - } - } - return Math.floor(from.currentStats.defence * prayerMultiplier) + bonuses.styleBonus + 8; - } - - get isMeleeAttack() { - return true; - } -} diff --git a/src/sdk/weapons/Projectile.ts b/src/sdk/weapons/Projectile.ts deleted file mode 100644 index cfd5bc30..00000000 --- a/src/sdk/weapons/Projectile.ts +++ /dev/null @@ -1,408 +0,0 @@ -"use strict"; - -import chebyshev from "chebyshev"; -import { Location, Location3 } from "../Location"; -import { Unit } from "../Unit"; -import { Weapon } from "../gear/Weapon"; -import { Sound, SoundCache } from "../utils/SoundCache"; -import { Renderable } from "../Renderable"; -import { Pathing } from "../Pathing"; -import { BasicModel } from "../rendering/BasicModel"; -import { GLTFModel } from "../rendering/GLTFModel"; -import { Collision } from "../Collision"; -import { Settings } from "../Settings"; -import { Viewport } from "../Viewport"; - -export interface ProjectileMotionInterpolator { - interpolate(from: Location3, to: Location3, percent: number): Location3; - interpolatePitch(from: Location3, to: Location3, percent: number): number; -} - -export interface MultiModelProjectileOffsetInterpolator { - // when there are multiple models, offset them by this much. Note that the projectile is already rotated towards - // the target, so the X axis offsets the models left-to-right, and Y axis offsets the models forward-and-back. - interpolateOffsets(from: Location3, to: Location3, percent: number): Location3[]; -} - -export interface ProjectileOptions { - forceSWTile?: boolean; - hidden?: boolean; - // if true, check prayer on landing rather than attack time - checkPrayerAtHit?: boolean; - // overrides reduceDelay - setDelay?: number; - reduceDelay?: number; - cancelOnDeath?: boolean; - color?: string; - size?: number; - motionInterpolator?: ProjectileMotionInterpolator; - // ticks until the projectile appears - visualDelayTicks?: number; - // ticks before actually landing that the projectile hits the target. can be negative in which the projectile - // 'lands' after the projectile hits - visualHitEarlyTicks?: number; - // played when the attack starts - sound?: Sound; - // played when the projectile is launched - projectileSound?: Sound; - // played when the projectile lands - hitSound?: Sound; - model?: string; - modelScale?: number; - // if there are multiple models - models?: string[]; - offsetsInterpolator?: MultiModelProjectileOffsetInterpolator; - // offset of start height - verticalOffset?: number; -} - -const targetIsLocation = (x: Unit | Location): x is Location => (x as Location).x !== undefined; -export class Projectile extends Renderable { - damage: number; - from: Unit; - to: Unit | Location3; - distance: number; - options: ProjectileOptions = {}; - remainingDelay: number; - totalDelay: number; - age = 0; - startLocation: Location; - currentLocation: Location; - currentHeight: number; - attackStyle: string; - - offsetX: number; - offsetY: number; - image: HTMLImageElement; - - interpolator: ProjectileMotionInterpolator; - - _color: string; - _size: number; - - /* - This should take the player and mob object, and do chebyshev on the size of them - */ - constructor( - private weapon: Weapon | null, - damage: number, - from: Unit, - to: Unit | Location3, - attackStyle: string, - options: ProjectileOptions = {}, - ) { - super(); - this.attackStyle = attackStyle; - if (Number.isNaN(damage)) { - throw new Error(`invalid damage value ${damage}`); - } - this.damage = Math.floor(damage); - if (!targetIsLocation(to) && this.damage > to.currentStats.hitpoint) { - this.damage = to.currentStats.hitpoint; - } - this.options = { - checkPrayerAtHit: false, - modelScale: 1.0, - verticalOffset: 0.0, - visualDelayTicks: 0, - visualHitEarlyTicks: 0, - ...options, - }; - this.startLocation = { - x: from.location.x + (from.size - 1) / 2, - y: from.location.y - (from.size - 1) / 2, - }; - this.currentLocation = { ...this.startLocation }; - this.currentHeight = from.height * 0.75 + this.options.verticalOffset; // projectile origin - this.from = from; - this.to = to; - this.distance = 999999; - - if (!weapon || Weapon.isMeleeAttackStyle(attackStyle)) { - this.distance = 0; - this.remainingDelay = 1; - } else if (weapon) { - if (weapon.image) { - this.image = weapon.image; - } - - if (options.forceSWTile) { - // Things like ice barrage calculate distance to SW tile only - const targetSW = targetIsLocation(to) ? to : to.location; - this.distance = chebyshev([this.from.location.x, this.from.location.y], [targetSW.x, targetSW.y]); - } else if (targetIsLocation(to)) { - const closestTile = to; - const closestTileFrom = from.getClosestTileTo(to.x, to.y); - this.distance = chebyshev([closestTileFrom[0], closestTileFrom[1]], [closestTile[0], closestTile[1]]); - } else { - const closestTile = to.getClosestTileTo(this.from.location.x, this.from.location.y); - const closestTileFrom = from.getClosestTileTo(to.location.x, to.location.y); - this.distance = chebyshev([closestTileFrom[0], closestTileFrom[1]], [closestTile[0], closestTile[1]]); - } - - this.remainingDelay = weapon.calculateHitDelay(this.distance); - if (from.isPlayer) { - this.remainingDelay++; - } - if (this.options.reduceDelay) { - this.remainingDelay -= this.options.reduceDelay; - if (this.remainingDelay < 1) { - this.remainingDelay = 1; - } - } - } - - this.checkSound(this.options.projectileSound, this.options.visualDelayTicks); - this.checkSound(this.options.sound, 0); - - this.remainingDelay = options.setDelay || this.remainingDelay; - this.totalDelay = this.remainingDelay; - - this._color = this.options.color || this.getColor(); - this._size = this.options.size || 0.5; - - if (this.options.motionInterpolator) { - this.interpolator = this.options.motionInterpolator; - } else { - this.interpolator = new LinearProjectileMotionInterpolator(); - } - } - - private isMeleeStyle() { - return this.attackStyle === "slash" || this.attackStyle === "crush" || this.attackStyle === "stab"; - } - - private getColor() { - if (this.isMeleeStyle()) { - return "#FF0000"; - } else if (this.attackStyle === "range") { - return "#00FF00"; - } else if (this.attackStyle === "magic") { - return "#0000FF"; - } else if (this.attackStyle === "heal") { - return "#9813aa"; - } else if (this.attackStyle === "recoil") { - return "#000000"; - } - console.log("[WARN] This style is not accounted for in custom coloring: ", this.attackStyle); - return "#000000"; - } - - getTargetDestination(tickPercent): Location3 { - if (targetIsLocation(this.to)) { - return this.to; - } - const { x: toX, y: toY } = this.to.getPerceivedLocation(tickPercent); - const endHeight = this.to.height * 0.5; - const targetSize = this.to.size; - - const x = toX + (targetSize - 1) / 2; - const y = toY - (targetSize - 1) / 2; - - return { x, y, z: endHeight }; - } - - getPerceivedRotation(tickPercent) { - const startX = this.startLocation.x; - const startY = this.startLocation.y; - const { x: endX, y: endY } = this.getTargetDestination(tickPercent); - return -Pathing.angle(startX, startY, endX, endY); - } - - getPerceivedPitch(tickPercent: number) { - // pass in the CENTERED position of the projectile` - const startX = this.startLocation.x; - const startY = this.startLocation.y; - const startHeight = this.currentHeight; - const { x: endX, y: endY, z: endHeight } = this.getTargetDestination(tickPercent); - const percent = this.getPercent(tickPercent); - return this.interpolator.interpolatePitch( - { x: startX, y: startY, z: startHeight }, - { x: endX, y: endY, z: endHeight }, - percent, - ); - } - - private getPercent(tickPercent: number) { - const numerator = this.age - this.options.visualDelayTicks + tickPercent; - const denominator = this.totalDelay - this.options.visualDelayTicks - this.options.visualHitEarlyTicks; - // special case for short lifetime projectiles - we let it appear early - if (denominator <= 0 && this.age >= this.options.visualDelayTicks - 1) { - return tickPercent; - } - return numerator / denominator; - } - - checkSound(sound: Sound, delay: number) { - if (Settings.playsAudio && sound && this.age === delay) { - const player = Viewport.viewport.player; - // projectiles launched at the player always play at full volume - let volumeRatio = - this.from === player || this.to === player - ? 1.0 - : 1 / - Pathing.dist( - Viewport.viewport.player.location.x, - Viewport.viewport.player.location.y, - this.startLocation.x, - this.startLocation.y, - ); - volumeRatio = Math.min(1, Math.max(0, Math.sqrt(volumeRatio))); - SoundCache.play({ - src: sound.src, - volume: volumeRatio * sound.volume, - }); - } - } - - onTick() { - const targetLocation = this.getTargetDestination(0.0); - this.currentLocation = { - x: Pathing.linearInterpolation(this.currentLocation.x, targetLocation.x, 1 / (this.remainingDelay + 1)), - y: Pathing.linearInterpolation(this.currentLocation.y, targetLocation.y, 1 / (this.remainingDelay + 1)), - }; - this.remainingDelay--; - this.age++; - this.checkSound(this.options.projectileSound, this.options.visualDelayTicks); - } - - // called as the projectile lands but before damage is calculated - beforeHit() { - if (this.options.hitSound) { - SoundCache.play(this.options.hitSound); - } - if (!targetIsLocation(this.to) && this.options.checkPrayerAtHit && this.weapon?.isBlockable(this.from, this.to, { attackStyle: this.attackStyle })) { - this.damage = 0; - } - } - - shouldDestroy() { - return this.age >= this.totalDelay + Math.max(0, -this.options.visualHitEarlyTicks); - } - - visible(tickPercent) { - const percent = this.getPercent(tickPercent); - return percent > 0 && percent <= 1; - } - - getPerceivedLocation(tickPercent: number) { - const startX = this.startLocation.x; - const startY = this.startLocation.y; - const startHeight = this.currentHeight; - const { x: endX, y: endY, z: endHeight } = this.getTargetDestination(tickPercent); - const percent = this.getPercent(tickPercent); - return this.interpolator.interpolate( - { x: startX, y: startY, z: startHeight }, - { x: endX, y: endY, z: endHeight }, - percent, - ); - } - - getPerceivedOffsets(tickPercent: number): Location3[] { - if (this.options.offsetsInterpolator) { - const startX = this.startLocation.x; - const startY = this.startLocation.y; - const startHeight = this.currentHeight; - const { x: endX, y: endY, z: endHeight } = this.getTargetDestination(tickPercent); - const percent = this.getPercent(tickPercent); - return this.options.offsetsInterpolator.interpolateOffsets( - { x: startX, y: startY, z: startHeight }, - { x: endX, y: endY, z: endHeight }, - percent, - ); - } - return super.getPerceivedOffsets(tickPercent); - } - - getTrueLocation() { - return this.getPerceivedLocation(0); - } - - get size(): number { - return this._size; - } - - get color(): string { - return this._color; - } - - get drawOutline() { - return false; - } - - protected create3dModel() { - if (this.options.hidden || !this.attackStyle || this.color === "#000000") { - return null; - } - if (this.options.models) { - return GLTFModel.forRenderableMulti(this, this.options.models, this.options.modelScale, 0); - } - if (this.options.model) { - return GLTFModel.forRenderable(this, this.options.model, this.options.modelScale, 0); - } - return BasicModel.sphereForRenderable(this); - } - - get animationIndex() { - return 0; - } -} - -export class LinearProjectileMotionInterpolator implements ProjectileMotionInterpolator { - interpolate(from: Location3, to: Location3, percent: number) { - // default linear - const startX = from.x; - const startY = from.y; - const startHeight = from.z; - const endX = to.x; - const endY = to.y; - const endHeight = to.z; - - const perceivedX = Pathing.linearInterpolation(startX, endX, percent); - const perceivedY = Pathing.linearInterpolation(startY, endY, percent); - const perceivedHeight = - startHeight === endHeight ? startHeight : Pathing.linearInterpolation(startHeight, endHeight, percent); - return { x: perceivedX, y: perceivedY, z: perceivedHeight }; - } - - interpolatePitch(from: Location3, to: Location3, percent: number) { - return 0; - } -} - -export class ArcProjectileMotionInterpolator implements ProjectileMotionInterpolator { - constructor(private height: number) {} - - interpolate(from: Location3, to: Location3, percent: number) { - const startX = from.x; - const startY = from.y; - const startHeight = from.z; - const endX = to.x; - const endY = to.y; - const endHeight = to.z; - - const perceivedX = Pathing.linearInterpolation(startX, endX, percent); - const perceivedY = Pathing.linearInterpolation(startY, endY, percent); - const perceivedHeight = - Math.sin(percent * Math.PI) * this.height + (endHeight - startHeight) * percent + startHeight; - return { x: perceivedX, y: perceivedY, z: perceivedHeight }; - } - - interpolatePitch(from: Location3, to: Location3, percent: number) { - return Math.sin(-(0.75 + percent * 0.5) * Math.PI); - } -} - -// Simply sticks to the target -export class FollowTargetInterpolator implements ProjectileMotionInterpolator { - interpolate(from: Location3, to: Location3, percent: number) { - const endX = to.x; - const endY = to.y; - const endHeight = to.z; - return { x: endX, y: endY, z: endHeight }; - } - - interpolatePitch(from: Location3, to: Location3, percent: number) { - return 0; - } -} diff --git a/src/sdk/weapons/RangedWeapon.ts b/src/sdk/weapons/RangedWeapon.ts deleted file mode 100644 index cbe096b1..00000000 --- a/src/sdk/weapons/RangedWeapon.ts +++ /dev/null @@ -1,152 +0,0 @@ -import { Unit, UnitTypes } from "../Unit"; -import { Projectile, ProjectileOptions } from "./Projectile"; -import { AttackBonuses, Weapon } from "../gear/Weapon"; -import { EquipmentTypes } from "../Equipment"; -import { AttackStylesController } from "../AttackStylesController"; -import { PrayerGroups } from "../BasePrayer"; - -export class RangedWeapon extends Weapon { - get type() { - return EquipmentTypes.WEAPON; - } - - registerProjectile(from: Unit, to: Unit, bonuses: AttackBonuses, options: ProjectileOptions = {}) { - to.addProjectile( - new Projectile(this, this.damage, from, to, "range", { - sound: this.attackSound, - hitSound: this.attackLandingSound, - model: this.projectileModel, - ...this.projectileOptions, - ...options, - }), - ); - } - - calculateHitDelay(distance: number) { - return Math.floor((3 + distance) / 6) + 1; - } - - _calculatePrayerEffects(from: Unit, to: Unit, bonuses: AttackBonuses) { - bonuses.effectivePrayers = {}; - - if (from.type !== UnitTypes.MOB && from.prayerController) { - const offensiveRange = from.prayerController.matchGroup(PrayerGroups.ACCURACY); - if (offensiveRange) { - bonuses.effectivePrayers.range = offensiveRange; - } - } - if (to.type !== UnitTypes.MOB && to.prayerController) { - const defence = to.prayerController.matchGroup(PrayerGroups.DEFENCE); - if (defence) { - bonuses.effectivePrayers.defence = defence; - } - const overhead = to.prayerController.overhead(); - if (overhead) { - bonuses.effectivePrayers.overhead = overhead; - } - } - } - - isBlockable(from: Unit, to: Unit, bonuses: AttackBonuses) { - this._calculatePrayerEffects(from, to, bonuses); - - if (bonuses.effectivePrayers.overhead && bonuses.effectivePrayers.overhead.feature() === "range") { - return true; - } - return false; - } - - _rangedAttack(from: Unit, to: Unit, bonuses: AttackBonuses) { - let prayerMultiplier = 1; - const rangePrayer = bonuses.effectivePrayers.range; - - if (rangePrayer) { - if (rangePrayer.name === "Sharp Eye") { - prayerMultiplier = 1.05; - } else if (rangePrayer.name === "Hawk Eye") { - prayerMultiplier = 1.1; - } else if (rangePrayer.name === "Eagle Eye") { - prayerMultiplier = 1.15; - } else if (rangePrayer.name === "Rigour") { - prayerMultiplier = 1.2; - } - } - - return ( - Math.floor(Math.floor(from.currentStats.range) * prayerMultiplier + (bonuses.isAccurate ? 3 : 0) + 8) * - bonuses.voidMultiplier - ); - } - - _maxHit(from: Unit, to: Unit, bonuses: AttackBonuses) { - let prayerMultiplier = 1; - const rangePrayer = bonuses.effectivePrayers.range; - if (rangePrayer) { - if (rangePrayer.name === "Sharp Eye") { - prayerMultiplier = 1.05; - } else if (rangePrayer.name === "Hawk Eye") { - prayerMultiplier = 1.1; - } else if (rangePrayer.name === "Eagle Eye") { - prayerMultiplier = 1.15; - } else if (rangePrayer.name === "Rigour") { - prayerMultiplier = 1.23; - } - } - const rangedStrength = - Math.floor(Math.floor(from.currentStats.range) * prayerMultiplier + (bonuses.isAccurate ? 3 : 0) + 8) * - bonuses.voidMultiplier; - const max = Math.floor( - Math.floor( - 0.5 + ((rangedStrength * (from.bonuses.other.rangedStrength + 64)) / 640) * bonuses.gearRangeMultiplier, - ) * this._damageMultiplier(from, to, bonuses), - ); - return max; - } - - _attackRoll(from: Unit, to: Unit, bonuses: AttackBonuses) { - return Math.floor( - Math.floor( - this._rangedAttack(from, to, bonuses) * (from.bonuses.attack.range + 64) * bonuses.gearRangeMultiplier, - ) * this._accuracyMultiplier(from, to, bonuses), - ); - } - - _defenceRoll(from: Unit, to: Unit, bonuses: AttackBonuses) { - let prayerMultiplier = 1; - const defencePrayer = bonuses.effectivePrayers.defence; - - if (defencePrayer) { - if (defencePrayer.name === "Thick Skin") { - prayerMultiplier = 1.05; - } else if (defencePrayer.name === "Mystic Will") { - prayerMultiplier = 1.05; - } else if (defencePrayer.name === "Rock Skin") { - prayerMultiplier = 1.1; - } else if (defencePrayer.name === "Mystic Lore") { - prayerMultiplier = 1.1; - } else if (defencePrayer.name === "Steel Skin") { - prayerMultiplier = 1.15; - } else if (defencePrayer.name === "Mystic Might") { - prayerMultiplier = 1.15; - } else if (defencePrayer.name === "Chivalry") { - prayerMultiplier = 1.2; - } else if (defencePrayer.name === "Piety") { - prayerMultiplier = 1.25; - } else if (defencePrayer.name === "Rigour") { - prayerMultiplier = 1.25; - } else if (defencePrayer.name === "Augury") { - prayerMultiplier = 1.25; - } - } - - return (to.currentStats.defence * prayerMultiplier + 9) * (to.bonuses.defence.range + 64); - } - - _accuracyMultiplier(from: Unit, to: Unit, bonuses: AttackBonuses) { - return 1; // Used for tbow passive effect - } - - _damageMultiplier(from: Unit, to: Unit, bonuses: AttackBonuses) { - return 1; // Used for tbow passive effect - } -} diff --git a/test/setupFiles.ts b/test/setupFiles.ts index 2a4176de..6985fdbb 100644 --- a/test/setupFiles.ts +++ b/test/setupFiles.ts @@ -1,50 +1,5 @@ /* eslint-disable @typescript-eslint/no-empty-function */ -jest.mock("../src/sdk/ControlPanelController"); -jest.mock("../src/sdk/MapController"); -jest.mock("../src/sdk/XpDropController"); -jest.mock("../src/sdk/utils/Assets"); -jest.mock("../src/sdk/utils/SoundCache"); -jest.mock("three", () => ({ - Scene: class Scene { - public add(): void { - return; - } - }, - WebGLRenderer: class WebGlRenderer { - public render(): void { - return; - } - public setSize(): void { - return; - } - }, - GLTFLoader: class GLTFLoader { - constructor() {} - setMeshoptDecoder() {} - }, -})); -import { Random } from "../src/sdk/Random"; -import { Settings } from "../src/sdk/Settings"; +import { setupTests } from "@supalosa/oldschool-trainer-sdk"; -jest.spyOn(document, "getElementById").mockImplementation((elementId: string) => { - const c = document.createElement("canvas"); - c.ariaLabel = elementId; - return c; -}); - -const nextRandom = []; - -export const forceRandom = (value: number) => { - nextRandom.push(value); -}; - -Random.setRandom(() => { - if (nextRandom.length > 0) { - return nextRandom.shift(); - } - Random.memory = (Random.memory + 13.37) % 180; - return Math.abs(Math.sin(Random.memory * 0.0174533)); -}); - -Settings.readFromStorage(); +setupTests(); \ No newline at end of file diff --git a/test/simulations/Drag.test.ts b/test/simulations/Drag.test.ts deleted file mode 100644 index 2e187688..00000000 --- a/test/simulations/Drag.test.ts +++ /dev/null @@ -1,179 +0,0 @@ -import { Player } from "../../src/sdk/Player"; -import { World } from "../../src/sdk/World"; -import { Viewport } from "../../src/sdk/Viewport"; -import { Wall } from "../../src/content/Wall"; -import { InvisibleMovementBlocker } from "../../src/content/MovementBlocker"; -import { InfernoPillar } from "../../src/content/inferno/js/InfernoPillar"; -import { JalXil } from "../../src/content/inferno/js/mobs/JalXil"; -import { TestRegion } from "../utils/TestRegion"; - - -// check that we accurately drag around pillars in the expected direction -describe("drag tests", () => { - let region: TestRegion; - let world: World; - - beforeEach(() => { - region = new TestRegion(51, 57); - world = new World(); - region.world = world; - world.addRegion(region); - - for (let x = 10; x < 41; x++) { - region.addEntity(new InvisibleMovementBlocker(region, { x, y: 13 })); - region.addEntity(new InvisibleMovementBlocker(region, { x, y: 44 })); - } - for (let y = 14; y < 44; y++) { - region.addEntity(new InvisibleMovementBlocker(region, { x: 10, y })); - region.addEntity(new InvisibleMovementBlocker(region, { x: 40, y })); - } - - region.addEntity(new Wall(region, { x: 21, y: 8 })); - region.addEntity(new Wall(region, { x: 21, y: 7 })); - region.addEntity(new Wall(region, { x: 21, y: 6 })); - region.addEntity(new Wall(region, { x: 21, y: 5 })); - region.addEntity(new Wall(region, { x: 21, y: 4 })); - region.addEntity(new Wall(region, { x: 21, y: 3 })); - region.addEntity(new Wall(region, { x: 21, y: 2 })); - region.addEntity(new Wall(region, { x: 21, y: 1 })); - region.addEntity(new Wall(region, { x: 21, y: 0 })); - region.addEntity(new Wall(region, { x: 29, y: 8 })); - region.addEntity(new Wall(region, { x: 29, y: 7 })); - region.addEntity(new Wall(region, { x: 29, y: 6 })); - region.addEntity(new Wall(region, { x: 29, y: 5 })); - region.addEntity(new Wall(region, { x: 29, y: 4 })); - region.addEntity(new Wall(region, { x: 29, y: 3 })); - region.addEntity(new Wall(region, { x: 29, y: 2 })); - region.addEntity(new Wall(region, { x: 29, y: 1 })); - region.addEntity(new Wall(region, { x: 29, y: 0 })); - - region.addEntity(new InfernoPillar(region, { x: 28, y: 21 })); - - Viewport.setupViewport(region, true); - }); - - test("drag east when clicking front npc", () => { - // player is right up against the pillar and clicks front 3x3 npc - const player = new Player(region, { x: 29, y: 18 }); - region.addPlayer(player); - Viewport.viewport.setPlayer(player); - - const jalxil = new JalXil(region, { x: 29, y: 24 }, { aggro: player }); - region.addMob(jalxil); - - player.setAggro(jalxil); - - expect(player.location).toEqual({ x: 29, y: 18 }); - world.tickWorld(); - // jal xil didn't move - expect(jalxil.location).toEqual({ x: 29, y: 24 }); - expect(player.pathTargetLocation).toEqual({ x: 31, y: 21 }); - expect(player.location).toEqual({ x: 31, y: 18 }); - }); - - test("drag forward and east when clicking front npc from one tile back", () => { - // player is one tile back from the pillar and clicks front 3x3 npc - const player = new Player(region, { x: 29, y: 17 }); - region.addPlayer(player); - Viewport.viewport.setPlayer(player); - - const jalxil = new JalXil(region, { x: 29, y: 24 }, { aggro: player }); - region.addMob(jalxil); - - player.setAggro(jalxil); - - expect(player.location).toEqual({ x: 29, y: 17 }); - world.tickWorld(); - // jal xil didn't move - expect(jalxil.location).toEqual({ x: 29, y: 24 }); - expect(player.pathTargetLocation).toEqual({ x: 31, y: 21 }); - expect(player.location).toEqual({ x: 31, y: 18 }); - }); - - test("drag forward and east twice when clicking front npc from three tiles back", () => { - // player is three tiles back from the pillar and clicks front 3x3 npc - const player = new Player(region, { x: 29, y: 15 }); - region.addPlayer(player); - Viewport.viewport.setPlayer(player); - - const jalxil = new JalXil(region, { x: 29, y: 24 }, { aggro: player }); - region.addMob(jalxil); - - player.setAggro(jalxil); - - expect(player.location).toEqual({ x: 29, y: 15 }); - world.tickWorld(); - expect(jalxil.location).toEqual({ x: 29, y: 24 }); - // player steps forward and east one tile - expect(player.location).toEqual({ x: 30, y: 17 }); - expect(player.pathTargetLocation).toEqual({ x: 31, y: 21 }); - world.tickWorld(); - // jal xil moves to follow one tick later - expect(jalxil.location).toEqual({ x: 30, y: 24 }); - expect(player.location).toEqual({ x: 31, y: 19 }); - }); - - test("drag west when clicking back npc", () => { - // player is right up against the pillar and clicks back 3x3 npc - const player = new Player(region, { x: 29, y: 18 }); - region.addPlayer(player); - Viewport.viewport.setPlayer(player); - - region.addMob(new JalXil(region, { x: 29, y: 24 }, { aggro: player })); - const backJalXil = new JalXil(region, { x: 29, y: 27 }, { aggro: player }); - region.addMob(backJalXil); - - player.setAggro(backJalXil); - - expect(player.location).toEqual({ x: 29, y: 18 }); - world.tickWorld(); - // jal xil didn't move - expect(backJalXil.location).toEqual({ x: 29, y: 27 }); - expect(player.pathTargetLocation).toEqual({ x: 29, y: 24 }); - expect(player.location).toEqual({ x: 27, y: 18 }); - world.tickWorld(); - expect(backJalXil.location).toEqual({ x: 28, y: 27 }); - }); - - test("drag forward and west when clicking back npc from one tile back", () => { - // player is 1 tile back against the pillar and clicks back 3x3 npc - const player = new Player(region, { x: 29, y: 17 }); - region.addPlayer(player); - Viewport.viewport.setPlayer(player); - - region.addMob(new JalXil(region, { x: 29, y: 24 }, { aggro: player })); - const backJalXil = new JalXil(region, { x: 29, y: 27 }, { aggro: player }); - region.addMob(backJalXil); - - player.setAggro(backJalXil); - - expect(player.location).toEqual({ x: 29, y: 17 }); - world.tickWorld(); - // jal xil didn't move - expect(backJalXil.location).toEqual({ x: 29, y: 27 }); - expect(player.pathTargetLocation).toEqual({ x: 29, y: 24 }); - expect(player.location).toEqual({ x: 27, y: 18 }); - world.tickWorld(); - expect(backJalXil.location).toEqual({ x: 28, y: 27 }); - }); - - test("drag forward and west twice when clicking back npc from three tiles back", () => { - // player is tile back against the pillar and clicks back 3x3 npc - const player = new Player(region, { x: 29, y: 15 }); - region.addPlayer(player); - Viewport.viewport.setPlayer(player); - - region.addMob(new JalXil(region, { x: 29, y: 24 }, { aggro: player })); - const backJalXil = new JalXil(region, { x: 29, y: 27 }, { aggro: player }); - region.addMob(backJalXil); - - player.setAggro(backJalXil); - - expect(player.location).toEqual({ x: 29, y: 15 }); - world.tickWorld(); - expect(player.location).toEqual({ x: 28, y: 17 }); - expect(player.pathTargetLocation).toEqual({ x: 29, y: 24 }); - world.tickWorld(); - expect(player.location).toEqual({ x: 27, y: 19 }); - }); -}); diff --git a/test/simulations/InfernoRanger.test.ts b/test/simulations/InfernoRanger.test.ts deleted file mode 100644 index a8dd36ff..00000000 --- a/test/simulations/InfernoRanger.test.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { JalXil } from "../../src/content/inferno/js/mobs/JalXil"; -import { Player } from "../../src/sdk/Player"; -import { World } from "../../src/sdk/World"; -import { Blowpipe } from "../../src/content/weapons/Blowpipe"; -import { TwistedBow } from "../../src/content/weapons/TwistedBow"; -import { Region } from "../../src/sdk/Region"; -import { Random } from "../../src/sdk/Random"; -import { Viewport } from "../../src/sdk/Viewport"; -import { TestRegion } from "../utils/TestRegion"; - - -describe("basic combat scenario", () => { - test("when player tries to kill an inferno ranger...", () => { - const region = new TestRegion(60, 60); - const world = new World(); - region.world = world; - world.addRegion(region); - const player = new Player(region, { x: 30, y: 60 }); - region.addPlayer(player); - Viewport.setupViewport(region, true); - Viewport.viewport.setPlayer(player); - - new TwistedBow().inventoryLeftClick(player); - const jalxil = new JalXil(region, { x: 25, y: 25 }, { aggro: player }); - region.addMob(jalxil); - world.tickWorld(30); - player.prayerController.findPrayerByName("Protect from Range").activate(player); - player.setAggro(jalxil); - world.tickWorld(20); - expect(player.location).toEqual({ x: 30, y: 54 }); - expect(player.currentStats.hitpoint).toBe(41); - expect(player.equipment.weapon.itemName).toEqual("Twisted Bow"); - expect(jalxil.location).toEqual({ x: 30, y: 45 }); - expect(jalxil.currentStats.hitpoint).toBe(124); - - player.moveTo(jalxil.location.x, jalxil.location.y); - player.prayerController.findPrayerByName("Rigour").activate(player); - const blowpipe = new Blowpipe(); - blowpipe.inventoryLeftClick(player); - expect(player.equipment.weapon.itemName).toEqual("Toxic Blowpipe"); - expect(player.aggro).toEqual(null); - - world.tickWorld(10); - player.setAggro(jalxil); - world.tickWorld(5); - expect(player.aggro).toEqual(jalxil); - - world.tickWorld(80); - expect(player.location).toEqual({ x: 30, y: 45 }); - expect(player.currentStats.prayer).toEqual(39); - expect(jalxil.location).toEqual({ x: 30, y: 44 }); - expect(jalxil.currentStats.hitpoint).toBe(0); - expect(player.currentStats.hitpoint).toBe(33); - expect(world.globalTickCounter).toEqual(145); - expect(Random.callCount).toEqual(78); - }); -}); diff --git a/test/simulations/Pathfinding.test.ts b/test/simulations/Pathfinding.test.ts deleted file mode 100644 index 8447aaad..00000000 --- a/test/simulations/Pathfinding.test.ts +++ /dev/null @@ -1,144 +0,0 @@ -import { Player } from "../../src/sdk/Player"; -import { World } from "../../src/sdk/World"; -import { Region } from "../../src/sdk/Region"; -import { Viewport } from "../../src/sdk/Viewport"; -import { Wall } from "../../src/content/Wall"; -import { InvisibleMovementBlocker } from "../../src/content/MovementBlocker"; -import { InfernoPillar } from "../../src/content/inferno/js/InfernoPillar"; -import { TestRegion } from "../utils/TestRegion"; - -describe("pathfinding tests", () => { - let region: TestRegion; - let world: World; - - beforeEach(() => { - region = new TestRegion(51, 57); - world = new World(); - region.world = world; - world.addRegion(region); - - for (let x = 10; x < 41; x++) { - region.addEntity(new InvisibleMovementBlocker(region, { x, y: 13 })); - region.addEntity(new InvisibleMovementBlocker(region, { x, y: 44 })); - } - for (let y = 14; y < 44; y++) { - region.addEntity(new InvisibleMovementBlocker(region, { x: 10, y })); - region.addEntity(new InvisibleMovementBlocker(region, { x: 40, y })); - } - - region.addEntity(new Wall(region, { x: 21, y: 8 })); - region.addEntity(new Wall(region, { x: 21, y: 7 })); - region.addEntity(new Wall(region, { x: 21, y: 6 })); - region.addEntity(new Wall(region, { x: 21, y: 5 })); - region.addEntity(new Wall(region, { x: 21, y: 4 })); - region.addEntity(new Wall(region, { x: 21, y: 3 })); - region.addEntity(new Wall(region, { x: 21, y: 2 })); - region.addEntity(new Wall(region, { x: 21, y: 1 })); - region.addEntity(new Wall(region, { x: 21, y: 0 })); - region.addEntity(new Wall(region, { x: 29, y: 8 })); - region.addEntity(new Wall(region, { x: 29, y: 7 })); - region.addEntity(new Wall(region, { x: 29, y: 6 })); - region.addEntity(new Wall(region, { x: 29, y: 5 })); - region.addEntity(new Wall(region, { x: 29, y: 4 })); - region.addEntity(new Wall(region, { x: 29, y: 3 })); - region.addEntity(new Wall(region, { x: 29, y: 2 })); - region.addEntity(new Wall(region, { x: 29, y: 1 })); - region.addEntity(new Wall(region, { x: 29, y: 0 })); - - Viewport.setupViewport(region, true); - }); - - test("can path in a straight line", () => { - const player = new Player(region, { x: 14, y: 14 }); - region.addPlayer(player); - Viewport.viewport.setPlayer(player); - - player.moveTo(20, 14); - - expect(player.location).toEqual({ x: 14, y: 14 }); - world.tickWorld(); - expect(player.location).toEqual({ x: 16, y: 14 }); - world.tickWorld(); - expect(player.location).toEqual({ x: 18, y: 14 }); - world.tickWorld(); - expect(player.location).toEqual({ x: 20, y: 14 }); - }); - - test("can path in a diagonal line", () => { - const player = new Player(region, { x: 14, y: 14 }); - region.addPlayer(player); - Viewport.viewport.setPlayer(player); - - player.moveTo(20, 20); - - expect(player.location).toEqual({ x: 14, y: 14 }); - world.tickWorld(); - expect(player.location).toEqual({ x: 16, y: 16 }); - world.tickWorld(); - expect(player.location).toEqual({ x: 18, y: 18 }); - world.tickWorld(); - expect(player.location).toEqual({ x: 20, y: 20 }); - }); - - test("can path around a pillar", () => { - const player = new Player(region, { x: 14, y: 14 }); - region.addPlayer(player); - Viewport.viewport.setPlayer(player); - - region.addEntity(new InfernoPillar(region, { x: 16, y: 16 })); - - player.moveTo(20, 20); - - expect(player.location).toEqual({ x: 14, y: 14 }); - world.tickWorld(); - expect(player.location).toEqual({ x: 14, y: 16 }); - world.tickWorld(); - expect(player.location).toEqual({ x: 16, y: 17 }); - world.tickWorld(); - expect(player.location).toEqual({ x: 18, y: 18 }); - world.tickWorld(); - expect(player.location).toEqual({ x: 20, y: 20 }); - }); - - test("can path outside the walled area", () => { - const player = new Player(region, { x: 14, y: 20 }); - region.addPlayer(player); - Viewport.viewport.setPlayer(player); - - player.moveTo(14, 0); - - expect(player.location).toEqual({ x: 14, y: 20 }); - world.tickWorld(); - expect(player.location).toEqual({ x: 14, y: 18 }); - world.tickWorld(); - expect(player.location).toEqual({ x: 14, y: 16 }); - world.tickWorld(); - expect(player.location).toEqual({ x: 14, y: 14 }); - world.tickWorld(); - expect(player.location).toEqual({ x: 14, y: 14 }); - // ensure the edge position (14, 14) is where the clickMarker stays - expect(player.pathTargetLocation).toEqual({ x: 14, y: 14 }); - world.tickWorld(); - expect(player.location).toEqual({ x: 14, y: 14 }); - expect(player.pathTargetLocation).toEqual({ x: 14, y: 14 }); - }); - - test("does not path back and forth on the west side", () => { - const player = new Player(region, { x: 12, y: 20 }); - region.addPlayer(player); - Viewport.viewport.setPlayer(player); - - player.moveTo(8, 20); - - // Player used to oscillate back and forth on the edges - expect(player.location).toEqual({ x: 12, y: 20 }); - world.tickWorld(); - expect(player.location).toEqual({ x: 11, y: 20 }); - world.tickWorld(); - expect(player.location).toEqual({ x: 11, y: 20 }); - world.tickWorld(); - expect(player.location).toEqual({ x: 11, y: 20 }); - world.tickWorld(); - expect(player.location).toEqual({ x: 11, y: 20 }); - }); -}); diff --git a/test/simulations/ZukLineOfSight.test.ts b/test/simulations/ZukLineOfSight.test.ts deleted file mode 100644 index 531bee57..00000000 --- a/test/simulations/ZukLineOfSight.test.ts +++ /dev/null @@ -1,172 +0,0 @@ -import { Player } from "../../src/sdk/Player"; -import { World } from "../../src/sdk/World"; -import { TwistedBow } from "../../src/content/weapons/TwistedBow"; -import { Region } from "../../src/sdk/Region"; -import { Viewport } from "../../src/sdk/Viewport"; -import { Wall } from "../../src/content/Wall"; -import { TzKalZuk } from "../../src/content/inferno/js/mobs/TzKalZuk"; -import { Mob } from "../../src/sdk/Mob"; -import { InvisibleMovementBlocker } from "../../src/content/MovementBlocker"; -import { TestRegion } from "../utils/TestRegion"; - -// Zuk LOS (dragging behaviour) tests -describe("player LOS in zuk fight", () => { - let region: TestRegion; - let world: World; - - let zuk: Mob; - - beforeEach(() => { - region = new TestRegion(51, 57); - world = new World(); - region.world = world; - world.addRegion(region); - - zuk = new TzKalZuk(region, { x: 22, y: 8 }, {}); - region.addMob(zuk); - - // The arena still needs to be closed off to prevent the player from pathing "around" the walls. - // Seems like this is most accurate if it's the exact size of the real arena. - for (let x = 10; x < 41; x++) { - region.addEntity(new InvisibleMovementBlocker(region, { x, y: 13 })); - region.addEntity(new InvisibleMovementBlocker(region, { x, y: 44 })); - } - for (let y = 14; y < 44; y++) { - region.addEntity(new InvisibleMovementBlocker(region, { x: 10, y })); - region.addEntity(new InvisibleMovementBlocker(region, { x: 40, y })); - } - - region.addEntity(new Wall(region, { x: 21, y: 8 })); - region.addEntity(new Wall(region, { x: 21, y: 7 })); - region.addEntity(new Wall(region, { x: 21, y: 6 })); - region.addEntity(new Wall(region, { x: 21, y: 5 })); - region.addEntity(new Wall(region, { x: 21, y: 4 })); - region.addEntity(new Wall(region, { x: 21, y: 3 })); - region.addEntity(new Wall(region, { x: 21, y: 2 })); - region.addEntity(new Wall(region, { x: 21, y: 1 })); - region.addEntity(new Wall(region, { x: 21, y: 0 })); - region.addEntity(new Wall(region, { x: 29, y: 8 })); - region.addEntity(new Wall(region, { x: 29, y: 7 })); - region.addEntity(new Wall(region, { x: 29, y: 6 })); - region.addEntity(new Wall(region, { x: 29, y: 5 })); - region.addEntity(new Wall(region, { x: 29, y: 4 })); - region.addEntity(new Wall(region, { x: 29, y: 3 })); - region.addEntity(new Wall(region, { x: 29, y: 2 })); - region.addEntity(new Wall(region, { x: 29, y: 1 })); - region.addEntity(new Wall(region, { x: 29, y: 0 })); - - Viewport.setupViewport(region, true); - }); - - test("player has line of sight at left safespot", () => { - const player = new Player(region, { x: 14, y: 14 }); - region.addPlayer(player); - Viewport.viewport.setPlayer(player); - - const twistedBow = new TwistedBow(); - twistedBow.inventoryLeftClick(player); - - player.setAggro(zuk); - - expect(player.location).toEqual({ x: 14, y: 14 }); - expect(player.attackDelay).toBe(0); - world.tickWorld(1); - expect(player.attackDelay).toBe(twistedBow.attackSpeed); - expect(player.location).toEqual({ x: 14, y: 14 }); - }); - - test("player has line of sight at middle-left safespot", () => { - const player = new Player(region, { x: 20, y: 14 }); - region.addPlayer(player); - Viewport.viewport.setPlayer(player); - - const twistedBow = new TwistedBow(); - twistedBow.inventoryLeftClick(player); - - player.setAggro(zuk); - - expect(player.location).toEqual({ x: 20, y: 14 }); - expect(player.attackDelay).toBe(0); - world.tickWorld(1); - expect(player.attackDelay).toBe(twistedBow.attackSpeed); - expect(player.location).toEqual({ x: 20, y: 14 }); - }); - - test("player has line of sight at middle-right safespot", () => { - const player = new Player(region, { x: 30, y: 14 }); - region.addPlayer(player); - Viewport.viewport.setPlayer(player); - - const twistedBow = new TwistedBow(); - twistedBow.inventoryLeftClick(player); - - player.setAggro(zuk); - - expect(player.location).toEqual({ x: 30, y: 14 }); - expect(player.attackDelay).toBe(0); - world.tickWorld(1); - expect(player.attackDelay).toBe(twistedBow.attackSpeed); - expect(player.location).toEqual({ x: 30, y: 14 }); - }); - - test("player has line of sight at right safespot", () => { - const player = new Player(region, { x: 36, y: 14 }); - region.addPlayer(player); - Viewport.viewport.setPlayer(player); - - const twistedBow = new TwistedBow(); - twistedBow.inventoryLeftClick(player); - - player.setAggro(zuk); - - expect(player.location).toEqual({ x: 36, y: 14 }); - expect(player.attackDelay).toBe(0); - world.tickWorld(1); - expect(player.attackDelay).toBe(twistedBow.attackSpeed); - expect(player.location).toEqual({ x: 36, y: 14 }); - }); - - test("player is dragged from dead tiles on left side", () => { - const player = new Player(region, { x: 16, y: 14 }); - region.addPlayer(player); - Viewport.viewport.setPlayer(player); - - const twistedBow = new TwistedBow(); - twistedBow.inventoryLeftClick(player); - - player.setAggro(zuk); - - expect(player.location).toEqual({ x: 16, y: 14 }); - expect(player.attackDelay).toBe(0); - world.tickWorld(); - // The player should look like they are pathing towards this position. In reality - // they gain LOS at x = 20. - expect(player.pathTargetLocation).toEqual({ x: 22, y: 14 }); - expect(player.attackDelay).toBe(-1); - expect(player.location).toEqual({ x: 18, y: 14 }); - world.tickWorld(); - expect(player.attackDelay).toBe(twistedBow.attackSpeed); - expect(player.location).toEqual({ x: 20, y: 14 }); - }); - - test("player is dragged from dead tiles on right side", () => { - const player = new Player(region, { x: 34, y: 14 }); - region.addPlayer(player); - Viewport.viewport.setPlayer(player); - - const twistedBow = new TwistedBow(); - twistedBow.inventoryLeftClick(player); - - player.setAggro(zuk); - - expect(player.location).toEqual({ x: 34, y: 14 }); - expect(player.attackDelay).toBe(0); - world.tickWorld(); - expect(player.pathTargetLocation).toEqual({ x: 28, y: 14 }); - expect(player.attackDelay).toBe(-1); - expect(player.location).toEqual({ x: 32, y: 14 }); - world.tickWorld(); - expect(player.attackDelay).toBe(twistedBow.attackSpeed); - expect(player.location).toEqual({ x: 30, y: 14 }); - }); -}); diff --git a/test/utils/TestRegion.ts b/test/utils/TestRegion.ts deleted file mode 100644 index 68f72b4d..00000000 --- a/test/utils/TestRegion.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Player } from "../../src/sdk/Player"; -import { Region } from "../../src/sdk/Region"; - -export class TestRegion extends Region { - constructor(private _width: number, private _height: number) { - super(); - } - - get width(): number { - return this._width; - } - - get height(): number { - return this._height; - } - - initialiseRegion() { - return null; - } - } \ No newline at end of file diff --git a/test/utils/Text.test.ts b/test/utils/Text.test.ts deleted file mode 100644 index af939baa..00000000 --- a/test/utils/Text.test.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { parseText } from "../../src/sdk/utils/Text"; - -describe("text tests", () => { - describe("parseText tests", () => { - test("handles untagged text", () => { - expect(parseText("something something")).toEqual([{ text: "something something" }]); - }); - - test("handles simple tagged text", () => { - expect(parseText("something something")).toEqual([ - { text: "something something", color: "ffffff" }, - ]); - }); - - test("handles text that changes color", () => { - expect(parseText("Give me your something")).toEqual([ - { text: "Give me your", color: "ffffff" }, - { text: " " }, - { text: "something", color: "ff0000" }, - ]); - }); - - test("handles unterminated tag", () => { - expect(parseText("Give me your")).toEqual([ - { text: "Give me your", color: "ffffff" }, - ]); - }); - }); -}); From 5d53c9c5ac5be793e8d16850d0be0f071931bfa4 Mon Sep 17 00:00:00 2001 From: supalosa Date: Wed, 8 May 2024 17:35:21 +1000 Subject: [PATCH 080/141] disable wasd camera movement if wasd keybinds are used --- package-lock.json | 8 ++++---- src/sdk/Settings.ts | 18 +++++++++++++++++- src/sdk/Viewport3d.ts | 25 ++++++++++++++++++++----- 3 files changed, 41 insertions(+), 10 deletions(-) diff --git a/package-lock.json b/package-lock.json index 66ca7999..dc584b7b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { - "name": "OldSchoolSDK", - "version": "1.0.0", + "name": "@supalosa/oldschool-trainer-sdk", + "version": "0.0.1", "lockfileVersion": 2, "requires": true, "packages": { "": { - "name": "OldSchoolSDK", - "version": "1.0.0", + "name": "@supalosa/oldschool-trainer-sdk", + "version": "0.0.1", "license": "ISC", "dependencies": { "@types/new-relic-browser": "^0.1118.2", diff --git a/src/sdk/Settings.ts b/src/sdk/Settings.ts index a9ad0a47..039c60d8 100644 --- a/src/sdk/Settings.ts +++ b/src/sdk/Settings.ts @@ -3,6 +3,8 @@ import { PlayerStats, SerializePlayerStats, DeserializePlayerStats } from "./PlayerStats"; import { Location } from "./Location"; +const WASD = ["w", "a", "s", "d"]; + export class Settings { static zoomScale = 1; @@ -51,6 +53,18 @@ export class Settings { static use3dView = true; + static isUsingWasdKeybind = Settings.checkWasd(); + + private static checkWasd() { + const result = + WASD.includes(Settings.inventory_key) || + WASD.includes(Settings.equipment_key) || + WASD.includes(Settings.combat_key) || + WASD.includes(Settings.prayer_key); + Settings.isUsingWasdKeybind = result; + return result; + } + static mobileCheck() { if (Settings._isMobileResult !== null) { return Settings._isMobileResult; @@ -90,6 +104,8 @@ export class Settings { window.localStorage.setItem("menuVisible", String(Settings.menuVisible)); window.localStorage.setItem("use3dView", String(Settings.use3dView)); window.localStorage.setItem("maxUiScale", String(Settings.maxUiScale)); + + Settings.checkWasd(); } static readFromStorage() { @@ -107,7 +123,7 @@ export class Settings { } // Settings.tileSize = parseInt(window.localStorage.getItem('tileSize')) || 23; // Settings.framesPerTick = parseInt(window.localStorage.getItem('framesPerTick')) || 30; - Settings.inputDelay = parseInt(window.localStorage.getItem("inputDelay") ?? '100'); + Settings.inputDelay = parseInt(window.localStorage.getItem("inputDelay") ?? "100"); Settings.rotated = window.localStorage.getItem("rotated") || "south"; Settings.loadout = window.localStorage.getItem("loadout") || "max_tbow_speed"; Settings.onTask = window.localStorage.getItem("onTask") === "true" || false; diff --git a/src/sdk/Viewport3d.ts b/src/sdk/Viewport3d.ts index 2f4fbc4c..9da5ce77 100644 --- a/src/sdk/Viewport3d.ts +++ b/src/sdk/Viewport3d.ts @@ -118,18 +118,25 @@ export class Viewport3d implements ViewportDelegate { checkGpu() { try { - const canvas = document.createElement('canvas'); + const canvas = document.createElement("canvas"); const gl = canvas.getContext("webgl"); const debugInfo = gl?.getExtension("WEBGL_debug_renderer_info"); const gpuInfo: string = gl?.getParameter(debugInfo.UNMASKED_VENDOR_WEBGL)?.toLowerCase() ?? "none"; - if (gpuInfo.includes("nvidia") || gpuInfo.includes("gpu") || gpuInfo.includes("geforce") || gpuInfo.includes("amd") || gpuInfo.includes("radeon")) { + if ( + gpuInfo.includes("nvidia") || + gpuInfo.includes("gpu") || + gpuInfo.includes("geforce") || + gpuInfo.includes("amd") || + gpuInfo.includes("radeon") + ) { return; } if (gpuInfo === "none" || gpuInfo.includes("google") || gpuInfo.includes("apple") || gpuInfo.includes("intel")) { - document.getElementById("gpu_warning").innerHTML = `Software rendering detected. Framerate may be low. Turn on Hardware Acceleration in your browser if you have a GPU.
${gpuInfo}
`; + document.getElementById("gpu_warning").innerHTML = + `Software rendering detected. Framerate may be low. Turn on Hardware Acceleration in your browser if you have a GPU.
${gpuInfo}
`; } - } catch(err) { - console.warn('error trying to detect gpu', err); + } catch (err) { + console.warn("error trying to detect gpu", err); } } @@ -154,6 +161,10 @@ export class Viewport3d implements ViewportDelegate { } onKeyDown(e: KeyboardEvent) { + const allowWasd = !Settings.isUsingWasdKeybind; + if (!allowWasd && ["w", "a", "s", "d"].includes(e.key.toLowerCase())) { + return; + } // values are desired change per second switch (e.key) { case "ArrowLeft": @@ -180,6 +191,10 @@ export class Viewport3d implements ViewportDelegate { } onKeyUp(e: KeyboardEvent) { + const allowWasd = !Settings.isUsingWasdKeybind; + if (!allowWasd && ["w", "a", "s", "d"].includes(e.key.toLowerCase())) { + return; + } switch (e.key) { case "ArrowLeft": case "ArrowRight": From 22eccd6754264eced755e8fc54759918b3b5875c Mon Sep 17 00:00:00 2001 From: supalosa Date: Wed, 8 May 2024 17:45:31 +1000 Subject: [PATCH 081/141] add shift click --- src/sdk/ClickController.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sdk/ClickController.ts b/src/sdk/ClickController.ts index 810b63c8..a428d44e 100644 --- a/src/sdk/ClickController.ts +++ b/src/sdk/ClickController.ts @@ -176,13 +176,13 @@ export class ClickController { Viewport.viewport.player.interruptCombat(); const inputController = InputController.controller; - if (mobs.length && mobs[0].canBeAttacked()) { + if (!e.shiftKey && mobs.length && mobs[0].canBeAttacked()) { this.redClick(); inputController.queueAction(() => this.playerAttackClick(mobs[0])); - } else if (players.length) { + } else if (!e.shiftKey && players.length) { this.redClick(); inputController.queueAction(() => this.playerAttackClick(players[0])); - } else if (groundItems.length) { + } else if (!e.shiftKey && groundItems.length) { this.redClick(); inputController.queueAction(() => player.setSeekingItem(groundItems[0])); From 0d1af166ef25abdd8401be7012897ce7d620b839 Mon Sep 17 00:00:00 2001 From: supalosa Date: Wed, 8 May 2024 17:51:08 +1000 Subject: [PATCH 082/141] add shiftclick walk under and disable WASD --- src/sdk/ClickController.ts | 6 +++--- src/sdk/Settings.ts | 18 +++++++++++++++++- src/sdk/Viewport3d.ts | 25 ++++++++++++++++++++----- 3 files changed, 40 insertions(+), 9 deletions(-) diff --git a/src/sdk/ClickController.ts b/src/sdk/ClickController.ts index 810b63c8..a428d44e 100644 --- a/src/sdk/ClickController.ts +++ b/src/sdk/ClickController.ts @@ -176,13 +176,13 @@ export class ClickController { Viewport.viewport.player.interruptCombat(); const inputController = InputController.controller; - if (mobs.length && mobs[0].canBeAttacked()) { + if (!e.shiftKey && mobs.length && mobs[0].canBeAttacked()) { this.redClick(); inputController.queueAction(() => this.playerAttackClick(mobs[0])); - } else if (players.length) { + } else if (!e.shiftKey && players.length) { this.redClick(); inputController.queueAction(() => this.playerAttackClick(players[0])); - } else if (groundItems.length) { + } else if (!e.shiftKey && groundItems.length) { this.redClick(); inputController.queueAction(() => player.setSeekingItem(groundItems[0])); diff --git a/src/sdk/Settings.ts b/src/sdk/Settings.ts index a9ad0a47..039c60d8 100644 --- a/src/sdk/Settings.ts +++ b/src/sdk/Settings.ts @@ -3,6 +3,8 @@ import { PlayerStats, SerializePlayerStats, DeserializePlayerStats } from "./PlayerStats"; import { Location } from "./Location"; +const WASD = ["w", "a", "s", "d"]; + export class Settings { static zoomScale = 1; @@ -51,6 +53,18 @@ export class Settings { static use3dView = true; + static isUsingWasdKeybind = Settings.checkWasd(); + + private static checkWasd() { + const result = + WASD.includes(Settings.inventory_key) || + WASD.includes(Settings.equipment_key) || + WASD.includes(Settings.combat_key) || + WASD.includes(Settings.prayer_key); + Settings.isUsingWasdKeybind = result; + return result; + } + static mobileCheck() { if (Settings._isMobileResult !== null) { return Settings._isMobileResult; @@ -90,6 +104,8 @@ export class Settings { window.localStorage.setItem("menuVisible", String(Settings.menuVisible)); window.localStorage.setItem("use3dView", String(Settings.use3dView)); window.localStorage.setItem("maxUiScale", String(Settings.maxUiScale)); + + Settings.checkWasd(); } static readFromStorage() { @@ -107,7 +123,7 @@ export class Settings { } // Settings.tileSize = parseInt(window.localStorage.getItem('tileSize')) || 23; // Settings.framesPerTick = parseInt(window.localStorage.getItem('framesPerTick')) || 30; - Settings.inputDelay = parseInt(window.localStorage.getItem("inputDelay") ?? '100'); + Settings.inputDelay = parseInt(window.localStorage.getItem("inputDelay") ?? "100"); Settings.rotated = window.localStorage.getItem("rotated") || "south"; Settings.loadout = window.localStorage.getItem("loadout") || "max_tbow_speed"; Settings.onTask = window.localStorage.getItem("onTask") === "true" || false; diff --git a/src/sdk/Viewport3d.ts b/src/sdk/Viewport3d.ts index 2f4fbc4c..9da5ce77 100644 --- a/src/sdk/Viewport3d.ts +++ b/src/sdk/Viewport3d.ts @@ -118,18 +118,25 @@ export class Viewport3d implements ViewportDelegate { checkGpu() { try { - const canvas = document.createElement('canvas'); + const canvas = document.createElement("canvas"); const gl = canvas.getContext("webgl"); const debugInfo = gl?.getExtension("WEBGL_debug_renderer_info"); const gpuInfo: string = gl?.getParameter(debugInfo.UNMASKED_VENDOR_WEBGL)?.toLowerCase() ?? "none"; - if (gpuInfo.includes("nvidia") || gpuInfo.includes("gpu") || gpuInfo.includes("geforce") || gpuInfo.includes("amd") || gpuInfo.includes("radeon")) { + if ( + gpuInfo.includes("nvidia") || + gpuInfo.includes("gpu") || + gpuInfo.includes("geforce") || + gpuInfo.includes("amd") || + gpuInfo.includes("radeon") + ) { return; } if (gpuInfo === "none" || gpuInfo.includes("google") || gpuInfo.includes("apple") || gpuInfo.includes("intel")) { - document.getElementById("gpu_warning").innerHTML = `Software rendering detected. Framerate may be low. Turn on Hardware Acceleration in your browser if you have a GPU.
${gpuInfo}
`; + document.getElementById("gpu_warning").innerHTML = + `Software rendering detected. Framerate may be low. Turn on Hardware Acceleration in your browser if you have a GPU.
${gpuInfo}
`; } - } catch(err) { - console.warn('error trying to detect gpu', err); + } catch (err) { + console.warn("error trying to detect gpu", err); } } @@ -154,6 +161,10 @@ export class Viewport3d implements ViewportDelegate { } onKeyDown(e: KeyboardEvent) { + const allowWasd = !Settings.isUsingWasdKeybind; + if (!allowWasd && ["w", "a", "s", "d"].includes(e.key.toLowerCase())) { + return; + } // values are desired change per second switch (e.key) { case "ArrowLeft": @@ -180,6 +191,10 @@ export class Viewport3d implements ViewportDelegate { } onKeyUp(e: KeyboardEvent) { + const allowWasd = !Settings.isUsingWasdKeybind; + if (!allowWasd && ["w", "a", "s", "d"].includes(e.key.toLowerCase())) { + return; + } switch (e.key) { case "ArrowLeft": case "ArrowRight": From b62247f41d9d54fe61e57a80f26b363dd06c5bc4 Mon Sep 17 00:00:00 2001 From: Supalosa Date: Wed, 8 May 2024 23:15:38 +1000 Subject: [PATCH 083/141] fix wasd on load --- src/sdk/Settings.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sdk/Settings.ts b/src/sdk/Settings.ts index 039c60d8..d5d6568e 100644 --- a/src/sdk/Settings.ts +++ b/src/sdk/Settings.ts @@ -162,5 +162,7 @@ export class Settings { Settings.rotated = "north"; } Settings.maxUiScale = parseFloat(window.localStorage.getItem("maxUiScale")) || 1.0; + + Settings.checkWasd(); } } From a063ac78bd61292e4cd2628daa0bf346c4bf43cb Mon Sep 17 00:00:00 2001 From: Supalosa Date: Wed, 8 May 2024 23:16:08 +1000 Subject: [PATCH 084/141] check wasd on load --- src/sdk/Settings.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sdk/Settings.ts b/src/sdk/Settings.ts index 039c60d8..d5d6568e 100644 --- a/src/sdk/Settings.ts +++ b/src/sdk/Settings.ts @@ -162,5 +162,7 @@ export class Settings { Settings.rotated = "north"; } Settings.maxUiScale = parseFloat(window.localStorage.getItem("maxUiScale")) || 1.0; + + Settings.checkWasd(); } } From a4c7ea3def270f4c06a3c20c2a60897d4ea0fe8e Mon Sep 17 00:00:00 2001 From: Supalosa Date: Wed, 8 May 2024 23:37:29 +1000 Subject: [PATCH 085/141] test --- jest.config.js | 2 +- test/setupFiles.ts | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/jest.config.js b/jest.config.js index 5cb3f2e7..e695c6db 100644 --- a/jest.config.js +++ b/jest.config.js @@ -14,6 +14,6 @@ module.exports = { "\\.(jpg|ico|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|ogg|glb|html)$": "/test/__mocks__/assetMock.js", "\\.(css|less)$": "/test/__mocks__/cssMock.js", - three: require.resolve("three"), + three: require.resolve("three") }, }; diff --git a/test/setupFiles.ts b/test/setupFiles.ts index 6985fdbb..81a87426 100644 --- a/test/setupFiles.ts +++ b/test/setupFiles.ts @@ -1,5 +1,7 @@ /* eslint-disable @typescript-eslint/no-empty-function */ -import { setupTests } from "@supalosa/oldschool-trainer-sdk"; - -setupTests(); \ No newline at end of file +jest.mock("@supalosa/oldschool-trainer-sdk/src/sdk/ControlPanelController"); +jest.mock("@supalosa/oldschool-trainer-sdk/src/sdk/MapController"); +jest.mock("@supalosa/oldschool-trainer-sdk/src/sdk/XpDropController"); +jest.mock("@supalosa/oldschool-trainer-sdk/src/sdk/utils/Assets"); +jest.mock("@supalosa/oldschool-trainer-sdk/src/sdk/utils/SoundCache"); \ No newline at end of file From 6631ca7b53693e93ff7d5b66ce42a29b54e288b9 Mon Sep 17 00:00:00 2001 From: Supalosa Date: Thu, 9 May 2024 00:28:45 +1000 Subject: [PATCH 086/141] tests passing! --- src/content/colosseum/js/ColosseumLoadout.ts | 22 ++--------- src/content/colosseum/js/mobs/SolHeredit.ts | 11 +----- test/setupFiles.ts | 40 +++++++++++++++++++- 3 files changed, 43 insertions(+), 30 deletions(-) diff --git a/src/content/colosseum/js/ColosseumLoadout.ts b/src/content/colosseum/js/ColosseumLoadout.ts index 2495abd3..eee26f50 100644 --- a/src/content/colosseum/js/ColosseumLoadout.ts +++ b/src/content/colosseum/js/ColosseumLoadout.ts @@ -1,22 +1,6 @@ -import { UnitOptions } from "../../../sdk/Unit"; - -import { RingOfSufferingImbued } from "../../equipment/RingOfSufferingImbued"; -import { DragonArrows } from "../../equipment/DragonArrows"; -import { SaradominBrew } from "../../items/SaradominBrew"; -import { SuperRestore } from "../../items/SuperRestore"; -import { Player } from "../../../sdk/Player"; -import { ScytheOfVitur } from "../../weapons/ScytheOfVitur"; -import { TorvaFullhelm } from "../../equipment/TorvaFullhelm"; -import { InfernalCape } from "../../equipment/InfernalCape"; -import { TorvaPlatebody } from "../../equipment/TorvaPlatebody"; -import { TorvaPlatelegs } from "../../equipment/TorvaPlatelegs"; -import { PrimordialBoots } from "../../equipment/PrimordialBoots"; -import { BladeOfSaeldor } from "../../weapons/BladeOfSaeldor"; -import { AmuletOfTorture } from "../../equipment/AmuletOfTorture"; -import { FerociousGloves } from "../../equipment/FerociousGloves"; -import { SuperCombatPotion } from "../../items/SuperCombatPotion"; -import { AvernicDefender } from "../../equipment/AvernicDefender"; -import { UltorRing } from "../../equipment/UltorRing"; +import { TorvaFullhelm, AmuletOfTorture, InfernalCape, DragonArrows, TorvaPlatebody, TorvaPlatelegs, PrimordialBoots, FerociousGloves, UltorRing, AvernicDefender, SuperCombatPotion, UnitOptions } from "@supalosa/oldschool-trainer-sdk"; +import { SaradominBrew, SuperRestore } from "@supalosa/oldschool-trainer-sdk"; +import { ScytheOfVitur, BladeOfSaeldor, Player } from "@supalosa/oldschool-trainer-sdk"; export class ColosseumLoadout { loadoutType: string; diff --git a/src/content/colosseum/js/mobs/SolHeredit.ts b/src/content/colosseum/js/mobs/SolHeredit.ts index 55a31bc2..18b254fa 100644 --- a/src/content/colosseum/js/mobs/SolHeredit.ts +++ b/src/content/colosseum/js/mobs/SolHeredit.ts @@ -2,16 +2,7 @@ import _ from "lodash"; -import { Assets, DelayedAction, EquipmentControls, GLTFModel, Collision, Region, Viewport, Location } from "@supalosa/oldschool-trainer-sdk"; - -import { EquipmentTypes } from "@supalosa/oldschool-trainer-sdk/src/sdk/Equipment"; -import { Mob, AttackIndicators } from "@supalosa/oldschool-trainer-sdk/src/sdk/Mob"; -import { Pathing } from "@supalosa/oldschool-trainer-sdk/src/sdk/Pathing"; -import { Random } from "@supalosa/oldschool-trainer-sdk/src/sdk/Random"; -import { UnitBonuses } from "@supalosa/oldschool-trainer-sdk/src/sdk/Unit"; -import { Sound, SoundCache } from "@supalosa/oldschool-trainer-sdk/src/sdk/utils/SoundCache"; -import { MeleeWeapon } from "@supalosa/oldschool-trainer-sdk/src/sdk/weapons/MeleeWeapon"; -import { Projectile } from "@supalosa/oldschool-trainer-sdk/src/sdk/weapons/Projectile"; +import { Assets, DelayedAction, EquipmentControls, GLTFModel, Collision, Region, Viewport, Location, EquipmentTypes, AttackIndicators, Mob, Pathing, Random, UnitBonuses, MeleeWeapon, Projectile, Sound, SoundCache } from "@supalosa/oldschool-trainer-sdk"; import { SolGroundSlam } from "../entities/SolGroundSlam"; import { RingBuffer } from "../utils/RingBuffer"; diff --git a/test/setupFiles.ts b/test/setupFiles.ts index 81a87426..181b6d0f 100644 --- a/test/setupFiles.ts +++ b/test/setupFiles.ts @@ -1,7 +1,45 @@ /* eslint-disable @typescript-eslint/no-empty-function */ +import { Random, Settings } from "@supalosa/oldschool-trainer-sdk"; + +const nextRandom = []; jest.mock("@supalosa/oldschool-trainer-sdk/src/sdk/ControlPanelController"); jest.mock("@supalosa/oldschool-trainer-sdk/src/sdk/MapController"); jest.mock("@supalosa/oldschool-trainer-sdk/src/sdk/XpDropController"); jest.mock("@supalosa/oldschool-trainer-sdk/src/sdk/utils/Assets"); -jest.mock("@supalosa/oldschool-trainer-sdk/src/sdk/utils/SoundCache"); \ No newline at end of file +jest.mock("@supalosa/oldschool-trainer-sdk/src/sdk/utils/SoundCache"); +jest.mock("three", () => ({ + Scene: class Scene { + public add(): void { + return; + } + }, + WebGLRenderer: class WebGlRenderer { + public render(): void { + return; + } + public setSize(): void { + return; + } + }, + GLTFLoader: class GLTFLoader { + constructor() {} + setMeshoptDecoder() {} + }, +})); +jest.spyOn(document, "getElementById").mockImplementation((elementId: string) => { + const c = document.createElement("canvas"); + c.ariaLabel = elementId; + return c; +}); + +Random.setRandom(() => { + if (nextRandom.length > 0) { + return nextRandom.shift(); + } + Random.memory = (Random.memory + 13.37) % 180; + return Math.abs(Math.sin(Random.memory * 0.0174533)); +}); + +Settings.readFromStorage(); + \ No newline at end of file From 6c1b68d0acf32c985196fd94683e8b32d015be51 Mon Sep 17 00:00:00 2001 From: Supalosa Date: Thu, 9 May 2024 12:26:13 +1000 Subject: [PATCH 087/141] fix manual mob mode --- src/content/inferno/js/InfernoRegion.ts | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/content/inferno/js/InfernoRegion.ts b/src/content/inferno/js/InfernoRegion.ts index 0f360e99..9f560ead 100644 --- a/src/content/inferno/js/InfernoRegion.ts +++ b/src/content/inferno/js/InfernoRegion.ts @@ -334,29 +334,29 @@ export class InfernoRegion extends Region { const mager = BrowserUtils.getQueryVar("mager") || "[]"; const replayLink = document.getElementById("replayLink") as HTMLLinkElement; - function importSpawn() { + function importSpawn(region: Region) { try { JSON.parse(mager).forEach((spawn: number[]) => - this.addMob(new JalZek(this, { x: spawn[0] + 11, y: spawn[1] + 14 }, { aggro: player })), + region.addMob(new JalZek(region, { x: spawn[0] + 11, y: spawn[1] + 14 }, { aggro: player })), ); JSON.parse(ranger).forEach((spawn: number[]) => - this.addMob(new JalXil(this, { x: spawn[0] + 11, y: spawn[1] + 14 }, { aggro: player })), + region.addMob(new JalXil(region, { x: spawn[0] + 11, y: spawn[1] + 14 }, { aggro: player })), ); JSON.parse(melee).forEach((spawn: number[]) => - this.addMob(new JalImKot(this, { x: spawn[0] + 11, y: spawn[1] + 14 }, { aggro: player })), + region.addMob(new JalImKot(region, { x: spawn[0] + 11, y: spawn[1] + 14 }, { aggro: player })), ); JSON.parse(blob).forEach((spawn: number[]) => - this.addMob(new JalAk(this, { x: spawn[0] + 11, y: spawn[1] + 14 }, { aggro: player })), + region.addMob(new JalAk(region, { x: spawn[0] + 11, y: spawn[1] + 14 }, { aggro: player })), ); JSON.parse(bat).forEach((spawn: number[]) => - this.addMob(new JalMejRah(this, { x: spawn[0] + 11, y: spawn[1] + 14 }, { aggro: player })), + region.addMob(new JalMejRah(region, { x: spawn[0] + 11, y: spawn[1] + 14 }, { aggro: player })), ); - InfernoWaves.spawnNibblers(3, this, randomPillar).forEach(this.addMob.bind(this)); + InfernoWaves.spawnNibblers(3, region, randomPillar).forEach(region.addMob.bind(region)); replayLink.href = `/${window.location.search}`; } catch (ex) { - console.log("failed to import wave from inferno stats"); + console.log("failed to import wave from inferno stats", ex); } } // Add mobs @@ -372,14 +372,14 @@ export class InfernoRegion extends Region { }); }); - importSpawn(); + importSpawn(this); } else if (this.wave < 67) { player.location = { x: 28, y: 17 }; if (bat != "[]" || blob != "[]" || melee != "[]" || ranger != "[]" || mager != "[]") { // Backwards compatibility layer for runelite plugin this.wave = 1; - importSpawn(); + importSpawn(this); } else { // Native approach const spawns = BrowserUtils.getQueryVar("spawns") @@ -468,7 +468,7 @@ export class InfernoRegion extends Region { this.addEntity(new TileMarker(this, { x: 36, y: 14 }, "#00FF00", 1, false)); } else if (this.wave === 74) { player.location = { x: 28, y: 17 }; - importSpawn(); + importSpawn(this); } document.getElementById("playWaveNum").addEventListener("click", () => { From 096a58bf43b0bb0675f086fd0c1f6ae88ac2726b Mon Sep 17 00:00:00 2001 From: Supalosa Date: Fri, 10 May 2024 17:37:24 +1000 Subject: [PATCH 088/141] use inputDelay to delay prayers --- src/sdk/BasePrayer.ts | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/sdk/BasePrayer.ts b/src/sdk/BasePrayer.ts index 24f62c3e..2b1a2ef0 100644 --- a/src/sdk/BasePrayer.ts +++ b/src/sdk/BasePrayer.ts @@ -1,6 +1,7 @@ "use strict"; import { Player } from "./Player"; +import { Settings } from "./Settings"; import { ImageLoader } from "./utils/ImageLoader"; export enum PrayerGroups { @@ -16,7 +17,10 @@ export enum PrayerGroups { export class BasePrayer { lastActivated = 0; + private lastDeactivated = 0; + // server-side isActive = false; + // client-side isLit = false; cachedImage: HTMLImageElement; @@ -29,11 +33,17 @@ export class BasePrayer { } tick() { + const ping = Settings.inputDelay || 0; + const now = Date.now(); if (this.isLit && !this.isActive) { - this.isActive = true; + if (now >= this.lastActivated + ping) { + this.isActive = true; + } this.isLit = true; } else if (!this.isLit && this.isActive) { - this.isActive = false; + if (now >= this.lastDeactivated + ping) { + this.isActive = false; + } this.isLit = false; } } @@ -70,6 +80,8 @@ export class BasePrayer { this.isLit = !this.isLit; if (this.isLit) { this.lastActivated = Date.now(); + } else { + this.lastDeactivated = Date.now(); } } From 67095408b7b8c1e363a05bf061ae22476b34038d Mon Sep 17 00:00:00 2001 From: Supalosa Date: Fri, 10 May 2024 18:00:49 +1000 Subject: [PATCH 089/141] fix prayer --- src/sdk/BasePrayer.ts | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/sdk/BasePrayer.ts b/src/sdk/BasePrayer.ts index 24f62c3e..2b1a2ef0 100644 --- a/src/sdk/BasePrayer.ts +++ b/src/sdk/BasePrayer.ts @@ -1,6 +1,7 @@ "use strict"; import { Player } from "./Player"; +import { Settings } from "./Settings"; import { ImageLoader } from "./utils/ImageLoader"; export enum PrayerGroups { @@ -16,7 +17,10 @@ export enum PrayerGroups { export class BasePrayer { lastActivated = 0; + private lastDeactivated = 0; + // server-side isActive = false; + // client-side isLit = false; cachedImage: HTMLImageElement; @@ -29,11 +33,17 @@ export class BasePrayer { } tick() { + const ping = Settings.inputDelay || 0; + const now = Date.now(); if (this.isLit && !this.isActive) { - this.isActive = true; + if (now >= this.lastActivated + ping) { + this.isActive = true; + } this.isLit = true; } else if (!this.isLit && this.isActive) { - this.isActive = false; + if (now >= this.lastDeactivated + ping) { + this.isActive = false; + } this.isLit = false; } } @@ -70,6 +80,8 @@ export class BasePrayer { this.isLit = !this.isLit; if (this.isLit) { this.lastActivated = Date.now(); + } else { + this.lastDeactivated = Date.now(); } } From 18acf79e4185e5fdc2efcbdc9ed5e547143b226d Mon Sep 17 00:00:00 2001 From: Supalosa Date: Fri, 10 May 2024 18:15:43 +1000 Subject: [PATCH 090/141] fix ping --- src/content/colosseum/tests/SolAttack.test.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/content/colosseum/tests/SolAttack.test.ts b/src/content/colosseum/tests/SolAttack.test.ts index 38a7ee66..4893411f 100644 --- a/src/content/colosseum/tests/SolAttack.test.ts +++ b/src/content/colosseum/tests/SolAttack.test.ts @@ -1,4 +1,4 @@ -import { DelayedAction, EquipmentControls, Player, TestRegion, Viewport, World } from "@supalosa/oldschool-trainer-sdk"; +import { DelayedAction, EquipmentControls, Player, Settings, TestRegion, Viewport, World } from "@supalosa/oldschool-trainer-sdk"; import { Attacks, SolHeredit } from "../js/mobs/SolHeredit"; // sol heredit movement tests @@ -9,6 +9,7 @@ describe("sol heredit attacks", () => { let boss: SolHeredit; const reset = () => { + Settings.inputDelay = 0; DelayedAction.reset(); region = new TestRegion(30, 30); world = new World(); From 2fb34f62093c83e1e2b5aab254834ea43583db6e Mon Sep 17 00:00:00 2001 From: Supalosa Date: Fri, 10 May 2024 19:39:46 +1000 Subject: [PATCH 091/141] working with trainer package --- src/assets/images/webappicon.png | Bin 0 -> 30973 bytes src/content/colosseum/assets/images/map.png | Bin 0 -> 10112 bytes src/content/colosseum/js/ColosseumRegion.ts | 11 +- src/content/colosseum/js/entities/LaserOrb.ts | 5 +- .../colosseum/js/entities/SolSandPool.ts | 3 +- .../colosseum/js/entities/SolarFlareOrb.ts | 4 +- src/content/colosseum/js/mobs/SolHeredit.ts | 4 +- src/index.html | 31 ++---- src/index.ts | 6 +- src/sdk/controlpanels/PrayerControls.ts | 101 ++++++++++++++++++ webpack.config.js | 2 - 11 files changed, 124 insertions(+), 43 deletions(-) create mode 100644 src/assets/images/webappicon.png create mode 100644 src/content/colosseum/assets/images/map.png create mode 100644 src/sdk/controlpanels/PrayerControls.ts diff --git a/src/assets/images/webappicon.png b/src/assets/images/webappicon.png new file mode 100644 index 0000000000000000000000000000000000000000..2edb6c18865ee792961c360e8580479d026084fa GIT binary patch literal 30973 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 ig@uKM#gbrU<^Kcw+c>5` literal 0 HcmV?d00001 diff --git a/src/content/colosseum/js/ColosseumRegion.ts b/src/content/colosseum/js/ColosseumRegion.ts index b0808784..c333fa25 100644 --- a/src/content/colosseum/js/ColosseumRegion.ts +++ b/src/content/colosseum/js/ColosseumRegion.ts @@ -1,10 +1,9 @@ "use strict"; -import { Region, Viewport, Settings, Player, CardinalDirection, ImageLoader } from "@supalosa/oldschool-trainer-sdk"; +import { Region, Viewport, Settings, Player, CardinalDirection, ImageLoader, Trainer } from "@supalosa/oldschool-trainer-sdk"; -// TODO -import InfernoMapImage from "../../../content/inferno/assets/images/map.png"; +import ColosseumMapImage from "../assets/images/map.png"; import { ColosseumLoadout } from "./ColosseumLoadout"; import { ColosseumScene } from "./ColosseumScene"; @@ -19,7 +18,7 @@ import { SolarFlareOrb } from "./entities/SolarFlareOrb"; export class ColosseumRegion extends Region { wave: number; - mapImage: HTMLImageElement = ImageLoader.createImage(InfernoMapImage); + mapImage: HTMLImageElement = ImageLoader.createImage(ColosseumMapImage); get initialFacing() { return CardinalDirection.NORTH; @@ -49,10 +48,10 @@ export class ColosseumRegion extends Region { { text: "Mager", fillStyle: "red" }, ], action: () => { - Viewport.viewport.clickController.yellowClick(); + Trainer.clickController.yellowClick(); const x = Viewport.viewport.contextMenu.destinationLocation.x; const y = Viewport.viewport.contextMenu.destinationLocation.y; - const mob = new SolHeredit(this, { x, y }, { aggro: Viewport.viewport.player }); + const mob = new SolHeredit(this, { x, y }, { aggro: Trainer.player }); mob.removableWithRightClick = true; this.addMob(mob); }, diff --git a/src/content/colosseum/js/entities/LaserOrb.ts b/src/content/colosseum/js/entities/LaserOrb.ts index 9e35a947..e8487c52 100644 --- a/src/content/colosseum/js/entities/LaserOrb.ts +++ b/src/content/colosseum/js/entities/LaserOrb.ts @@ -10,6 +10,7 @@ import { Projectile, Pathing, Location, + Trainer, } from "@supalosa/oldschool-trainer-sdk"; import _ from "lodash"; @@ -158,7 +159,7 @@ export class LaserOrb extends Entity { this.moveTick = 2; } if (this.firingFreeze === 3) { - const player = Viewport.viewport.player; + const player = Trainer.player; if (this.isInLineWithPlayer()) { const damage = 60 + Math.floor(Random.get() * 20); player.addProjectile(new Projectile(null, damage, player, player, "typeless", { setDelay: 0 })); @@ -170,7 +171,7 @@ export class LaserOrb extends Entity { } isInLineWithPlayer() { - const player = Viewport.viewport.player; + const player = Trainer.player; if ((this.edge === Edge.NORTH || this.edge === Edge.SOUTH) && player.location.x === this.location.x) { return true; } diff --git a/src/content/colosseum/js/entities/SolSandPool.ts b/src/content/colosseum/js/entities/SolSandPool.ts index 5237e2c8..17dc31bd 100644 --- a/src/content/colosseum/js/entities/SolSandPool.ts +++ b/src/content/colosseum/js/entities/SolSandPool.ts @@ -13,6 +13,7 @@ import { Unit, Random, Location, + Trainer, } from "@supalosa/oldschool-trainer-sdk"; import { SandPoolModel } from "../rendering/SandPoolModel"; @@ -74,7 +75,7 @@ export class SolSandPool extends Entity { tick() { ++this.age; // sand pools can damage after 3 ticks - const player = Viewport.viewport.player; + const player = Trainer.player; if (player.dying >= 0) { return; } diff --git a/src/content/colosseum/js/entities/SolarFlareOrb.ts b/src/content/colosseum/js/entities/SolarFlareOrb.ts index d1181833..c5c6b5ec 100644 --- a/src/content/colosseum/js/entities/SolarFlareOrb.ts +++ b/src/content/colosseum/js/entities/SolarFlareOrb.ts @@ -2,7 +2,7 @@ import _ from "lodash"; -import { Entity, Region, CollisionType, LineOfSightMask, Viewport, Random, Projectile, Pathing, Location } from "@supalosa/oldschool-trainer-sdk"; +import { Entity, Region, CollisionType, LineOfSightMask, Viewport, Random, Projectile, Pathing, Location, Trainer } from "@supalosa/oldschool-trainer-sdk"; import { SolarFlareModel } from "../rendering/SolarFlareModel"; @@ -70,7 +70,7 @@ export class SolarFlareOrb extends Entity { } tick() { - const player = Viewport.viewport.player; + const player = Trainer.player; if (this.waitTicks <= 0 && this.moveTick <= 0) { this.lastLocation = { x: this.location.x, diff --git a/src/content/colosseum/js/mobs/SolHeredit.ts b/src/content/colosseum/js/mobs/SolHeredit.ts index 18b254fa..f4163a33 100644 --- a/src/content/colosseum/js/mobs/SolHeredit.ts +++ b/src/content/colosseum/js/mobs/SolHeredit.ts @@ -2,7 +2,7 @@ import _ from "lodash"; -import { Assets, DelayedAction, EquipmentControls, GLTFModel, Collision, Region, Viewport, Location, EquipmentTypes, AttackIndicators, Mob, Pathing, Random, UnitBonuses, MeleeWeapon, Projectile, Sound, SoundCache } from "@supalosa/oldschool-trainer-sdk"; +import { Assets, DelayedAction, EquipmentControls, GLTFModel, Collision, Region, Viewport, Location, EquipmentTypes, AttackIndicators, Mob, Pathing, Random, UnitBonuses, MeleeWeapon, Projectile, Sound, SoundCache, Trainer } from "@supalosa/oldschool-trainer-sdk"; import { SolGroundSlam } from "../entities/SolGroundSlam"; import { RingBuffer } from "../utils/RingBuffer"; @@ -232,7 +232,7 @@ export class SolHeredit extends Mob { { text: " hp ", fillStyle: "white" }, ], action: () => { - Viewport.viewport.clickController.redClick(); + Trainer.clickController.redClick(); this.phaseId = idx; this.currentStats.hitpoint = hp; }, diff --git a/src/index.html b/src/index.html index 19cefe76..a62ecbf6 100644 --- a/src/index.html +++ b/src/index.html @@ -14,20 +14,20 @@ - - - - - - - - diff --git a/src/index.ts b/src/index.ts index ecb3b749..128476c0 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,9 +1,9 @@ "use strict"; -import { World, Settings, ImageLoader, Viewport, TileMarker, Location, MapController, Assets, Chrome, Region } from "@supalosa/oldschool-trainer-sdk"; +import { World, Settings, ImageLoader, Viewport, TileMarker, Location, MapController, Assets, Chrome, Region, Trainer } from "@supalosa/oldschool-trainer-sdk"; import { ColosseumRegion } from "./content/colosseum/js/ColosseumRegion"; -import SpecialAttackBarBackground from "./assets/images/attackstyles/interface/special_attack_background.png"; +const SpecialAttackBarBackground = Assets.getAssetUrl("/assets/images/attackstyles/interface/special_attack_background.png"); Settings.readFromStorage(); @@ -59,7 +59,7 @@ player.destinationLocation = player.location; // UI controls ImageLoader.onAllImagesLoaded(() => - MapController.controller.updateOrbsMask(Viewport.viewport.player.currentStats, Viewport.viewport.player.stats), + MapController.controller.updateOrbsMask(Trainer.player.currentStats, Trainer.player.stats), ); ImageLoader.onAllImagesLoaded(() => { diff --git a/src/sdk/controlpanels/PrayerControls.ts b/src/sdk/controlpanels/PrayerControls.ts new file mode 100644 index 00000000..5565e944 --- /dev/null +++ b/src/sdk/controlpanels/PrayerControls.ts @@ -0,0 +1,101 @@ +import PrayerPanel from "../../assets/images/panels/prayer.png"; +import PrayerTab from "../../assets/images/tabs/prayer.png"; +import { BaseControls } from "./BaseControls"; +import { Settings } from "../Settings"; +import { ControlPanelController } from "../ControlPanelController"; +import { Viewport } from "../Viewport"; +import { Trainer } from "@supalosa/oldschool-trainer-sdk"; + +export class PrayerControls extends BaseControls { + hasQuickPrayersActivated = false; + + get panelImageReference() { + return PrayerPanel; + } + + get tabImageReference() { + return PrayerTab; + } + + get keyBinding() { + return Settings.prayer_key; + } + + deactivateAllPrayers() { + this.hasQuickPrayersActivated = false; + Trainer.player.prayerController.activePrayers().forEach((prayer) => prayer.deactivate()); + } + + activateQuickPrayers() { + this.hasQuickPrayersActivated = true; + + Trainer.player.prayerController.prayers.forEach((prayer) => { + prayer.deactivate(); + if (prayer.name === "Protect from Magic") { + prayer.activate(Trainer.player); + } + if (prayer.name === "Rigour") { + prayer.activate(Trainer.player); + } + }); + } + + panelClickDown(x: number, y: number) { + const scale = Settings.controlPanelScale; + + x = x / scale; + y = y / scale; + + const gridX = x - 14; + const gridY = y - 22; + + const clickedPrayer = + Trainer.player.prayerController.prayers[Math.floor(gridY / 35) * 5 + Math.floor(gridX / 35)]; + if (clickedPrayer && Trainer.player.currentStats.prayer > 0) { + clickedPrayer.toggle(Trainer.player); + + if (this.hasQuickPrayersActivated && Trainer.player.prayerController.activePrayers().length === 0) { + ControlPanelController.controls.PRAYER.hasQuickPrayersActivated = false; + } + } + } + + get isAvailable(): boolean { + return true; + } + + draw(context, ctrl: ControlPanelController, x: number, y: number) { + super.draw(context, ctrl, x, y); + const scale = Settings.controlPanelScale; + + Trainer.player.prayerController.prayers.forEach((prayer, index) => { + const x2 = index % 5; + const y2 = Math.floor(index / 5); + + if (prayer.isActive || prayer.isLit) { + Viewport.viewport.context.beginPath(); + Viewport.viewport.context.fillStyle = "#D1BB7773"; + Viewport.viewport.context.arc( + x + 10 * scale + (x2 + 0.5) * 36.8 * scale, + y + (16 + (y2 + 0.5) * 37) * scale, + 18 * scale, + 0, + 2 * Math.PI, + ); + Viewport.viewport.context.fill(); + } + if (Trainer.player.stats.prayer < prayer.levelRequirement()) { + Viewport.viewport.context.beginPath(); + Viewport.viewport.context.fillStyle = "#00000073"; + Viewport.viewport.context.arc( + x + 10 * scale + (x2 + 0.5) * 36.8 * scale, + y + (16 + (y2 + 0.5) * 37) * scale, + 18 * scale, + 0, + 2 * Math.PI, + ); + Viewport.viewport.context.fill(); + } + }); + } +} diff --git a/webpack.config.js b/webpack.config.js index 846324e0..ccc0dc03 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -42,8 +42,6 @@ const config = { to: "webappicon.png", context: `src/`, }, - { from: `assets/fonts/*.woff`, to: "", context: `src/` }, - { from: `assets/fonts/*.woff2`, to: "", context: `src/` }, ], }), new webpack.EnvironmentPlugin(["COMMIT_REF", "BUILD_DATE", "DEPLOY_URL"]), From 35781d148cc3fb7548a3c953820503ea01a38eb4 Mon Sep 17 00:00:00 2001 From: Supalosa Date: Sat, 11 May 2024 00:34:26 +1000 Subject: [PATCH 092/141] consume library it works --- package-lock.json | 2383 +++++++++++++---- package.json | 3 +- .../colosseum/js/entities/SolarFlareOrb.ts | 2 +- src/sdk/controlpanels/PrayerControls.ts | 101 - 4 files changed, 1885 insertions(+), 604 deletions(-) delete mode 100644 src/sdk/controlpanels/PrayerControls.ts diff --git a/package-lock.json b/package-lock.json index 52d3bbcb..6f993b51 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "0.0.1", "license": "ISC", "dependencies": { + "@supalosa/oldschool-trainer-sdk": "0.0.9", "three": "^0.163.0" }, "devDependencies": { @@ -401,7 +402,6 @@ "version": "7.24.4", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.4.tgz", "integrity": "sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg==", - "dev": true, "bin": { "parser": "bin/babel-parser.js" }, @@ -658,6 +658,18 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, + "node_modules/@dependents/detective-less": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@dependents/detective-less/-/detective-less-4.1.0.tgz", + "integrity": "sha512-KrkT6qO5NxqNfy68sBl6CTSoJ4SNDIS5iQArkibhlbGU4LaDukZ3q2HIkh8aUKDio6o4itU4xDR7t82Y2eP1Bg==", + "dependencies": { + "gonzales-pe": "^4.3.0", + "node-source-walk": "^6.0.1" + }, + "engines": { + "node": ">=14" + } + }, "node_modules/@discoveryjs/json-ext": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.3.tgz", @@ -1046,7 +1058,6 @@ "version": "0.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", - "dev": true, "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", @@ -1060,7 +1071,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, "engines": { "node": ">=6.0.0" } @@ -1069,7 +1079,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true, "engines": { "node": ">=6.0.0" } @@ -1078,7 +1087,6 @@ "version": "0.3.6", "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", - "dev": true, "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25" @@ -1087,14 +1095,12 @@ "node_modules/@jridgewell/sourcemap-codec": { "version": "1.4.15", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.25", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -1104,7 +1110,6 @@ "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -1117,7 +1122,6 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, "engines": { "node": ">= 8" } @@ -1126,7 +1130,6 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -1153,6 +1156,20 @@ "@sinonjs/commons": "^1.7.0" } }, + "node_modules/@supalosa/oldschool-trainer-sdk": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/@supalosa/oldschool-trainer-sdk/-/oldschool-trainer-sdk-0.0.9.tgz", + "integrity": "sha512-HUBSysNtoZdEUdZtF4U2AA++86dd9Enp6E+BKWAtK+Qy7bz/irTBA9lQWcipRc9sblOE6M29Jg7yK2YBnyWg3w==", + "dependencies": { + "@types/new-relic-browser": "^0.1118.2", + "@types/offscreencanvas": "^2019.6.4", + "chebyshev": "^0.2.1", + "color-scales": "^3.0.2", + "madge": "^7.0.0", + "source-map-loader": "^3.0.0", + "three": "^0.163.0" + } + }, "node_modules/@tootallnate/once": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", @@ -1213,7 +1230,6 @@ "version": "8.56.9", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.9.tgz", "integrity": "sha512-W4W3KcqzjJ0sHg2vAq9vfml6OhsJ53TcUjUqfzzZf/EChUtwspszj/S0pzMxnfRcO55/iGq47dscXw71Fxc4Zg==", - "dev": true, "dependencies": { "@types/estree": "*", "@types/json-schema": "*" @@ -1223,7 +1239,6 @@ "version": "3.7.7", "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", - "dev": true, "dependencies": { "@types/eslint": "*", "@types/estree": "*" @@ -1232,8 +1247,7 @@ "node_modules/@types/estree": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", - "dev": true + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==" }, "node_modules/@types/glob": { "version": "7.2.0", @@ -1291,8 +1305,7 @@ "node_modules/@types/json-schema": { "version": "7.0.11", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", - "dev": true + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==" }, "node_modules/@types/lodash": { "version": "4.14.171", @@ -1306,11 +1319,20 @@ "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==", "dev": true }, + "node_modules/@types/new-relic-browser": { + "version": "0.1118.2", + "resolved": "https://registry.npmjs.org/@types/new-relic-browser/-/new-relic-browser-0.1118.2.tgz", + "integrity": "sha512-Cy3qMm3QVZT0HmpFxUsc204AdWa4yWX1yJsFhdBqZgecUBYDq86ljDmJQQxUk/4yPwCQ2C73nRLMb2jH3CnbrA==" + }, "node_modules/@types/node": { "version": "16.4.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-16.4.0.tgz", - "integrity": "sha512-HrJuE7Mlqcjj+00JqMWpZ3tY8w7EUd+S0U3L1+PQSWiXZbOgyQDvi+ogoUxaHApPJq5diKxYBQwA3iIlNcPqOg==", - "dev": true + "integrity": "sha512-HrJuE7Mlqcjj+00JqMWpZ3tY8w7EUd+S0U3L1+PQSWiXZbOgyQDvi+ogoUxaHApPJq5diKxYBQwA3iIlNcPqOg==" + }, + "node_modules/@types/offscreencanvas": { + "version": "2019.7.3", + "resolved": "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.7.3.tgz", + "integrity": "sha512-ieXiYmgSRXUDeOntE1InxjWyvEelZGP63M+cGuquuRLuIKKT1osnkXjxev9B7d1nXSug5vpunx+gNlbVxMlC9A==" }, "node_modules/@types/prettier": { "version": "2.4.4", @@ -1588,7 +1610,6 @@ "version": "1.12.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", - "dev": true, "dependencies": { "@webassemblyjs/helper-numbers": "1.11.6", "@webassemblyjs/helper-wasm-bytecode": "1.11.6" @@ -1597,26 +1618,22 @@ "node_modules/@webassemblyjs/floating-point-hex-parser": { "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", - "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", - "dev": true + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==" }, "node_modules/@webassemblyjs/helper-api-error": { "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", - "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", - "dev": true + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==" }, "node_modules/@webassemblyjs/helper-buffer": { "version": "1.12.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", - "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==", - "dev": true + "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==" }, "node_modules/@webassemblyjs/helper-numbers": { "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", - "dev": true, "dependencies": { "@webassemblyjs/floating-point-hex-parser": "1.11.6", "@webassemblyjs/helper-api-error": "1.11.6", @@ -1626,14 +1643,12 @@ "node_modules/@webassemblyjs/helper-wasm-bytecode": { "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", - "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", - "dev": true + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==" }, "node_modules/@webassemblyjs/helper-wasm-section": { "version": "1.12.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", - "dev": true, "dependencies": { "@webassemblyjs/ast": "1.12.1", "@webassemblyjs/helper-buffer": "1.12.1", @@ -1645,7 +1660,6 @@ "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", - "dev": true, "dependencies": { "@xtuc/ieee754": "^1.2.0" } @@ -1654,7 +1668,6 @@ "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", - "dev": true, "dependencies": { "@xtuc/long": "4.2.2" } @@ -1662,14 +1675,12 @@ "node_modules/@webassemblyjs/utf8": { "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", - "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", - "dev": true + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==" }, "node_modules/@webassemblyjs/wasm-edit": { "version": "1.12.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", - "dev": true, "dependencies": { "@webassemblyjs/ast": "1.12.1", "@webassemblyjs/helper-buffer": "1.12.1", @@ -1685,7 +1696,6 @@ "version": "1.12.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", - "dev": true, "dependencies": { "@webassemblyjs/ast": "1.12.1", "@webassemblyjs/helper-wasm-bytecode": "1.11.6", @@ -1698,7 +1708,6 @@ "version": "1.12.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", - "dev": true, "dependencies": { "@webassemblyjs/ast": "1.12.1", "@webassemblyjs/helper-buffer": "1.12.1", @@ -1710,7 +1719,6 @@ "version": "1.12.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", - "dev": true, "dependencies": { "@webassemblyjs/ast": "1.12.1", "@webassemblyjs/helper-api-error": "1.11.6", @@ -1724,7 +1732,6 @@ "version": "1.12.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", - "dev": true, "dependencies": { "@webassemblyjs/ast": "1.12.1", "@xtuc/long": "4.2.2" @@ -1769,20 +1776,17 @@ "node_modules/@xtuc/ieee754": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==" }, "node_modules/@xtuc/long": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "dev": true + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" }, "node_modules/abab": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", - "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==", - "dev": true + "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==" }, "node_modules/accepts": { "version": "1.3.7", @@ -1853,7 +1857,6 @@ "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -1878,7 +1881,6 @@ "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, "peerDependencies": { "ajv": "^6.9.1" } @@ -1935,7 +1937,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "engines": { "node": ">=8" } @@ -1944,7 +1945,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -1955,6 +1955,11 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==" + }, "node_modules/anymatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", @@ -1968,6 +1973,11 @@ "node": ">= 8" } }, + "node_modules/app-module-path": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/app-module-path/-/app-module-path-2.2.0.tgz", + "integrity": "sha512-gkco+qxENJV+8vFcDiiFhuoSvRXb2a/QPqpSoWhVz829VNJfOTnELbBmPmNKFxf3xdNnw4DWCkzkDaavcX/1YQ==" + }, "node_modules/argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -2033,7 +2043,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, "engines": { "node": ">=8" } @@ -2082,6 +2091,14 @@ "node": ">=0.10.0" } }, + "node_modules/ast-module-types": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ast-module-types/-/ast-module-types-5.0.0.tgz", + "integrity": "sha512-JvqziE0Wc0rXQfma0HZC/aY7URXHFuZV84fJRtP8u+lhp0JYCNd5wJzVXP45t0PH0Mej3ynlzvdyITYIu0G4LQ==", + "engines": { + "node": ">=14" + } + }, "node_modules/astral-regex": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", @@ -2225,8 +2242,7 @@ "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "node_modules/base": { "version": "0.11.2", @@ -2296,6 +2312,25 @@ "node": ">=0.10.0" } }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/batch": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", @@ -2321,6 +2356,29 @@ "file-uri-to-path": "1.0.0" } }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bl/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/body-parser": { "version": "1.19.0", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", @@ -2396,7 +2454,6 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -2406,7 +2463,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, "dependencies": { "fill-range": "^7.0.1" }, @@ -2424,7 +2480,6 @@ "version": "4.23.0", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", - "dev": true, "funding": [ { "type": "opencollective", @@ -2473,11 +2528,33 @@ "node-int64": "^0.4.0" } }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, "node_modules/buffer-from": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", - "dev": true + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" }, "node_modules/buffer-indexof": { "version": "1.1.1", @@ -2565,7 +2642,6 @@ "version": "1.0.30001611", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001611.tgz", "integrity": "sha512-19NuN1/3PjA3QI8Eki55N8my4LzfkMCRLgCVfrl/slbSAchQfV0+GwjPrK3rq37As4UCLlM/DHajbKkAqbv92Q==", - "dev": true, "funding": [ { "type": "opencollective", @@ -2585,7 +2661,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -2606,6 +2681,11 @@ "node": ">=10" } }, + "node_modules/chebyshev": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/chebyshev/-/chebyshev-0.2.1.tgz", + "integrity": "sha512-FaLyrAPJ57VsPOfalGAVqVqjoX75V56ZbnPe74/NzR4+CzzC8Y65xdoRdH6w+xuMbead4/nJYDN6NFqbKUFkRw==" + }, "node_modules/chokidar": { "version": "2.1.8", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", @@ -2869,7 +2949,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", - "dev": true, "engines": { "node": ">=6.0" } @@ -2913,6 +2992,28 @@ "node": ">= 10.0" } }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/cliui": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", @@ -2974,6 +3075,14 @@ "node": ">=6" } }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "engines": { + "node": ">=0.8" + } + }, "node_modules/clone-deep": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", @@ -3021,7 +3130,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "dependencies": { "color-name": "~1.1.4" }, @@ -3032,8 +3140,12 @@ "node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/color-scales": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/color-scales/-/color-scales-3.0.2.tgz", + "integrity": "sha512-AwX0kUE1Ps6Gv0b8if20DAfgchAs5HRmr+ulBbP4anqcBqUevaj8S9OWVFlYynsfuvB9GF1oSpCWOVNtox7aRA==" }, "node_modules/colorette": { "version": "2.0.16", @@ -3056,8 +3168,12 @@ "node_modules/commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==" }, "node_modules/component-emitter": { "version": "1.3.0", @@ -3119,8 +3235,7 @@ "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, "node_modules/connect-history-api-fallback": { "version": "1.6.0", @@ -3284,7 +3399,6 @@ "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, "dependencies": { "ms": "2.1.2" }, @@ -3344,11 +3458,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/deep-is": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=" }, "node_modules/deepmerge": { "version": "4.2.2", @@ -3490,6 +3611,17 @@ "which": "bin/which" } }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/define-properties": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", @@ -3608,6 +3740,43 @@ "node": ">= 0.6" } }, + "node_modules/dependency-tree": { + "version": "10.0.9", + "resolved": "https://registry.npmjs.org/dependency-tree/-/dependency-tree-10.0.9.tgz", + "integrity": "sha512-dwc59FRIsht+HfnTVM0BCjJaEWxdq2YAvEDy4/Hn6CwS3CBWMtFnL3aZGAkQn3XCYxk/YcTDE4jX2Q7bFTwCjA==", + "dependencies": { + "commander": "^10.0.1", + "filing-cabinet": "^4.1.6", + "precinct": "^11.0.5", + "typescript": "^5.0.4" + }, + "bin": { + "dependency-tree": "bin/cli.js" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/dependency-tree/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "engines": { + "node": ">=14" + } + }, + "node_modules/dependency-tree/node_modules/typescript": { + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/destroy": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", @@ -3629,92 +3798,267 @@ "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", "dev": true }, - "node_modules/diff-sequences": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", - "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", - "dev": true, + "node_modules/detective-amd": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/detective-amd/-/detective-amd-5.0.2.tgz", + "integrity": "sha512-XFd/VEQ76HSpym80zxM68ieB77unNuoMwopU2TFT/ErUk5n4KvUTwW4beafAVUugrjV48l4BmmR0rh2MglBaiA==", + "dependencies": { + "ast-module-types": "^5.0.0", + "escodegen": "^2.0.0", + "get-amd-module-type": "^5.0.1", + "node-source-walk": "^6.0.1" + }, + "bin": { + "detective-amd": "bin/cli.js" + }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=14" } }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, + "node_modules/detective-cjs": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/detective-cjs/-/detective-cjs-5.0.1.tgz", + "integrity": "sha512-6nTvAZtpomyz/2pmEmGX1sXNjaqgMplhQkskq2MLrar0ZAIkHMrDhLXkRiK2mvbu9wSWr0V5/IfiTrZqAQMrmQ==", "dependencies": { - "path-type": "^4.0.0" + "ast-module-types": "^5.0.0", + "node-source-walk": "^6.0.0" }, "engines": { - "node": ">=8" + "node": ">=14" } }, - "node_modules/dns-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", - "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=", - "dev": true - }, - "node_modules/dns-packet": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.4.tgz", - "integrity": "sha512-BQ6F4vycLXBvdrJZ6S3gZewt6rcrks9KBgM9vrhW+knGRqc8uEdT7fuCwloc7nny5xNoMJ17HGH0R/6fpo8ECA==", - "dev": true, + "node_modules/detective-es6": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/detective-es6/-/detective-es6-4.0.1.tgz", + "integrity": "sha512-k3Z5tB4LQ8UVHkuMrFOlvb3GgFWdJ9NqAa2YLUU/jTaWJIm+JJnEh4PsMc+6dfT223Y8ACKOaC0qcj7diIhBKw==", "dependencies": { - "ip": "^1.1.0", - "safe-buffer": "^5.0.1" + "node-source-walk": "^6.0.1" + }, + "engines": { + "node": ">=14" } }, - "node_modules/dns-txt": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz", - "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=", - "dev": true, + "node_modules/detective-postcss": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/detective-postcss/-/detective-postcss-6.1.3.tgz", + "integrity": "sha512-7BRVvE5pPEvk2ukUWNQ+H2XOq43xENWbH0LcdCE14mwgTBEAMoAx+Fc1rdp76SmyZ4Sp48HlV7VedUnP6GA1Tw==", "dependencies": { - "buffer-indexof": "^1.0.0" + "is-url": "^1.2.4", + "postcss": "^8.4.23", + "postcss-values-parser": "^6.0.2" + }, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, + "node_modules/detective-sass": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/detective-sass/-/detective-sass-5.0.3.tgz", + "integrity": "sha512-YsYT2WuA8YIafp2RVF5CEfGhhyIVdPzlwQgxSjK+TUm3JoHP+Tcorbk3SfG0cNZ7D7+cYWa0ZBcvOaR0O8+LlA==", "dependencies": { - "esutils": "^2.0.2" + "gonzales-pe": "^4.3.0", + "node-source-walk": "^6.0.1" }, "engines": { - "node": ">=6.0.0" + "node": ">=14" } }, - "node_modules/domexception": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", - "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", - "dev": true, + "node_modules/detective-scss": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/detective-scss/-/detective-scss-4.0.3.tgz", + "integrity": "sha512-VYI6cHcD0fLokwqqPFFtDQhhSnlFWvU614J42eY6G0s8c+MBhi9QAWycLwIOGxlmD8I/XvGSOUV1kIDhJ70ZPg==", "dependencies": { - "webidl-conversions": "^5.0.0" + "gonzales-pe": "^4.3.0", + "node-source-walk": "^6.0.1" }, "engines": { - "node": ">=8" + "node": ">=14" } }, - "node_modules/domexception/node_modules/webidl-conversions": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", - "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", - "dev": true, + "node_modules/detective-stylus": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/detective-stylus/-/detective-stylus-4.0.0.tgz", + "integrity": "sha512-TfPotjhszKLgFBzBhTOxNHDsutIxx9GTWjrL5Wh7Qx/ydxKhwUrlSFeLIn+ZaHPF+h0siVBkAQSuy6CADyTxgQ==", "engines": { - "node": ">=8" + "node": ">=14" } }, - "node_modules/dot-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", - "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", - "dev": true, + "node_modules/detective-typescript": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/detective-typescript/-/detective-typescript-11.2.0.tgz", + "integrity": "sha512-ARFxjzizOhPqs1fYC/2NMC3N4jrQ6HvVflnXBTRqNEqJuXwyKLRr9CrJwkRcV/SnZt1sNXgsF6FPm0x57Tq0rw==", "dependencies": { - "no-case": "^3.0.4", + "@typescript-eslint/typescript-estree": "^5.62.0", + "ast-module-types": "^5.0.0", + "node-source-walk": "^6.0.2", + "typescript": "^5.4.4" + }, + "engines": { + "node": "^14.14.0 || >=16.0.0" + } + }, + "node_modules/detective-typescript/node_modules/@typescript-eslint/types": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", + "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/detective-typescript/node_modules/@typescript-eslint/typescript-estree": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", + "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/detective-typescript/node_modules/@typescript-eslint/visitor-keys": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", + "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/detective-typescript/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/detective-typescript/node_modules/typescript": { + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/diff-sequences": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", + "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", + "dev": true, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dns-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", + "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=", + "dev": true + }, + "node_modules/dns-packet": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.4.tgz", + "integrity": "sha512-BQ6F4vycLXBvdrJZ6S3gZewt6rcrks9KBgM9vrhW+knGRqc8uEdT7fuCwloc7nny5xNoMJ17HGH0R/6fpo8ECA==", + "dev": true, + "dependencies": { + "ip": "^1.1.0", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/dns-txt": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz", + "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=", + "dev": true, + "dependencies": { + "buffer-indexof": "^1.0.0" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/domexception": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", + "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", + "dev": true, + "dependencies": { + "webidl-conversions": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/domexception/node_modules/webidl-conversions": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", + "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dev": true, + "dependencies": { + "no-case": "^3.0.4", "tslib": "^2.0.3" } }, @@ -3733,8 +4077,7 @@ "node_modules/electron-to-chromium": { "version": "1.4.740", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.740.tgz", - "integrity": "sha512-Yvg5i+iyv7Xm18BRdVPVm8lc7kgxM3r6iwqCH2zB7QZy1kZRNmd0Zqm0zcD9XoFREE5/5rwIuIAOT+/mzGcnZg==", - "dev": true + "integrity": "sha512-Yvg5i+iyv7Xm18BRdVPVm8lc7kgxM3r6iwqCH2zB7QZy1kZRNmd0Zqm0zcD9XoFREE5/5rwIuIAOT+/mzGcnZg==" }, "node_modules/emittery": { "version": "0.8.1", @@ -3776,7 +4119,6 @@ "version": "5.16.0", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.16.0.tgz", "integrity": "sha512-O+QWCviPNSSLAD9Ucn8Awv+poAkqn3T1XY5/N7kR7rQO9yfSGWkYZDwpJ+iKF7B8rxaQKWngSqACpgzeapSyoA==", - "dev": true, "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" @@ -3875,8 +4217,7 @@ "node_modules/es-module-lexer": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.0.tgz", - "integrity": "sha512-pqrTKmwEIgafsYZAGw9kszYzmagcE/n4dbgwGWLEXg7J4QFJVQRBld8j3Q3GNez79jzxZshq0bcT962QHOghjw==", - "dev": true + "integrity": "sha512-pqrTKmwEIgafsYZAGw9kszYzmagcE/n4dbgwGWLEXg7J4QFJVQRBld8j3Q3GNez79jzxZshq0bcT962QHOghjw==" }, "node_modules/es-to-primitive": { "version": "1.2.1", @@ -3899,7 +4240,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true, "engines": { "node": ">=6" } @@ -3926,7 +4266,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", - "dev": true, "dependencies": { "esprima": "^4.0.1", "estraverse": "^5.2.0", @@ -3948,7 +4287,6 @@ "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, "engines": { "node": ">=4.0" } @@ -3957,7 +4295,6 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dev": true, "dependencies": { "prelude-ls": "~1.1.2", "type-check": "~0.3.2" @@ -3970,7 +4307,6 @@ "version": "0.8.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dev": true, "dependencies": { "deep-is": "~0.1.3", "fast-levenshtein": "~2.0.6", @@ -3987,7 +4323,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true, "engines": { "node": ">= 0.8.0" } @@ -3996,7 +4331,6 @@ "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "dev": true, "dependencies": { "prelude-ls": "~1.1.2" }, @@ -4263,7 +4597,6 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" @@ -4344,7 +4677,6 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, "bin": { "esparse": "bin/esparse.js", "esvalidate": "bin/esvalidate.js" @@ -4378,7 +4710,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, "dependencies": { "estraverse": "^5.2.0" }, @@ -4390,7 +4721,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true, "engines": { "node": ">=4.0" } @@ -4399,7 +4729,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, "engines": { "node": ">=4.0" } @@ -4408,7 +4737,6 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -4432,7 +4760,6 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "dev": true, "engines": { "node": ">=0.8.x" } @@ -4681,14 +5008,12 @@ "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "node_modules/fast-glob": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", - "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -4704,7 +5029,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, "dependencies": { "is-glob": "^4.0.1" }, @@ -4715,14 +5039,12 @@ "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" }, "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" }, "node_modules/fastest-levenshtein": { "version": "1.0.12", @@ -4734,7 +5056,6 @@ "version": "1.11.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.1.tgz", "integrity": "sha512-HOnr8Mc60eNYl1gzwp6r5RoUyAn5/glBolUzP/Ez6IFVPMPirxn/9phgL6zhOtaTy7ISwPvQ+wT+hfcRZh/bzw==", - "dev": true, "dependencies": { "reusify": "^1.0.4" } @@ -4785,11 +5106,68 @@ "dev": true, "optional": true }, + "node_modules/filing-cabinet": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/filing-cabinet/-/filing-cabinet-4.2.0.tgz", + "integrity": "sha512-YZ21ryzRcyqxpyKggdYSoXx//d3sCJzM3lsYoaeg/FyXdADGJrUl+BW1KIglaVLJN5BBcMtWylkygY8zBp2MrQ==", + "dependencies": { + "app-module-path": "^2.2.0", + "commander": "^10.0.1", + "enhanced-resolve": "^5.14.1", + "is-relative-path": "^1.0.2", + "module-definition": "^5.0.1", + "module-lookup-amd": "^8.0.5", + "resolve": "^1.22.3", + "resolve-dependency-path": "^3.0.2", + "sass-lookup": "^5.0.1", + "stylus-lookup": "^5.0.1", + "tsconfig-paths": "^4.2.0", + "typescript": "^5.0.4" + }, + "bin": { + "filing-cabinet": "bin/cli.js" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/filing-cabinet/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "engines": { + "node": ">=14" + } + }, + "node_modules/filing-cabinet/node_modules/tsconfig-paths": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", + "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", + "dependencies": { + "json5": "^2.2.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/filing-cabinet/node_modules/typescript": { + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, "dependencies": { "to-regex-range": "^5.0.1" }, @@ -4937,8 +5315,7 @@ "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, "node_modules/fsevents": { "version": "2.3.2", @@ -4958,7 +5335,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -4978,6 +5354,18 @@ "node": ">=6.9.0" } }, + "node_modules/get-amd-module-type": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/get-amd-module-type/-/get-amd-module-type-5.0.1.tgz", + "integrity": "sha512-jb65zDeHyDjFR1loOVk0HQGM5WNwoGB8aLWy3LKCieMKol0/ProHkhO2X1JxojuN10vbz1qNn09MJ7tNp7qMzw==", + "dependencies": { + "ast-module-types": "^5.0.0", + "node-source-walk": "^6.0.1" + }, + "engines": { + "node": ">=14" + } + }, "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -5001,6 +5389,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-own-enumerable-property-symbols": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", + "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==" + }, "node_modules/get-package-type": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", @@ -5035,7 +5428,6 @@ "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -5066,8 +5458,7 @@ "node_modules/glob-to-regexp": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "dev": true + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" }, "node_modules/globals": { "version": "13.10.0", @@ -5088,7 +5479,6 @@ "version": "11.1.0", "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", @@ -5108,16 +5498,28 @@ "version": "5.3.1", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", - "dev": true, "engines": { "node": ">= 4" } }, + "node_modules/gonzales-pe": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/gonzales-pe/-/gonzales-pe-4.3.0.tgz", + "integrity": "sha512-otgSPpUmdWJ43VXyiNgEYE4luzHCL2pz4wQ0OnDluC6Eg4Ko3Vexy/SrSynglw/eR+OhkzmqFCZa/OFa/RgAOQ==", + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "gonzales": "bin/gonzales.js" + }, + "engines": { + "node": ">=0.6.0" + } + }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" }, "node_modules/handle-thing": { "version": "2.0.1", @@ -5150,7 +5552,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, "engines": { "node": ">=8" } @@ -5234,7 +5635,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, "dependencies": { "function-bind": "^1.1.2" }, @@ -5618,6 +6018,36 @@ "node": ">=10.17.0" } }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/ignore": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", @@ -5745,7 +6175,6 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -5754,8 +6183,12 @@ "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" }, "node_modules/internal-ip": { "version": "4.3.0", @@ -5915,7 +6348,6 @@ "version": "2.13.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", - "dev": true, "dependencies": { "hasown": "^2.0.0" }, @@ -5995,7 +6427,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -6022,7 +6453,6 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, "dependencies": { "is-extglob": "^2.1.1" }, @@ -6030,6 +6460,14 @@ "node": ">=0.10.0" } }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "engines": { + "node": ">=8" + } + }, "node_modules/is-negative-zero": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", @@ -6046,7 +6484,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, "engines": { "node": ">=0.12.0" } @@ -6063,6 +6500,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-path-cwd": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", @@ -6130,6 +6575,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", + "integrity": "sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-relative-path": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-relative-path/-/is-relative-path-1.0.2.tgz", + "integrity": "sha512-i1h+y50g+0hRbBD+dbnInl3JlJ702aar58snAeX+MxBAPvzXGej7sYoPMhlnykabt0ZzCJNBEyzMlekuQZN7fA==" + }, "node_modules/is-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", @@ -6172,6 +6630,33 @@ "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", "dev": true }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-url": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz", + "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==" + }, + "node_modules/is-url-superb": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-url-superb/-/is-url-superb-4.0.0.tgz", + "integrity": "sha512-GI+WjezhPPcbM+tqE9LnmsY5qqjwHzTvjJ36wxYX5ujNXefSUJ/T17r5bqDV8yLhcgB59KTPNOc9O9cmHTPWsA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-windows": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", @@ -6977,7 +7462,6 @@ "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", - "dev": true, "dependencies": { "@types/node": "*", "merge-stream": "^2.0.0", @@ -6991,7 +7475,6 @@ "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -7121,14 +7604,12 @@ "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", @@ -7140,7 +7621,6 @@ "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, "bin": { "json5": "lib/cli.js" }, @@ -7219,7 +7699,6 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz", "integrity": "sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw==", - "dev": true, "engines": { "node": ">=6.11.5" } @@ -7267,6 +7746,21 @@ "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", "dev": true }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/loglevel": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.8.0.tgz", @@ -7299,12 +7793,57 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, "dependencies": { "yallist": "^4.0.0" }, "engines": { - "node": ">=10" + "node": ">=10" + } + }, + "node_modules/madge": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/madge/-/madge-7.0.0.tgz", + "integrity": "sha512-x9eHkBWoCJ2B8yGesWf8LRucarkbH5P3lazqgvmxe4xn5U2Meyfu906iG9mBB1RnY/f4D+gtELWdiz1k6+jAZA==", + "dependencies": { + "chalk": "^4.1.2", + "commander": "^7.2.0", + "commondir": "^1.0.1", + "debug": "^4.3.4", + "dependency-tree": "^10.0.9", + "ora": "^5.4.1", + "pluralize": "^8.0.0", + "precinct": "^11.0.5", + "pretty-ms": "^7.0.1", + "rc": "^1.2.8", + "stream-to-array": "^2.3.0", + "ts-graphviz": "^1.8.1", + "walkdir": "^0.4.1" + }, + "bin": { + "madge": "bin/cli.js" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "individual", + "url": "https://www.paypal.me/pahen" + }, + "peerDependencies": { + "typescript": "^3.9.5 || ^4.9.5 || ^5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/madge/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "engines": { + "node": ">= 10" } }, "node_modules/make-dir": { @@ -7395,14 +7934,12 @@ "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, "engines": { "node": ">= 8" } @@ -7426,7 +7963,6 @@ "version": "4.0.4", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", - "dev": true, "dependencies": { "braces": "^3.0.1", "picomatch": "^2.2.3" @@ -7451,7 +7987,6 @@ "version": "1.48.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz", "integrity": "sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ==", - "dev": true, "engines": { "node": ">= 0.6" } @@ -7460,7 +7995,6 @@ "version": "2.1.31", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.31.tgz", "integrity": "sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==", - "dev": true, "dependencies": { "mime-db": "1.48.0" }, @@ -7472,7 +8006,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, "engines": { "node": ">=6" } @@ -7487,7 +8020,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -7498,8 +8030,7 @@ "node_modules/minimist": { "version": "1.2.6", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "dev": true + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" }, "node_modules/mixin-deep": { "version": "1.3.2", @@ -7538,11 +8069,50 @@ "mkdirp": "bin/cmd.js" } }, + "node_modules/module-definition": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/module-definition/-/module-definition-5.0.1.tgz", + "integrity": "sha512-kvw3B4G19IXk+BOXnYq/D/VeO9qfHaapMeuS7w7sNUqmGaA6hywdFHMi+VWeR9wUScXM7XjoryTffCZ5B0/8IA==", + "dependencies": { + "ast-module-types": "^5.0.0", + "node-source-walk": "^6.0.1" + }, + "bin": { + "module-definition": "bin/cli.js" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/module-lookup-amd": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/module-lookup-amd/-/module-lookup-amd-8.0.5.tgz", + "integrity": "sha512-vc3rYLjDo5Frjox8NZpiyLXsNWJ5BWshztc/5KSOMzpg9k5cHH652YsJ7VKKmtM4SvaxuE9RkrYGhiSjH3Ehow==", + "dependencies": { + "commander": "^10.0.1", + "glob": "^7.2.3", + "requirejs": "^2.3.6", + "requirejs-config-file": "^4.0.0" + }, + "bin": { + "lookup-amd": "bin/cli.js" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/module-lookup-amd/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "engines": { + "node": ">=14" + } + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/multicast-dns": { "version": "6.2.3", @@ -7570,6 +8140,23 @@ "dev": true, "optional": true }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, "node_modules/nanomatch": { "version": "1.2.13", "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", @@ -7686,8 +8273,7 @@ "node_modules/neo-async": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" }, "node_modules/nice-try": { "version": "1.0.5", @@ -7729,8 +8315,18 @@ "node_modules/node-releases": { "version": "2.0.14", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", - "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", - "dev": true + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==" + }, + "node_modules/node-source-walk": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/node-source-walk/-/node-source-walk-6.0.2.tgz", + "integrity": "sha512-jn9vOIK/nfqoFCcpK89/VCVaLg1IHE6UVfDOzvqmANaJ/rWCTEdH8RZ1V278nv2jr36BJdyQXIAavBLXpzdlag==", + "dependencies": { + "@babel/parser": "^7.21.8" + }, + "engines": { + "node": ">=14" + } }, "node_modules/normalize-package-data": { "version": "2.5.0", @@ -7939,7 +8535,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, "dependencies": { "wrappy": "1" } @@ -7948,7 +8543,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, "dependencies": { "mimic-fn": "^2.1.0" }, @@ -7988,6 +8582,28 @@ "node": ">= 0.8.0" } }, + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/original": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz", @@ -8125,6 +8741,14 @@ "node": ">=4" } }, + "node_modules/parse-ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-2.1.0.tgz", + "integrity": "sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA==", + "engines": { + "node": ">=6" + } + }, "node_modules/parse5": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", @@ -8184,7 +8808,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -8207,8 +8830,7 @@ "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, "node_modules/path-to-regexp": { "version": "0.1.7", @@ -8220,7 +8842,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, "engines": { "node": ">=8" } @@ -8228,14 +8849,12 @@ "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" }, "node_modules/picomatch": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", - "dev": true, "engines": { "node": ">=8.6" }, @@ -8306,6 +8925,14 @@ "node": ">=4" } }, + "node_modules/pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", + "engines": { + "node": ">=4" + } + }, "node_modules/portfinder": { "version": "1.0.28", "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", @@ -8338,6 +8965,82 @@ "node": ">=0.10.0" } }, + "node_modules/postcss": { + "version": "8.4.38", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", + "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.0.0", + "source-map-js": "^1.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-values-parser": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-values-parser/-/postcss-values-parser-6.0.2.tgz", + "integrity": "sha512-YLJpK0N1brcNJrs9WatuJFtHaV9q5aAOj+S4DI5S7jgHlRfm0PIbDCAFRYMQD5SHq7Fy6xsDhyutgS0QOAs0qw==", + "dependencies": { + "color-name": "^1.1.4", + "is-url-superb": "^4.0.0", + "quote-unquote": "^1.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "postcss": "^8.2.9" + } + }, + "node_modules/precinct": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/precinct/-/precinct-11.0.5.tgz", + "integrity": "sha512-oHSWLC8cL/0znFhvln26D14KfCQFFn4KOLSw6hmLhd+LQ2SKt9Ljm89but76Pc7flM9Ty1TnXyrA2u16MfRV3w==", + "dependencies": { + "@dependents/detective-less": "^4.1.0", + "commander": "^10.0.1", + "detective-amd": "^5.0.2", + "detective-cjs": "^5.0.1", + "detective-es6": "^4.0.1", + "detective-postcss": "^6.1.3", + "detective-sass": "^5.0.3", + "detective-scss": "^4.0.3", + "detective-stylus": "^4.0.0", + "detective-typescript": "^11.1.0", + "module-definition": "^5.0.1", + "node-source-walk": "^6.0.2" + }, + "bin": { + "precinct": "bin/cli.js" + }, + "engines": { + "node": "^14.14.0 || >=16.0.0" + } + }, + "node_modules/precinct/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "engines": { + "node": ">=14" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -8388,6 +9091,20 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/pretty-ms": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-7.0.1.tgz", + "integrity": "sha512-973driJZvxiGOQ5ONsFhOF/DtzPMOMtgC11kCpUrPGMTgqp2q/1gwzCquocrN33is0VZ5GFHXZYMM9l6h67v2Q==", + "dependencies": { + "parse-ms": "^2.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -8455,7 +9172,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true, "engines": { "node": ">=6" } @@ -8489,7 +9205,6 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, "funding": [ { "type": "github", @@ -8505,11 +9220,15 @@ } ] }, + "node_modules/quote-unquote": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/quote-unquote/-/quote-unquote-1.0.0.tgz", + "integrity": "sha512-twwRO/ilhlG/FIgYeKGFqyHhoEhqgnKVkcmqMKi2r524gz3ZbDTcyFt38E9xjJI2vT+KbRNHVbnJ/e0I25Azwg==" + }, "node_modules/randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, "dependencies": { "safe-buffer": "^5.1.0" } @@ -8559,6 +9278,28 @@ "node": ">=0.10.0" } }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", @@ -8947,6 +9688,30 @@ "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", "dev": true }, + "node_modules/requirejs": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/requirejs/-/requirejs-2.3.6.tgz", + "integrity": "sha512-ipEzlWQe6RK3jkzikgCupiTbTvm4S0/CAU5GlgptkN5SO6F3u0UD0K18wy6ErDqiCyP4J4YYe1HuAShvsxePLg==", + "bin": { + "r_js": "bin/r.js", + "r.js": "bin/r.js" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/requirejs-config-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/requirejs-config-file/-/requirejs-config-file-4.0.0.tgz", + "integrity": "sha512-jnIre8cbWOyvr8a5F2KuqBnY+SDA4NXr/hzEZJG79Mxm2WiFQz2dzhC8ibtPJS7zkmBEl1mxSwp5HhC1W4qpxw==", + "dependencies": { + "esprima": "^4.0.0", + "stringify-object": "^3.2.1" + }, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", @@ -8957,7 +9722,6 @@ "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", - "dev": true, "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", @@ -8991,6 +9755,14 @@ "node": ">=8" } }, + "node_modules/resolve-dependency-path": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/resolve-dependency-path/-/resolve-dependency-path-3.0.2.tgz", + "integrity": "sha512-Tz7zfjhLfsvR39ADOSk9us4421J/1ztVBo4rWUkF38hgHK5m0OCZ3NxFVpqHRkjctnwVa15igEUHFJp8MCS7vA==", + "engines": { + "node": ">=14" + } + }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -9016,6 +9788,18 @@ "node": ">=10" } }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/ret": { "version": "0.1.15", "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", @@ -9038,7 +9822,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" @@ -9063,7 +9846,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, "funding": [ { "type": "github", @@ -9086,7 +9868,6 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, "funding": [ { "type": "github", @@ -9114,8 +9895,29 @@ "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/sass-lookup": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/sass-lookup/-/sass-lookup-5.0.1.tgz", + "integrity": "sha512-t0X5PaizPc2H4+rCwszAqHZRtr4bugo4pgiCvrBFvIX0XFxnr29g77LJcpyj9A0DcKf7gXMLcgvRjsonYI6x4g==", + "dependencies": { + "commander": "^10.0.1" + }, + "bin": { + "sass-lookup": "bin/cli.js" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/sass-lookup/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "engines": { + "node": ">=14" + } }, "node_modules/saxes": { "version": "5.0.1", @@ -9133,7 +9935,6 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", - "dev": true, "dependencies": { "@types/json-schema": "^7.0.8", "ajv": "^6.12.5", @@ -9166,7 +9967,6 @@ "version": "7.6.0", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", - "dev": true, "dependencies": { "lru-cache": "^6.0.0" }, @@ -9226,7 +10026,6 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", - "dev": true, "dependencies": { "randombytes": "^2.1.0" } @@ -9369,8 +10168,7 @@ "node_modules/signal-exit": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", - "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", - "dev": true + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" }, "node_modules/sisteransi": { "version": "1.0.5", @@ -9382,7 +10180,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, "engines": { "node": ">=8" } @@ -9578,11 +10375,38 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, "engines": { "node": ">=0.10.0" } }, + "node_modules/source-map-js": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-loader": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-3.0.2.tgz", + "integrity": "sha512-BokxPoLjyl3iOrgkWaakaxqnelAJSS+0V+De0kKIq6lyWrXuiPgYTGp6z3iHmqljKAaLXwZa+ctD8GccRJeVvg==", + "dependencies": { + "abab": "^2.0.5", + "iconv-lite": "^0.6.3", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, "node_modules/source-map-resolve": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", @@ -9601,7 +10425,6 @@ "version": "0.5.21", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -9776,11 +10599,18 @@ "node": ">= 0.6" } }, + "node_modules/stream-to-array": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/stream-to-array/-/stream-to-array-2.3.0.tgz", + "integrity": "sha512-UsZtOYEn4tWU2RGLOXr/o/xjRBftZRlG3dEWoaHr8j4GuypJ3isitGbVyjQKAuMu+xbiop8q224TjiZWc4XTZA==", + "dependencies": { + "any-promise": "^1.1.0" + } + }, "node_modules/string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, "dependencies": { "safe-buffer": "~5.1.0" } @@ -9788,8 +10618,7 @@ "node_modules/string_decoder/node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "node_modules/string-length": { "version": "4.0.2", @@ -9844,11 +10673,23 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/stringify-object": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", + "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", + "dependencies": { + "get-own-enumerable-property-symbols": "^3.0.0", + "is-obj": "^1.0.1", + "is-regexp": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/strip-ansi": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, "dependencies": { "ansi-regex": "^5.0.0" }, @@ -9860,7 +10701,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true, "engines": { "node": ">=4" } @@ -9895,11 +10735,32 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/stylus-lookup": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/stylus-lookup/-/stylus-lookup-5.0.1.tgz", + "integrity": "sha512-tLtJEd5AGvnVy4f9UHQMw4bkJJtaAcmo54N+ovQBjDY3DuWyK9Eltxzr5+KG0q4ew6v2EHyuWWNnHeiw/Eo7rQ==", + "dependencies": { + "commander": "^10.0.1" + }, + "bin": { + "stylus-lookup": "bin/cli.js" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/stylus-lookup/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "engines": { + "node": ">=14" + } + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -9924,7 +10785,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -9981,7 +10841,6 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.0.tgz", "integrity": "sha512-FBk4IesMV1rBxX2tfiK8RAmogtWn53puLOQlvO8XuwlgxcYbP4mVPS9Ph4aeamSyyVjOl24aYWAuc8U5kCVwMw==", - "dev": true, "engines": { "node": ">=6" } @@ -10006,7 +10865,6 @@ "version": "5.30.3", "resolved": "https://registry.npmjs.org/terser/-/terser-5.30.3.tgz", "integrity": "sha512-STdUgOUx8rLbMGO9IOwHLpCqolkDITFFQSMYYwKE1N2lY6MVSaeoi10z/EhWxRc6ybqoVmKSkhKYH/XUpl7vSA==", - "dev": true, "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.8.2", @@ -10024,7 +10882,6 @@ "version": "5.3.10", "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", - "dev": true, "dependencies": { "@jridgewell/trace-mapping": "^0.3.20", "jest-worker": "^27.4.5", @@ -10058,7 +10915,6 @@ "version": "8.11.3", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", - "dev": true, "bin": { "acorn": "bin/acorn" }, @@ -10161,7 +11017,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, "dependencies": { "is-number": "^7.0.0" }, @@ -10280,6 +11135,18 @@ "node": ">=8" } }, + "node_modules/ts-graphviz": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/ts-graphviz/-/ts-graphviz-1.8.2.tgz", + "integrity": "sha512-5YhbFoHmjxa7pgQLkB07MtGnGJ/yhvjmc9uhsnDBEICME6gkPf83SBwLDQqGDoCa3XzUMWLk1AU2Wn1u1naDtA==", + "engines": { + "node": ">=14.16" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ts-graphviz" + } + }, "node_modules/ts-jest": { "version": "27.1.4", "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-27.1.4.tgz", @@ -10375,14 +11242,12 @@ "node_modules/tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, "node_modules/tsutils": { "version": "3.21.0", "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, "dependencies": { "tslib": "^1.8.1" }, @@ -10452,7 +11317,6 @@ "version": "4.9.5", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", - "dev": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -10571,7 +11435,6 @@ "version": "1.0.13", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", - "dev": true, "funding": [ { "type": "opencollective", @@ -10601,7 +11464,6 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, "dependencies": { "punycode": "^2.1.0" } @@ -10651,8 +11513,7 @@ "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, "node_modules/utils-merge": { "version": "1.0.1", @@ -10742,6 +11603,14 @@ "node": ">=10" } }, + "node_modules/walkdir": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/walkdir/-/walkdir-0.4.1.tgz", + "integrity": "sha512-3eBwRyEln6E1MSzcxcVpQIhRG8Q1jLvEqRmCZqS3dsfXEDR/AhOF4d+jHg1qvDCpYaVRZjENPQyrVxAkQqxPgQ==", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/walker": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", @@ -10755,7 +11624,6 @@ "version": "2.4.1", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.1.tgz", "integrity": "sha512-8wrBCMtVhqcXP2Sup1ctSkga6uc2Bx0IIvKyT7yTFier5AXHooSI+QyQQAtTb7+E0IUCCKyTFmXqdqgum2XWGg==", - "dev": true, "dependencies": { "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.1.2" @@ -10773,6 +11641,14 @@ "minimalistic-assert": "^1.0.0" } }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dependencies": { + "defaults": "^1.0.3" + } + }, "node_modules/webidl-conversions": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", @@ -10786,7 +11662,6 @@ "version": "5.91.0", "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.91.0.tgz", "integrity": "sha512-rzVwlLeBWHJbmgTC/8TvAcu5vpJNII+MelQpylD4jNERPwpBJOE2lEcko1zJX3QJeLjTTAnQxn/OJ8bjDzVQaw==", - "dev": true, "dependencies": { "@types/eslint-scope": "^3.7.3", "@types/estree": "^1.0.5", @@ -11172,7 +12047,6 @@ "version": "3.2.3", "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", - "dev": true, "engines": { "node": ">=10.13.0" } @@ -11181,7 +12055,6 @@ "version": "8.11.3", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", - "dev": true, "bin": { "acorn": "bin/acorn" }, @@ -11193,7 +12066,6 @@ "version": "1.9.0", "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", - "dev": true, "peerDependencies": { "acorn": "^8" } @@ -11309,7 +12181,6 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -11408,8 +12279,7 @@ "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "node_modules/write-file-atomic": { "version": "3.0.3", @@ -11453,8 +12323,7 @@ "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/yargs": { "version": "13.3.2", @@ -11885,8 +12754,7 @@ "@babel/parser": { "version": "7.24.4", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.4.tgz", - "integrity": "sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg==", - "dev": true + "integrity": "sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg==" }, "@babel/plugin-syntax-async-generators": { "version": "7.8.4", @@ -12078,6 +12946,15 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, + "@dependents/detective-less": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@dependents/detective-less/-/detective-less-4.1.0.tgz", + "integrity": "sha512-KrkT6qO5NxqNfy68sBl6CTSoJ4SNDIS5iQArkibhlbGU4LaDukZ3q2HIkh8aUKDio6o4itU4xDR7t82Y2eP1Bg==", + "requires": { + "gonzales-pe": "^4.3.0", + "node-source-walk": "^6.0.1" + } + }, "@discoveryjs/json-ext": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.3.tgz", @@ -12383,7 +13260,6 @@ "version": "0.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", - "dev": true, "requires": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", @@ -12393,20 +13269,17 @@ "@jridgewell/resolve-uri": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==" }, "@jridgewell/set-array": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==" }, "@jridgewell/source-map": { "version": "0.3.6", "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", - "dev": true, "requires": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25" @@ -12415,14 +13288,12 @@ "@jridgewell/sourcemap-codec": { "version": "1.4.15", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" }, "@jridgewell/trace-mapping": { "version": "0.3.25", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, "requires": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -12432,7 +13303,6 @@ "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, "requires": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -12441,14 +13311,12 @@ "@nodelib/fs.stat": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==" }, "@nodelib/fs.walk": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, "requires": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -12472,6 +13340,20 @@ "@sinonjs/commons": "^1.7.0" } }, + "@supalosa/oldschool-trainer-sdk": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/@supalosa/oldschool-trainer-sdk/-/oldschool-trainer-sdk-0.0.9.tgz", + "integrity": "sha512-HUBSysNtoZdEUdZtF4U2AA++86dd9Enp6E+BKWAtK+Qy7bz/irTBA9lQWcipRc9sblOE6M29Jg7yK2YBnyWg3w==", + "requires": { + "@types/new-relic-browser": "^0.1118.2", + "@types/offscreencanvas": "^2019.6.4", + "chebyshev": "^0.2.1", + "color-scales": "^3.0.2", + "madge": "^7.0.0", + "source-map-loader": "^3.0.0", + "three": "^0.163.0" + } + }, "@tootallnate/once": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", @@ -12529,7 +13411,6 @@ "version": "8.56.9", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.9.tgz", "integrity": "sha512-W4W3KcqzjJ0sHg2vAq9vfml6OhsJ53TcUjUqfzzZf/EChUtwspszj/S0pzMxnfRcO55/iGq47dscXw71Fxc4Zg==", - "dev": true, "requires": { "@types/estree": "*", "@types/json-schema": "*" @@ -12539,7 +13420,6 @@ "version": "3.7.7", "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", - "dev": true, "requires": { "@types/eslint": "*", "@types/estree": "*" @@ -12548,8 +13428,7 @@ "@types/estree": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", - "dev": true + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==" }, "@types/glob": { "version": "7.2.0", @@ -12607,8 +13486,7 @@ "@types/json-schema": { "version": "7.0.11", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", - "dev": true + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==" }, "@types/lodash": { "version": "4.14.171", @@ -12622,11 +13500,20 @@ "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==", "dev": true }, + "@types/new-relic-browser": { + "version": "0.1118.2", + "resolved": "https://registry.npmjs.org/@types/new-relic-browser/-/new-relic-browser-0.1118.2.tgz", + "integrity": "sha512-Cy3qMm3QVZT0HmpFxUsc204AdWa4yWX1yJsFhdBqZgecUBYDq86ljDmJQQxUk/4yPwCQ2C73nRLMb2jH3CnbrA==" + }, "@types/node": { "version": "16.4.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-16.4.0.tgz", - "integrity": "sha512-HrJuE7Mlqcjj+00JqMWpZ3tY8w7EUd+S0U3L1+PQSWiXZbOgyQDvi+ogoUxaHApPJq5diKxYBQwA3iIlNcPqOg==", - "dev": true + "integrity": "sha512-HrJuE7Mlqcjj+00JqMWpZ3tY8w7EUd+S0U3L1+PQSWiXZbOgyQDvi+ogoUxaHApPJq5diKxYBQwA3iIlNcPqOg==" + }, + "@types/offscreencanvas": { + "version": "2019.7.3", + "resolved": "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.7.3.tgz", + "integrity": "sha512-ieXiYmgSRXUDeOntE1InxjWyvEelZGP63M+cGuquuRLuIKKT1osnkXjxev9B7d1nXSug5vpunx+gNlbVxMlC9A==" }, "@types/prettier": { "version": "2.4.4", @@ -12806,7 +13693,6 @@ "version": "1.12.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", - "dev": true, "requires": { "@webassemblyjs/helper-numbers": "1.11.6", "@webassemblyjs/helper-wasm-bytecode": "1.11.6" @@ -12815,26 +13701,22 @@ "@webassemblyjs/floating-point-hex-parser": { "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", - "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", - "dev": true + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==" }, "@webassemblyjs/helper-api-error": { "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", - "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", - "dev": true + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==" }, "@webassemblyjs/helper-buffer": { "version": "1.12.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", - "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==", - "dev": true + "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==" }, "@webassemblyjs/helper-numbers": { "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", - "dev": true, "requires": { "@webassemblyjs/floating-point-hex-parser": "1.11.6", "@webassemblyjs/helper-api-error": "1.11.6", @@ -12844,14 +13726,12 @@ "@webassemblyjs/helper-wasm-bytecode": { "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", - "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", - "dev": true + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==" }, "@webassemblyjs/helper-wasm-section": { "version": "1.12.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", - "dev": true, "requires": { "@webassemblyjs/ast": "1.12.1", "@webassemblyjs/helper-buffer": "1.12.1", @@ -12863,7 +13743,6 @@ "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", - "dev": true, "requires": { "@xtuc/ieee754": "^1.2.0" } @@ -12872,7 +13751,6 @@ "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", - "dev": true, "requires": { "@xtuc/long": "4.2.2" } @@ -12880,14 +13758,12 @@ "@webassemblyjs/utf8": { "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", - "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", - "dev": true + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==" }, "@webassemblyjs/wasm-edit": { "version": "1.12.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", - "dev": true, "requires": { "@webassemblyjs/ast": "1.12.1", "@webassemblyjs/helper-buffer": "1.12.1", @@ -12903,7 +13779,6 @@ "version": "1.12.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", - "dev": true, "requires": { "@webassemblyjs/ast": "1.12.1", "@webassemblyjs/helper-wasm-bytecode": "1.11.6", @@ -12916,7 +13791,6 @@ "version": "1.12.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", - "dev": true, "requires": { "@webassemblyjs/ast": "1.12.1", "@webassemblyjs/helper-buffer": "1.12.1", @@ -12928,7 +13802,6 @@ "version": "1.12.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", - "dev": true, "requires": { "@webassemblyjs/ast": "1.12.1", "@webassemblyjs/helper-api-error": "1.11.6", @@ -12942,7 +13815,6 @@ "version": "1.12.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", - "dev": true, "requires": { "@webassemblyjs/ast": "1.12.1", "@xtuc/long": "4.2.2" @@ -12974,20 +13846,17 @@ "@xtuc/ieee754": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==" }, "@xtuc/long": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "dev": true + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" }, "abab": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", - "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==", - "dev": true + "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==" }, "accepts": { "version": "1.3.7", @@ -13041,7 +13910,6 @@ "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, "requires": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -13060,7 +13928,6 @@ "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, "requires": {} }, "ansi-colors": { @@ -13095,18 +13962,21 @@ "ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "requires": { "color-convert": "^2.0.1" } }, + "any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==" + }, "anymatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", @@ -13117,6 +13987,11 @@ "picomatch": "^2.0.4" } }, + "app-module-path": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/app-module-path/-/app-module-path-2.2.0.tgz", + "integrity": "sha512-gkco+qxENJV+8vFcDiiFhuoSvRXb2a/QPqpSoWhVz829VNJfOTnELbBmPmNKFxf3xdNnw4DWCkzkDaavcX/1YQ==" + }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -13166,8 +14041,7 @@ "array-union": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==" }, "array-uniq": { "version": "1.0.3", @@ -13198,6 +14072,11 @@ "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", "dev": true }, + "ast-module-types": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ast-module-types/-/ast-module-types-5.0.0.tgz", + "integrity": "sha512-JvqziE0Wc0rXQfma0HZC/aY7URXHFuZV84fJRtP8u+lhp0JYCNd5wJzVXP45t0PH0Mej3ynlzvdyITYIu0G4LQ==" + }, "astral-regex": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", @@ -13311,8 +14190,7 @@ "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "base": { "version": "0.11.2", @@ -13369,6 +14247,11 @@ } } }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + }, "batch": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", @@ -13391,6 +14274,28 @@ "file-uri-to-path": "1.0.0" } }, + "bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "requires": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, "body-parser": { "version": "1.19.0", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", @@ -13459,7 +14364,6 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -13469,7 +14373,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, "requires": { "fill-range": "^7.0.1" } @@ -13484,7 +14387,6 @@ "version": "4.23.0", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", - "dev": true, "requires": { "caniuse-lite": "^1.0.30001587", "electron-to-chromium": "^1.4.668", @@ -13510,11 +14412,19 @@ "node-int64": "^0.4.0" } }, + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, "buffer-from": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", - "dev": true + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" }, "buffer-indexof": { "version": "1.1.1", @@ -13588,14 +14498,12 @@ "caniuse-lite": { "version": "1.0.30001611", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001611.tgz", - "integrity": "sha512-19NuN1/3PjA3QI8Eki55N8my4LzfkMCRLgCVfrl/slbSAchQfV0+GwjPrK3rq37As4UCLlM/DHajbKkAqbv92Q==", - "dev": true + "integrity": "sha512-19NuN1/3PjA3QI8Eki55N8my4LzfkMCRLgCVfrl/slbSAchQfV0+GwjPrK3rq37As4UCLlM/DHajbKkAqbv92Q==" }, "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -13607,6 +14515,11 @@ "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", "dev": true }, + "chebyshev": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/chebyshev/-/chebyshev-0.2.1.tgz", + "integrity": "sha512-FaLyrAPJ57VsPOfalGAVqVqjoX75V56ZbnPe74/NzR4+CzzC8Y65xdoRdH6w+xuMbead4/nJYDN6NFqbKUFkRw==" + }, "chokidar": { "version": "2.1.8", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", @@ -13826,8 +14739,7 @@ "chrome-trace-event": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", - "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", - "dev": true + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==" }, "ci-info": { "version": "3.3.0", @@ -13862,6 +14774,19 @@ "source-map": "~0.6.0" } }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==" + }, "cliui": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", @@ -13913,6 +14838,11 @@ } } }, + "clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==" + }, "clone-deep": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", @@ -13950,7 +14880,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "requires": { "color-name": "~1.1.4" } @@ -13958,8 +14887,12 @@ "color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "color-scales": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/color-scales/-/color-scales-3.0.2.tgz", + "integrity": "sha512-AwX0kUE1Ps6Gv0b8if20DAfgchAs5HRmr+ulBbP4anqcBqUevaj8S9OWVFlYynsfuvB9GF1oSpCWOVNtox7aRA==" }, "colorette": { "version": "2.0.16", @@ -13979,8 +14912,12 @@ "commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==" }, "component-emitter": { "version": "1.3.0", @@ -14038,8 +14975,7 @@ "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, "connect-history-api-fallback": { "version": "1.6.0", @@ -14175,7 +15111,6 @@ "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, "requires": { "ms": "2.1.2" } @@ -14218,11 +15153,15 @@ "regexp.prototype.flags": "^1.2.0" } }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" + }, "deep-is": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=" }, "deepmerge": { "version": "4.2.2", @@ -14330,6 +15269,14 @@ } } }, + "defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "requires": { + "clone": "^1.0.2" + } + }, "define-properties": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", @@ -14422,6 +15369,29 @@ "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", "dev": true }, + "dependency-tree": { + "version": "10.0.9", + "resolved": "https://registry.npmjs.org/dependency-tree/-/dependency-tree-10.0.9.tgz", + "integrity": "sha512-dwc59FRIsht+HfnTVM0BCjJaEWxdq2YAvEDy4/Hn6CwS3CBWMtFnL3aZGAkQn3XCYxk/YcTDE4jX2Q7bFTwCjA==", + "requires": { + "commander": "^10.0.1", + "filing-cabinet": "^4.1.6", + "precinct": "^11.0.5", + "typescript": "^5.0.4" + }, + "dependencies": { + "commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==" + }, + "typescript": { + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==" + } + } + }, "destroy": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", @@ -14440,6 +15410,118 @@ "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", "dev": true }, + "detective-amd": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/detective-amd/-/detective-amd-5.0.2.tgz", + "integrity": "sha512-XFd/VEQ76HSpym80zxM68ieB77unNuoMwopU2TFT/ErUk5n4KvUTwW4beafAVUugrjV48l4BmmR0rh2MglBaiA==", + "requires": { + "ast-module-types": "^5.0.0", + "escodegen": "^2.0.0", + "get-amd-module-type": "^5.0.1", + "node-source-walk": "^6.0.1" + } + }, + "detective-cjs": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/detective-cjs/-/detective-cjs-5.0.1.tgz", + "integrity": "sha512-6nTvAZtpomyz/2pmEmGX1sXNjaqgMplhQkskq2MLrar0ZAIkHMrDhLXkRiK2mvbu9wSWr0V5/IfiTrZqAQMrmQ==", + "requires": { + "ast-module-types": "^5.0.0", + "node-source-walk": "^6.0.0" + } + }, + "detective-es6": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/detective-es6/-/detective-es6-4.0.1.tgz", + "integrity": "sha512-k3Z5tB4LQ8UVHkuMrFOlvb3GgFWdJ9NqAa2YLUU/jTaWJIm+JJnEh4PsMc+6dfT223Y8ACKOaC0qcj7diIhBKw==", + "requires": { + "node-source-walk": "^6.0.1" + } + }, + "detective-postcss": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/detective-postcss/-/detective-postcss-6.1.3.tgz", + "integrity": "sha512-7BRVvE5pPEvk2ukUWNQ+H2XOq43xENWbH0LcdCE14mwgTBEAMoAx+Fc1rdp76SmyZ4Sp48HlV7VedUnP6GA1Tw==", + "requires": { + "is-url": "^1.2.4", + "postcss": "^8.4.23", + "postcss-values-parser": "^6.0.2" + } + }, + "detective-sass": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/detective-sass/-/detective-sass-5.0.3.tgz", + "integrity": "sha512-YsYT2WuA8YIafp2RVF5CEfGhhyIVdPzlwQgxSjK+TUm3JoHP+Tcorbk3SfG0cNZ7D7+cYWa0ZBcvOaR0O8+LlA==", + "requires": { + "gonzales-pe": "^4.3.0", + "node-source-walk": "^6.0.1" + } + }, + "detective-scss": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/detective-scss/-/detective-scss-4.0.3.tgz", + "integrity": "sha512-VYI6cHcD0fLokwqqPFFtDQhhSnlFWvU614J42eY6G0s8c+MBhi9QAWycLwIOGxlmD8I/XvGSOUV1kIDhJ70ZPg==", + "requires": { + "gonzales-pe": "^4.3.0", + "node-source-walk": "^6.0.1" + } + }, + "detective-stylus": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/detective-stylus/-/detective-stylus-4.0.0.tgz", + "integrity": "sha512-TfPotjhszKLgFBzBhTOxNHDsutIxx9GTWjrL5Wh7Qx/ydxKhwUrlSFeLIn+ZaHPF+h0siVBkAQSuy6CADyTxgQ==" + }, + "detective-typescript": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/detective-typescript/-/detective-typescript-11.2.0.tgz", + "integrity": "sha512-ARFxjzizOhPqs1fYC/2NMC3N4jrQ6HvVflnXBTRqNEqJuXwyKLRr9CrJwkRcV/SnZt1sNXgsF6FPm0x57Tq0rw==", + "requires": { + "@typescript-eslint/typescript-estree": "^5.62.0", + "ast-module-types": "^5.0.0", + "node-source-walk": "^6.0.2", + "typescript": "^5.4.4" + }, + "dependencies": { + "@typescript-eslint/types": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", + "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==" + }, + "@typescript-eslint/typescript-estree": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", + "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", + "requires": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/visitor-keys": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", + "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", + "requires": { + "@typescript-eslint/types": "5.62.0", + "eslint-visitor-keys": "^3.3.0" + } + }, + "eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==" + }, + "typescript": { + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==" + } + } + }, "diff-sequences": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", @@ -14450,7 +15532,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, "requires": { "path-type": "^4.0.0" } @@ -14533,8 +15614,7 @@ "electron-to-chromium": { "version": "1.4.740", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.740.tgz", - "integrity": "sha512-Yvg5i+iyv7Xm18BRdVPVm8lc7kgxM3r6iwqCH2zB7QZy1kZRNmd0Zqm0zcD9XoFREE5/5rwIuIAOT+/mzGcnZg==", - "dev": true + "integrity": "sha512-Yvg5i+iyv7Xm18BRdVPVm8lc7kgxM3r6iwqCH2zB7QZy1kZRNmd0Zqm0zcD9XoFREE5/5rwIuIAOT+/mzGcnZg==" }, "emittery": { "version": "0.8.1", @@ -14567,7 +15647,6 @@ "version": "5.16.0", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.16.0.tgz", "integrity": "sha512-O+QWCviPNSSLAD9Ucn8Awv+poAkqn3T1XY5/N7kR7rQO9yfSGWkYZDwpJ+iKF7B8rxaQKWngSqACpgzeapSyoA==", - "dev": true, "requires": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" @@ -14639,8 +15718,7 @@ "es-module-lexer": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.0.tgz", - "integrity": "sha512-pqrTKmwEIgafsYZAGw9kszYzmagcE/n4dbgwGWLEXg7J4QFJVQRBld8j3Q3GNez79jzxZshq0bcT962QHOghjw==", - "dev": true + "integrity": "sha512-pqrTKmwEIgafsYZAGw9kszYzmagcE/n4dbgwGWLEXg7J4QFJVQRBld8j3Q3GNez79jzxZshq0bcT962QHOghjw==" }, "es-to-primitive": { "version": "1.2.1", @@ -14656,8 +15734,7 @@ "escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" }, "escape-html": { "version": "1.0.3", @@ -14675,7 +15752,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", - "dev": true, "requires": { "esprima": "^4.0.1", "estraverse": "^5.2.0", @@ -14687,14 +15763,12 @@ "estraverse": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==" }, "levn": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dev": true, "requires": { "prelude-ls": "~1.1.2", "type-check": "~0.3.2" @@ -14704,7 +15778,6 @@ "version": "0.8.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dev": true, "requires": { "deep-is": "~0.1.3", "fast-levenshtein": "~2.0.6", @@ -14717,14 +15790,12 @@ "prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" }, "type-check": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "dev": true, "requires": { "prelude-ls": "~1.1.2" } @@ -14943,7 +16014,6 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, "requires": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" @@ -14994,8 +16064,7 @@ "esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" }, "esquery": { "version": "1.4.0", @@ -15018,7 +16087,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, "requires": { "estraverse": "^5.2.0" }, @@ -15026,22 +16094,19 @@ "estraverse": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==" } } }, "estraverse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==" }, "esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" }, "etag": { "version": "1.8.1", @@ -15058,8 +16123,7 @@ "events": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "dev": true + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==" }, "eventsource": { "version": "1.1.0", @@ -15272,14 +16336,12 @@ "fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "fast-glob": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", - "dev": true, "requires": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -15292,7 +16354,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, "requires": { "is-glob": "^4.0.1" } @@ -15302,14 +16363,12 @@ "fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" }, "fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" }, "fastest-levenshtein": { "version": "1.0.12", @@ -15321,7 +16380,6 @@ "version": "1.11.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.1.tgz", "integrity": "sha512-HOnr8Mc60eNYl1gzwp6r5RoUyAn5/glBolUzP/Ez6IFVPMPirxn/9phgL6zhOtaTy7ISwPvQ+wT+hfcRZh/bzw==", - "dev": true, "requires": { "reusify": "^1.0.4" } @@ -15366,11 +16424,51 @@ "dev": true, "optional": true }, + "filing-cabinet": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/filing-cabinet/-/filing-cabinet-4.2.0.tgz", + "integrity": "sha512-YZ21ryzRcyqxpyKggdYSoXx//d3sCJzM3lsYoaeg/FyXdADGJrUl+BW1KIglaVLJN5BBcMtWylkygY8zBp2MrQ==", + "requires": { + "app-module-path": "^2.2.0", + "commander": "^10.0.1", + "enhanced-resolve": "^5.14.1", + "is-relative-path": "^1.0.2", + "module-definition": "^5.0.1", + "module-lookup-amd": "^8.0.5", + "resolve": "^1.22.3", + "resolve-dependency-path": "^3.0.2", + "sass-lookup": "^5.0.1", + "stylus-lookup": "^5.0.1", + "tsconfig-paths": "^4.2.0", + "typescript": "^5.0.4" + }, + "dependencies": { + "commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==" + }, + "tsconfig-paths": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", + "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", + "requires": { + "json5": "^2.2.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "typescript": { + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==" + } + } + }, "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, "requires": { "to-regex-range": "^5.0.1" } @@ -15479,8 +16577,7 @@ "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, "fsevents": { "version": "2.3.2", @@ -15492,8 +16589,7 @@ "function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" }, "functional-red-black-tree": { "version": "1.0.1", @@ -15507,6 +16603,15 @@ "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", "dev": true }, + "get-amd-module-type": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/get-amd-module-type/-/get-amd-module-type-5.0.1.tgz", + "integrity": "sha512-jb65zDeHyDjFR1loOVk0HQGM5WNwoGB8aLWy3LKCieMKol0/ProHkhO2X1JxojuN10vbz1qNn09MJ7tNp7qMzw==", + "requires": { + "ast-module-types": "^5.0.0", + "node-source-walk": "^6.0.1" + } + }, "get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -15524,6 +16629,11 @@ "has-symbols": "^1.0.1" } }, + "get-own-enumerable-property-symbols": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", + "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==" + }, "get-package-type": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", @@ -15546,7 +16656,6 @@ "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -15568,8 +16677,7 @@ "glob-to-regexp": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "dev": true + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" }, "globals": { "version": "13.10.0", @@ -15584,7 +16692,6 @@ "version": "11.1.0", "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, "requires": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", @@ -15597,16 +16704,22 @@ "ignore": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", - "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", - "dev": true + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==" } } }, + "gonzales-pe": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/gonzales-pe/-/gonzales-pe-4.3.0.tgz", + "integrity": "sha512-otgSPpUmdWJ43VXyiNgEYE4luzHCL2pz4wQ0OnDluC6Eg4Ko3Vexy/SrSynglw/eR+OhkzmqFCZa/OFa/RgAOQ==", + "requires": { + "minimist": "^1.2.5" + } + }, "graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" }, "handle-thing": { "version": "2.0.1", @@ -15632,8 +16745,7 @@ "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, "has-symbols": { "version": "1.0.2", @@ -15697,7 +16809,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, "requires": { "function-bind": "^1.1.2" } @@ -16011,6 +17122,19 @@ "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true }, + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + }, "ignore": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", @@ -16101,7 +17225,6 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, "requires": { "once": "^1.3.0", "wrappy": "1" @@ -16110,8 +17233,12 @@ "inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" }, "internal-ip": { "version": "4.3.0", @@ -16228,7 +17355,6 @@ "version": "2.13.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", - "dev": true, "requires": { "hasown": "^2.0.0" } @@ -16287,8 +17413,7 @@ "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" }, "is-fullwidth-code-point": { "version": "3.0.0", @@ -16306,11 +17431,15 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, "requires": { "is-extglob": "^2.1.1" } }, + "is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==" + }, "is-negative-zero": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", @@ -16320,8 +17449,7 @@ "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" }, "is-number-object": { "version": "1.0.5", @@ -16329,6 +17457,11 @@ "integrity": "sha512-RU0lI/n95pMoUKu9v1BZP5MBcZuNSVJkMkAG2dJqC4z2GlkGUNeH68SuHuBKBD/XFe+LHZ+f9BKkLET60Niedw==", "dev": true }, + "is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==" + }, "is-path-cwd": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", @@ -16378,6 +17511,16 @@ "has-symbols": "^1.0.2" } }, + "is-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", + "integrity": "sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==" + }, + "is-relative-path": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-relative-path/-/is-relative-path-1.0.2.tgz", + "integrity": "sha512-i1h+y50g+0hRbBD+dbnInl3JlJ702aar58snAeX+MxBAPvzXGej7sYoPMhlnykabt0ZzCJNBEyzMlekuQZN7fA==" + }, "is-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", @@ -16405,6 +17548,21 @@ "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", "dev": true }, + "is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==" + }, + "is-url": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz", + "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==" + }, + "is-url-superb": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-url-superb/-/is-url-superb-4.0.0.tgz", + "integrity": "sha512-GI+WjezhPPcbM+tqE9LnmsY5qqjwHzTvjJ36wxYX5ujNXefSUJ/T17r5bqDV8yLhcgB59KTPNOc9O9cmHTPWsA==" + }, "is-windows": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", @@ -17039,7 +18197,6 @@ "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", - "dev": true, "requires": { "@types/node": "*", "merge-stream": "^2.0.0", @@ -17050,7 +18207,6 @@ "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, "requires": { "has-flag": "^4.0.0" } @@ -17138,14 +18294,12 @@ "json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" }, "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, "json-stable-stringify-without-jsonify": { "version": "1.0.1", @@ -17156,8 +18310,7 @@ "json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==" }, "killable": { "version": "1.0.1", @@ -17214,8 +18367,7 @@ "loader-runner": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz", - "integrity": "sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw==", - "dev": true + "integrity": "sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw==" }, "locate-path": { "version": "2.0.0", @@ -17257,6 +18409,15 @@ "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", "dev": true }, + "log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "requires": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + } + }, "loglevel": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.8.0.tgz", @@ -17284,11 +18445,37 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, "requires": { "yallist": "^4.0.0" } }, + "madge": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/madge/-/madge-7.0.0.tgz", + "integrity": "sha512-x9eHkBWoCJ2B8yGesWf8LRucarkbH5P3lazqgvmxe4xn5U2Meyfu906iG9mBB1RnY/f4D+gtELWdiz1k6+jAZA==", + "requires": { + "chalk": "^4.1.2", + "commander": "^7.2.0", + "commondir": "^1.0.1", + "debug": "^4.3.4", + "dependency-tree": "^10.0.9", + "ora": "^5.4.1", + "pluralize": "^8.0.0", + "precinct": "^11.0.5", + "pretty-ms": "^7.0.1", + "rc": "^1.2.8", + "stream-to-array": "^2.3.0", + "ts-graphviz": "^1.8.1", + "walkdir": "^0.4.1" + }, + "dependencies": { + "commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==" + } + } + }, "make-dir": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", @@ -17361,14 +18548,12 @@ "merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" }, "merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==" }, "meshoptimizer": { "version": "0.18.1", @@ -17386,7 +18571,6 @@ "version": "4.0.4", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", - "dev": true, "requires": { "braces": "^3.0.1", "picomatch": "^2.2.3" @@ -17401,14 +18585,12 @@ "mime-db": { "version": "1.48.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz", - "integrity": "sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ==", - "dev": true + "integrity": "sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ==" }, "mime-types": { "version": "2.1.31", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.31.tgz", "integrity": "sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==", - "dev": true, "requires": { "mime-db": "1.48.0" } @@ -17416,8 +18598,7 @@ "mimic-fn": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" }, "minimalistic-assert": { "version": "1.0.1", @@ -17429,7 +18610,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, "requires": { "brace-expansion": "^1.1.7" } @@ -17437,8 +18617,7 @@ "minimist": { "version": "1.2.6", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "dev": true + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" }, "mixin-deep": { "version": "1.3.2", @@ -17470,11 +18649,37 @@ "minimist": "^1.2.5" } }, + "module-definition": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/module-definition/-/module-definition-5.0.1.tgz", + "integrity": "sha512-kvw3B4G19IXk+BOXnYq/D/VeO9qfHaapMeuS7w7sNUqmGaA6hywdFHMi+VWeR9wUScXM7XjoryTffCZ5B0/8IA==", + "requires": { + "ast-module-types": "^5.0.0", + "node-source-walk": "^6.0.1" + } + }, + "module-lookup-amd": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/module-lookup-amd/-/module-lookup-amd-8.0.5.tgz", + "integrity": "sha512-vc3rYLjDo5Frjox8NZpiyLXsNWJ5BWshztc/5KSOMzpg9k5cHH652YsJ7VKKmtM4SvaxuE9RkrYGhiSjH3Ehow==", + "requires": { + "commander": "^10.0.1", + "glob": "^7.2.3", + "requirejs": "^2.3.6", + "requirejs-config-file": "^4.0.0" + }, + "dependencies": { + "commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==" + } + } + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "multicast-dns": { "version": "6.2.3", @@ -17499,6 +18704,11 @@ "dev": true, "optional": true }, + "nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==" + }, "nanomatch": { "version": "1.2.13", "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", @@ -17593,8 +18803,7 @@ "neo-async": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" }, "nice-try": { "version": "1.0.5", @@ -17635,8 +18844,15 @@ "node-releases": { "version": "2.0.14", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", - "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", - "dev": true + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==" + }, + "node-source-walk": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/node-source-walk/-/node-source-walk-6.0.2.tgz", + "integrity": "sha512-jn9vOIK/nfqoFCcpK89/VCVaLg1IHE6UVfDOzvqmANaJ/rWCTEdH8RZ1V278nv2jr36BJdyQXIAavBLXpzdlag==", + "requires": { + "@babel/parser": "^7.21.8" + } }, "normalize-package-data": { "version": "2.5.0", @@ -17795,7 +19011,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, "requires": { "wrappy": "1" } @@ -17804,7 +19019,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, "requires": { "mimic-fn": "^2.1.0" } @@ -17832,6 +19046,22 @@ "word-wrap": "^1.2.3" } }, + "ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "requires": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + } + }, "original": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz", @@ -17940,6 +19170,11 @@ "json-parse-better-errors": "^1.0.1" } }, + "parse-ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-2.1.0.tgz", + "integrity": "sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA==" + }, "parse5": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", @@ -17991,8 +19226,7 @@ "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, "path-is-inside": { "version": "1.0.2", @@ -18009,8 +19243,7 @@ "path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, "path-to-regexp": { "version": "0.1.7", @@ -18021,20 +19254,17 @@ "path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" }, "picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" }, "picomatch": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", - "dev": true + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==" }, "pify": { "version": "3.0.0", @@ -18081,6 +19311,11 @@ "find-up": "^2.1.0" } }, + "pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==" + }, "portfinder": { "version": "1.0.28", "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", @@ -18109,6 +19344,52 @@ "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", "dev": true }, + "postcss": { + "version": "8.4.38", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", + "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", + "requires": { + "nanoid": "^3.3.7", + "picocolors": "^1.0.0", + "source-map-js": "^1.2.0" + } + }, + "postcss-values-parser": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-values-parser/-/postcss-values-parser-6.0.2.tgz", + "integrity": "sha512-YLJpK0N1brcNJrs9WatuJFtHaV9q5aAOj+S4DI5S7jgHlRfm0PIbDCAFRYMQD5SHq7Fy6xsDhyutgS0QOAs0qw==", + "requires": { + "color-name": "^1.1.4", + "is-url-superb": "^4.0.0", + "quote-unquote": "^1.0.0" + } + }, + "precinct": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/precinct/-/precinct-11.0.5.tgz", + "integrity": "sha512-oHSWLC8cL/0znFhvln26D14KfCQFFn4KOLSw6hmLhd+LQ2SKt9Ljm89but76Pc7flM9Ty1TnXyrA2u16MfRV3w==", + "requires": { + "@dependents/detective-less": "^4.1.0", + "commander": "^10.0.1", + "detective-amd": "^5.0.2", + "detective-cjs": "^5.0.1", + "detective-es6": "^4.0.1", + "detective-postcss": "^6.1.3", + "detective-sass": "^5.0.3", + "detective-scss": "^4.0.3", + "detective-stylus": "^4.0.0", + "detective-typescript": "^11.1.0", + "module-definition": "^5.0.1", + "node-source-walk": "^6.0.2" + }, + "dependencies": { + "commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==" + } + } + }, "prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -18140,6 +19421,14 @@ } } }, + "pretty-ms": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-7.0.1.tgz", + "integrity": "sha512-973driJZvxiGOQ5ONsFhOF/DtzPMOMtgC11kCpUrPGMTgqp2q/1gwzCquocrN33is0VZ5GFHXZYMM9l6h67v2Q==", + "requires": { + "parse-ms": "^2.1.0" + } + }, "process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -18197,8 +19486,7 @@ "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" }, "qs": { "version": "6.7.0", @@ -18221,14 +19509,17 @@ "queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" + }, + "quote-unquote": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/quote-unquote/-/quote-unquote-1.0.0.tgz", + "integrity": "sha512-twwRO/ilhlG/FIgYeKGFqyHhoEhqgnKVkcmqMKi2r524gz3ZbDTcyFt38E9xjJI2vT+KbRNHVbnJ/e0I25Azwg==" }, "randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, "requires": { "safe-buffer": "^5.1.0" } @@ -18268,6 +19559,24 @@ } } }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==" + } + } + }, "react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", @@ -18581,6 +19890,20 @@ "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", "dev": true }, + "requirejs": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/requirejs/-/requirejs-2.3.6.tgz", + "integrity": "sha512-ipEzlWQe6RK3jkzikgCupiTbTvm4S0/CAU5GlgptkN5SO6F3u0UD0K18wy6ErDqiCyP4J4YYe1HuAShvsxePLg==" + }, + "requirejs-config-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/requirejs-config-file/-/requirejs-config-file-4.0.0.tgz", + "integrity": "sha512-jnIre8cbWOyvr8a5F2KuqBnY+SDA4NXr/hzEZJG79Mxm2WiFQz2dzhC8ibtPJS7zkmBEl1mxSwp5HhC1W4qpxw==", + "requires": { + "esprima": "^4.0.0", + "stringify-object": "^3.2.1" + } + }, "requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", @@ -18591,7 +19914,6 @@ "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", - "dev": true, "requires": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", @@ -18615,6 +19937,11 @@ } } }, + "resolve-dependency-path": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/resolve-dependency-path/-/resolve-dependency-path-3.0.2.tgz", + "integrity": "sha512-Tz7zfjhLfsvR39ADOSk9us4421J/1ztVBo4rWUkF38hgHK5m0OCZ3NxFVpqHRkjctnwVa15igEUHFJp8MCS7vA==" + }, "resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -18633,6 +19960,15 @@ "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==", "dev": true }, + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, "ret": { "version": "0.1.15", "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", @@ -18648,8 +19984,7 @@ "reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==" }, "rimraf": { "version": "3.0.2", @@ -18664,7 +19999,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, "requires": { "queue-microtask": "^1.2.2" } @@ -18672,8 +20006,7 @@ "safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" }, "safe-regex": { "version": "1.1.0", @@ -18687,8 +20020,22 @@ "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "sass-lookup": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/sass-lookup/-/sass-lookup-5.0.1.tgz", + "integrity": "sha512-t0X5PaizPc2H4+rCwszAqHZRtr4bugo4pgiCvrBFvIX0XFxnr29g77LJcpyj9A0DcKf7gXMLcgvRjsonYI6x4g==", + "requires": { + "commander": "^10.0.1" + }, + "dependencies": { + "commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==" + } + } }, "saxes": { "version": "5.0.1", @@ -18703,7 +20050,6 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", - "dev": true, "requires": { "@types/json-schema": "^7.0.8", "ajv": "^6.12.5", @@ -18729,7 +20075,6 @@ "version": "7.6.0", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", - "dev": true, "requires": { "lru-cache": "^6.0.0" } @@ -18784,7 +20129,6 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", - "dev": true, "requires": { "randombytes": "^2.1.0" } @@ -18908,8 +20252,7 @@ "signal-exit": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", - "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", - "dev": true + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" }, "sisteransi": { "version": "1.0.5", @@ -18920,8 +20263,7 @@ "slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==" }, "slice-ansi": { "version": "4.0.0", @@ -19082,8 +20424,22 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "source-map-js": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==" + }, + "source-map-loader": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-3.0.2.tgz", + "integrity": "sha512-BokxPoLjyl3iOrgkWaakaxqnelAJSS+0V+De0kKIq6lyWrXuiPgYTGp6z3iHmqljKAaLXwZa+ctD8GccRJeVvg==", + "requires": { + "abab": "^2.0.5", + "iconv-lite": "^0.6.3", + "source-map-js": "^1.0.1" + } }, "source-map-resolve": { "version": "0.5.3", @@ -19102,7 +20458,6 @@ "version": "0.5.21", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, "requires": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -19255,11 +20610,18 @@ "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", "dev": true }, + "stream-to-array": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/stream-to-array/-/stream-to-array-2.3.0.tgz", + "integrity": "sha512-UsZtOYEn4tWU2RGLOXr/o/xjRBftZRlG3dEWoaHr8j4GuypJ3isitGbVyjQKAuMu+xbiop8q224TjiZWc4XTZA==", + "requires": { + "any-promise": "^1.1.0" + } + }, "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, "requires": { "safe-buffer": "~5.1.0" }, @@ -19267,8 +20629,7 @@ "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" } } }, @@ -19313,11 +20674,20 @@ "define-properties": "^1.1.3" } }, + "stringify-object": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", + "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", + "requires": { + "get-own-enumerable-property-symbols": "^3.0.0", + "is-obj": "^1.0.1", + "is-regexp": "^1.0.0" + } + }, "strip-ansi": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, "requires": { "ansi-regex": "^5.0.0" } @@ -19325,8 +20695,7 @@ "strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=" }, "strip-eof": { "version": "1.0.0", @@ -19346,11 +20715,25 @@ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true }, + "stylus-lookup": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/stylus-lookup/-/stylus-lookup-5.0.1.tgz", + "integrity": "sha512-tLtJEd5AGvnVy4f9UHQMw4bkJJtaAcmo54N+ovQBjDY3DuWyK9Eltxzr5+KG0q4ew6v2EHyuWWNnHeiw/Eo7rQ==", + "requires": { + "commander": "^10.0.1" + }, + "dependencies": { + "commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==" + } + } + }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, "requires": { "has-flag": "^4.0.0" } @@ -19368,8 +20751,7 @@ "supports-preserve-symlinks-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" }, "symbol-tree": { "version": "3.2.4", @@ -19414,8 +20796,7 @@ "tapable": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.0.tgz", - "integrity": "sha512-FBk4IesMV1rBxX2tfiK8RAmogtWn53puLOQlvO8XuwlgxcYbP4mVPS9Ph4aeamSyyVjOl24aYWAuc8U5kCVwMw==", - "dev": true + "integrity": "sha512-FBk4IesMV1rBxX2tfiK8RAmogtWn53puLOQlvO8XuwlgxcYbP4mVPS9Ph4aeamSyyVjOl24aYWAuc8U5kCVwMw==" }, "terminal-link": { "version": "2.1.1", @@ -19431,7 +20812,6 @@ "version": "5.30.3", "resolved": "https://registry.npmjs.org/terser/-/terser-5.30.3.tgz", "integrity": "sha512-STdUgOUx8rLbMGO9IOwHLpCqolkDITFFQSMYYwKE1N2lY6MVSaeoi10z/EhWxRc6ybqoVmKSkhKYH/XUpl7vSA==", - "dev": true, "requires": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.8.2", @@ -19442,8 +20822,7 @@ "acorn": { "version": "8.11.3", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", - "dev": true + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==" } } }, @@ -19451,7 +20830,6 @@ "version": "5.3.10", "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", - "dev": true, "requires": { "@jridgewell/trace-mapping": "^0.3.20", "jest-worker": "^27.4.5", @@ -19602,7 +20980,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, "requires": { "is-number": "^7.0.0" } @@ -19633,6 +21010,11 @@ "punycode": "^2.1.1" } }, + "ts-graphviz": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/ts-graphviz/-/ts-graphviz-1.8.2.tgz", + "integrity": "sha512-5YhbFoHmjxa7pgQLkB07MtGnGJ/yhvjmc9uhsnDBEICME6gkPf83SBwLDQqGDoCa3XzUMWLk1AU2Wn1u1naDtA==" + }, "ts-jest": { "version": "27.1.4", "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-27.1.4.tgz", @@ -19692,14 +21074,12 @@ "tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, "tsutils": { "version": "3.21.0", "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, "requires": { "tslib": "^1.8.1" } @@ -19747,8 +21127,7 @@ "typescript": { "version": "4.9.5", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", - "dev": true + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==" }, "unbox-primitive": { "version": "1.0.1", @@ -19836,7 +21215,6 @@ "version": "1.0.13", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", - "dev": true, "requires": { "escalade": "^3.1.1", "picocolors": "^1.0.0" @@ -19846,7 +21224,6 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, "requires": { "punycode": "^2.1.0" } @@ -19894,8 +21271,7 @@ "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, "utils-merge": { "version": "1.0.1", @@ -19968,6 +21344,11 @@ "xml-name-validator": "^3.0.0" } }, + "walkdir": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/walkdir/-/walkdir-0.4.1.tgz", + "integrity": "sha512-3eBwRyEln6E1MSzcxcVpQIhRG8Q1jLvEqRmCZqS3dsfXEDR/AhOF4d+jHg1qvDCpYaVRZjENPQyrVxAkQqxPgQ==" + }, "walker": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", @@ -19981,7 +21362,6 @@ "version": "2.4.1", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.1.tgz", "integrity": "sha512-8wrBCMtVhqcXP2Sup1ctSkga6uc2Bx0IIvKyT7yTFier5AXHooSI+QyQQAtTb7+E0IUCCKyTFmXqdqgum2XWGg==", - "dev": true, "requires": { "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.1.2" @@ -19996,6 +21376,14 @@ "minimalistic-assert": "^1.0.0" } }, + "wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "requires": { + "defaults": "^1.0.3" + } + }, "webidl-conversions": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", @@ -20006,7 +21394,6 @@ "version": "5.91.0", "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.91.0.tgz", "integrity": "sha512-rzVwlLeBWHJbmgTC/8TvAcu5vpJNII+MelQpylD4jNERPwpBJOE2lEcko1zJX3QJeLjTTAnQxn/OJ8bjDzVQaw==", - "dev": true, "requires": { "@types/eslint-scope": "^3.7.3", "@types/estree": "^1.0.5", @@ -20037,14 +21424,12 @@ "acorn": { "version": "8.11.3", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", - "dev": true + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==" }, "acorn-import-assertions": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", - "dev": true, "requires": {} } } @@ -20290,8 +21675,7 @@ "webpack-sources": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", - "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", - "dev": true + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==" }, "websocket-driver": { "version": "0.7.4", @@ -20384,8 +21768,7 @@ "word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==" }, "wrap-ansi": { "version": "5.1.0", @@ -20465,8 +21848,7 @@ "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "write-file-atomic": { "version": "3.0.3", @@ -20510,8 +21892,7 @@ "yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "yargs": { "version": "13.3.2", diff --git a/package.json b/package.json index 71f01ab1..68dbfbfd 100644 --- a/package.json +++ b/package.json @@ -42,8 +42,9 @@ "webpack": "^5.91.0", "webpack-cli": "^4.9.2", "webpack-dev-server": "^3.11.2" - }, + }, "dependencies": { + "@supalosa/oldschool-trainer-sdk": "0.0.9", "three": "^0.163.0" } } diff --git a/src/content/colosseum/js/entities/SolarFlareOrb.ts b/src/content/colosseum/js/entities/SolarFlareOrb.ts index c5c6b5ec..458952f4 100644 --- a/src/content/colosseum/js/entities/SolarFlareOrb.ts +++ b/src/content/colosseum/js/entities/SolarFlareOrb.ts @@ -2,7 +2,7 @@ import _ from "lodash"; -import { Entity, Region, CollisionType, LineOfSightMask, Viewport, Random, Projectile, Pathing, Location, Trainer } from "@supalosa/oldschool-trainer-sdk"; +import { Entity, Region, CollisionType, LineOfSightMask, Random, Projectile, Pathing, Location, Trainer } from "@supalosa/oldschool-trainer-sdk"; import { SolarFlareModel } from "../rendering/SolarFlareModel"; diff --git a/src/sdk/controlpanels/PrayerControls.ts b/src/sdk/controlpanels/PrayerControls.ts deleted file mode 100644 index 5565e944..00000000 --- a/src/sdk/controlpanels/PrayerControls.ts +++ /dev/null @@ -1,101 +0,0 @@ -import PrayerPanel from "../../assets/images/panels/prayer.png"; -import PrayerTab from "../../assets/images/tabs/prayer.png"; -import { BaseControls } from "./BaseControls"; -import { Settings } from "../Settings"; -import { ControlPanelController } from "../ControlPanelController"; -import { Viewport } from "../Viewport"; -import { Trainer } from "@supalosa/oldschool-trainer-sdk"; - -export class PrayerControls extends BaseControls { - hasQuickPrayersActivated = false; - - get panelImageReference() { - return PrayerPanel; - } - - get tabImageReference() { - return PrayerTab; - } - - get keyBinding() { - return Settings.prayer_key; - } - - deactivateAllPrayers() { - this.hasQuickPrayersActivated = false; - Trainer.player.prayerController.activePrayers().forEach((prayer) => prayer.deactivate()); - } - - activateQuickPrayers() { - this.hasQuickPrayersActivated = true; - - Trainer.player.prayerController.prayers.forEach((prayer) => { - prayer.deactivate(); - if (prayer.name === "Protect from Magic") { - prayer.activate(Trainer.player); - } - if (prayer.name === "Rigour") { - prayer.activate(Trainer.player); - } - }); - } - - panelClickDown(x: number, y: number) { - const scale = Settings.controlPanelScale; - - x = x / scale; - y = y / scale; - - const gridX = x - 14; - const gridY = y - 22; - - const clickedPrayer = - Trainer.player.prayerController.prayers[Math.floor(gridY / 35) * 5 + Math.floor(gridX / 35)]; - if (clickedPrayer && Trainer.player.currentStats.prayer > 0) { - clickedPrayer.toggle(Trainer.player); - - if (this.hasQuickPrayersActivated && Trainer.player.prayerController.activePrayers().length === 0) { - ControlPanelController.controls.PRAYER.hasQuickPrayersActivated = false; - } - } - } - - get isAvailable(): boolean { - return true; - } - - draw(context, ctrl: ControlPanelController, x: number, y: number) { - super.draw(context, ctrl, x, y); - const scale = Settings.controlPanelScale; - - Trainer.player.prayerController.prayers.forEach((prayer, index) => { - const x2 = index % 5; - const y2 = Math.floor(index / 5); - - if (prayer.isActive || prayer.isLit) { - Viewport.viewport.context.beginPath(); - Viewport.viewport.context.fillStyle = "#D1BB7773"; - Viewport.viewport.context.arc( - x + 10 * scale + (x2 + 0.5) * 36.8 * scale, - y + (16 + (y2 + 0.5) * 37) * scale, - 18 * scale, - 0, - 2 * Math.PI, - ); - Viewport.viewport.context.fill(); - } - if (Trainer.player.stats.prayer < prayer.levelRequirement()) { - Viewport.viewport.context.beginPath(); - Viewport.viewport.context.fillStyle = "#00000073"; - Viewport.viewport.context.arc( - x + 10 * scale + (x2 + 0.5) * 36.8 * scale, - y + (16 + (y2 + 0.5) * 37) * scale, - 18 * scale, - 0, - 2 * Math.PI, - ); - Viewport.viewport.context.fill(); - } - }); - } -} From c74ee23176052cbd3d80c60ab50768e676bd876a Mon Sep 17 00:00:00 2001 From: Supalosa Date: Sat, 11 May 2024 01:17:07 +1000 Subject: [PATCH 093/141] copy assets out of the npm package --- webpack.config.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/webpack.config.js b/webpack.config.js index ccc0dc03..5d6b79a8 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -42,6 +42,9 @@ const config = { to: "webappicon.png", context: `src/`, }, + { from: '*.png', to: "", context: "node_modules/@supalosa/oldschool-trainer-sdk/_bundles/", noErrorOnMissing: true }, + { from: '*.gif', to: "", context: "node_modules/@supalosa/oldschool-trainer-sdk/_bundles/", noErrorOnMissing: true }, + { from: '*.ogg', to: "", context: "node_modules/@supalosa/oldschool-trainer-sdk/_bundles/", noErrorOnMissing: true }, ], }), new webpack.EnvironmentPlugin(["COMMIT_REF", "BUILD_DATE", "DEPLOY_URL"]), From 5c9e41c052bd0ee700c0bbbeeb428ea74de3a1fc Mon Sep 17 00:00:00 2001 From: Supalosa Date: Sat, 11 May 2024 18:08:14 +1000 Subject: [PATCH 094/141] wtf is going on --- jest.config.js | 3 +- package-lock.json | 14 +++--- package.json | 2 +- src/content/colosseum/tests/Sol32.test.ts | 2 + src/content/colosseum/tests/SolAttack.test.ts | 3 ++ .../colosseum/tests/SolMovement.test.ts | 2 + src/index.html | 2 +- src/index.ts | 1 - test/setupFiles.ts | 46 ++++++++++++++++--- webpack.config.js | 1 + 10 files changed, 58 insertions(+), 18 deletions(-) diff --git a/jest.config.js b/jest.config.js index e695c6db..9fffe2b5 100644 --- a/jest.config.js +++ b/jest.config.js @@ -14,6 +14,7 @@ module.exports = { "\\.(jpg|ico|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|ogg|glb|html)$": "/test/__mocks__/assetMock.js", "\\.(css|less)$": "/test/__mocks__/cssMock.js", - three: require.resolve("three") + three: require.resolve("three"), + //"@supalosa/oldschool-trainer-sdk": require.resolve("@supalosa/oldschool-trainer-sdk"), }, }; diff --git a/package-lock.json b/package-lock.json index 6f993b51..d586de55 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "0.0.1", "license": "ISC", "dependencies": { - "@supalosa/oldschool-trainer-sdk": "0.0.9", + "@supalosa/oldschool-trainer-sdk": "0.0.12", "three": "^0.163.0" }, "devDependencies": { @@ -1157,9 +1157,9 @@ } }, "node_modules/@supalosa/oldschool-trainer-sdk": { - "version": "0.0.9", - "resolved": "https://registry.npmjs.org/@supalosa/oldschool-trainer-sdk/-/oldschool-trainer-sdk-0.0.9.tgz", - "integrity": "sha512-HUBSysNtoZdEUdZtF4U2AA++86dd9Enp6E+BKWAtK+Qy7bz/irTBA9lQWcipRc9sblOE6M29Jg7yK2YBnyWg3w==", + "version": "0.0.12", + "resolved": "https://registry.npmjs.org/@supalosa/oldschool-trainer-sdk/-/oldschool-trainer-sdk-0.0.12.tgz", + "integrity": "sha512-VBhSfKp1dEwMMi0o2t7Hs03dTF5v8zoyzMgvie3blRzF4oZTzs1f70glbLtKKJ/3bV7sGQp2lYR/f/4lsT8mig==", "dependencies": { "@types/new-relic-browser": "^0.1118.2", "@types/offscreencanvas": "^2019.6.4", @@ -13341,9 +13341,9 @@ } }, "@supalosa/oldschool-trainer-sdk": { - "version": "0.0.9", - "resolved": "https://registry.npmjs.org/@supalosa/oldschool-trainer-sdk/-/oldschool-trainer-sdk-0.0.9.tgz", - "integrity": "sha512-HUBSysNtoZdEUdZtF4U2AA++86dd9Enp6E+BKWAtK+Qy7bz/irTBA9lQWcipRc9sblOE6M29Jg7yK2YBnyWg3w==", + "version": "0.0.12", + "resolved": "https://registry.npmjs.org/@supalosa/oldschool-trainer-sdk/-/oldschool-trainer-sdk-0.0.12.tgz", + "integrity": "sha512-VBhSfKp1dEwMMi0o2t7Hs03dTF5v8zoyzMgvie3blRzF4oZTzs1f70glbLtKKJ/3bV7sGQp2lYR/f/4lsT8mig==", "requires": { "@types/new-relic-browser": "^0.1118.2", "@types/offscreencanvas": "^2019.6.4", diff --git a/package.json b/package.json index 68dbfbfd..52185bf6 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ "webpack-dev-server": "^3.11.2" }, "dependencies": { - "@supalosa/oldschool-trainer-sdk": "0.0.9", + "@supalosa/oldschool-trainer-sdk": "0.0.12", "three": "^0.163.0" } } diff --git a/src/content/colosseum/tests/Sol32.test.ts b/src/content/colosseum/tests/Sol32.test.ts index 37984f22..04643507 100644 --- a/src/content/colosseum/tests/Sol32.test.ts +++ b/src/content/colosseum/tests/Sol32.test.ts @@ -1,3 +1,5 @@ +import "../../../../test/setupFiles"; + import { BladeOfSaeldor, Player, ScytheOfVitur, TestRegion, Viewport, World } from "@supalosa/oldschool-trainer-sdk"; import { Attacks, SolHeredit } from "../js/mobs/SolHeredit"; diff --git a/src/content/colosseum/tests/SolAttack.test.ts b/src/content/colosseum/tests/SolAttack.test.ts index 4893411f..5656a845 100644 --- a/src/content/colosseum/tests/SolAttack.test.ts +++ b/src/content/colosseum/tests/SolAttack.test.ts @@ -1,6 +1,9 @@ +import "../../../../test/setupFiles"; + import { DelayedAction, EquipmentControls, Player, Settings, TestRegion, Viewport, World } from "@supalosa/oldschool-trainer-sdk"; import { Attacks, SolHeredit } from "../js/mobs/SolHeredit"; + // sol heredit movement tests describe("sol heredit attacks", () => { let region: TestRegion; diff --git a/src/content/colosseum/tests/SolMovement.test.ts b/src/content/colosseum/tests/SolMovement.test.ts index 74952770..ec6e5f03 100644 --- a/src/content/colosseum/tests/SolMovement.test.ts +++ b/src/content/colosseum/tests/SolMovement.test.ts @@ -1,3 +1,5 @@ +import "../../../../test/setupFiles"; + import { Player, World, Viewport, TestRegion } from "@supalosa/oldschool-trainer-sdk"; import { SolHeredit } from "../js/mobs/SolHeredit"; diff --git a/src/index.html b/src/index.html index a62ecbf6..a23a2092 100644 --- a/src/index.html +++ b/src/index.html @@ -10,7 +10,7 @@ - Inferno Trainer + Sol Heredit Trainer - - - - -
All assets are property of Jagex.
- Configure key bindings in the settings tab. + + +
+ More settings: +
+ + +
{ + Trainer.reset(); +}); + +document.getElementById("settings").addEventListener("click", () => { + ControlPanelController.controller.setActiveControl('SETTINGS'); +}); + +const tileMarkerColor = document.getElementById("tileMarkerColor") as HTMLInputElement; +tileMarkerColor.addEventListener("input", () => { + Settings.tileMarkerColor = tileMarkerColor.value; + TileMarker.onSetColor(Settings.tileMarkerColor); + Settings.persistToStorage(); +}, false); +tileMarkerColor.value = Settings.tileMarkerColor; + const { player } = selectedRegion.initialiseRegion(); Viewport.setupViewport(selectedRegion); @@ -35,15 +51,8 @@ ImageLoader.onAllImagesLoaded(() => { MapController.controller.updateOrbsMask(player.currentStats, player.stats); }); -if (Settings.tile_markers) { - Settings.tile_markers - .map((location: Location) => { - return new TileMarker(selectedRegion, location, "#FF0000"); - }) - .forEach((tileMarker: TileMarker) => { - selectedRegion.addEntity(tileMarker); - }); -} + +TileMarker.loadAll(selectedRegion); player.perceivedLocation = player.location; player.destinationLocation = player.location; @@ -127,6 +136,7 @@ function checkStart() { /// ///////////////////////////////////////////////////////// + // UI disclaimer const topHeaderContainer = document.getElementById("disclaimer_panel"); topHeaderContainer.innerHTML = From bfdf82f26581d2aa1f13235e54f4d360422d5857 Mon Sep 17 00:00:00 2001 From: Supalosa Date: Mon, 13 May 2024 22:25:44 +1000 Subject: [PATCH 109/141] empty From 5ec67276a3f4acb289f3d0fdb66da463cf053c87 Mon Sep 17 00:00:00 2001 From: Supalosa Date: Mon, 13 May 2024 22:39:01 +1000 Subject: [PATCH 110/141] better floor image --- src/content/inferno/assets/images/map.png | Bin 1553 -> 1601 bytes src/content/inferno/js/VerzikRegion.ts | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/content/inferno/assets/images/map.png b/src/content/inferno/assets/images/map.png index bd1f1220411c92264e0be7aa58b9a6812d1a98b6..8733366354efe5d4fecb5944af4464ba9e8e4601 100644 GIT binary patch literal 1601 zcmeAS@N?(olHy`uVBq!ia0y~yV0;h6i5zS|kw{~uR3ODz9OUlAu$8>eZF?ybKDD4g47toc1s(JbQk#CieQyg#G7^e~wAM zGw*w$ZR|5~*Z=<>KK?p``&;tuZ9DG(mAM14+bA9lgV8iFng&MG08P?BT4nuNUIvyO jmCO!370eE&B;*UCq_%uKyH*!i>@#?}`njxgN@xNA+;-GN literal 1553 zcmeAS@N?(olHy`uVBq!ia0y~yV0;h6i5zS|kw{~uR3ODz9OUlAuH83!+F7tG845^5Fd(~0!fC0~e4Qm|Q)c$C$ zoj>uz+%JYK_P^hmGdLXk$<5$0!<^yBC>{-i(KIlc21e5WUDLplGcoB)Sklj=O#c8Z P#u+?a{an^LB{Ts53~yC0 diff --git a/src/content/inferno/js/VerzikRegion.ts b/src/content/inferno/js/VerzikRegion.ts index 4bcbd9bb..bc871daf 100644 --- a/src/content/inferno/js/VerzikRegion.ts +++ b/src/content/inferno/js/VerzikRegion.ts @@ -39,12 +39,12 @@ export class VerzikRegion extends Region { // create player const player = new Player(this, { x: parseInt(BrowserUtils.getQueryVar("x")) || 25, - y: parseInt(BrowserUtils.getQueryVar("y")) || 30, + y: parseInt(BrowserUtils.getQueryVar("y")) || 26, }); this.addPlayer(player); - this.addMob(new VerzikVitur(this, { x: 25, y: 25 }, { aggro: player })); + this.addMob(new VerzikVitur(this, { x: 22, y: 25 }, { aggro: player })); const loadout = new VerzikLoadout(); loadout.setStats(player); // flip this around one day From 83e019c2ef0edfd91535475ac9852365923f424f Mon Sep 17 00:00:00 2001 From: Supalosa Date: Mon, 13 May 2024 22:40:52 +1000 Subject: [PATCH 111/141] page title --- src/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.html b/src/index.html index 24a4cbef..acbc16de 100644 --- a/src/index.html +++ b/src/index.html @@ -10,7 +10,7 @@ - OSRS SDK Trainer + Verzik P3 Tanking Trainer