diff --git a/src/battle-animations-moves.ts b/src/battle-animations-moves.ts index ec39628e9..81c8a0681 100644 --- a/src/battle-animations-moves.ts +++ b/src/battle-animations-moves.ts @@ -9,7 +9,9 @@ * @license CC0-1.0 */ -const BattleMoveAnims: AnimTable = { +import {AnimTable, BattleOtherAnims} from './battle-animations'; + +export const BattleMoveAnims: AnimTable = { taunt: { anim(scene, [attacker, defender]) { BattleOtherAnims.dance.anim(scene, [attacker, defender]); diff --git a/src/battle-animations.ts b/src/battle-animations.ts index 396eb1934..b86378367 100644 --- a/src/battle-animations.ts +++ b/src/battle-animations.ts @@ -11,6 +11,12 @@ * @license MIT */ +import type {Battle, Pokemon, Side, WeatherState} from './battle'; +import type {BattleSceneStub} from './battle-scene-stub'; +import {BattleMoveAnims} from './battle-animations-moves'; +import {BattleLog} from './battle-log'; +import {BattleBGM, BattleSound} from './battle-sound'; + /* Most of this file is: CC0 (public domain) @@ -30,7 +36,7 @@ This license DOES NOT extend to any other files in this repository. */ -class BattleScene { +export class BattleScene implements BattleSceneStub { battle: Battle; animating = true; acceleration = 1; @@ -234,7 +240,7 @@ class BattleScene { } else { this.$frame.append('


'); this.$frame.find('div.playbutton button[name=play-muted]').click(() => { - this.battle.setMute(true); + this.setMute(true); this.battle.play(); }); } @@ -244,6 +250,9 @@ class BattleScene { this.$frame.find('div.playbutton').remove(); this.updateBgm(); } + setMute(muted: boolean) { + BattleSound.setMute(muted); + } wait(time: number) { if (!this.animating) return; this.timeOffset += time; @@ -589,7 +598,7 @@ class BattleScene { } else { let statustext = ''; if (pokemon.hp !== pokemon.maxhp) { - statustext += Pokemon.getHPText(pokemon); + statustext += pokemon.getHPText(); } if (pokemon.status) { if (statustext) statustext += '|'; @@ -1643,7 +1652,7 @@ class BattleScene { } } -interface ScenePos { +export interface ScenePos { /** - left, + right */ x?: number; /** - down, + up */ @@ -1669,7 +1678,7 @@ interface InitScenePos { display?: string; } -class Sprite { +export class Sprite { scene: BattleScene; $el: JQuery = null!; sp: SpriteData; @@ -1732,7 +1741,7 @@ class Sprite { } } -class PokemonSprite extends Sprite { +export class PokemonSprite extends Sprite { // HTML strings are constructed from this table and stored back in it to cache them protected static statusTable: {[id: string]: [string, 'good' | 'bad' | 'neutral'] | null | string} = { formechange: null, @@ -2795,7 +2804,7 @@ interface AnimData { prepareAnim?(scene: BattleScene, args: PokemonSprite[]): void; residualAnim?(scene: BattleScene, args: PokemonSprite[]): void; } -type AnimTable = {[k: string]: AnimData}; +export type AnimTable = {[k: string]: AnimData}; const BattleEffects: {[k: string]: SpriteData} = { wisp: { @@ -3112,7 +3121,7 @@ const BattleBackdrops = [ 'bg-skypillar.jpg', ]; -const BattleOtherAnims: AnimTable = { +export const BattleOtherAnims: AnimTable = { hitmark: { anim(scene, [attacker]) { scene.showEffect('hitmark', { @@ -5698,7 +5707,7 @@ const BattleOtherAnims: AnimTable = { }, }, }; -const BattleStatusAnims: AnimTable = { +export const BattleStatusAnims: AnimTable = { brn: { anim(scene, [attacker]) { scene.showEffect('fireball', { diff --git a/src/battle-log.ts b/src/battle-log.ts index ece0bad60..a45b6c9c1 100644 --- a/src/battle-log.ts +++ b/src/battle-log.ts @@ -13,7 +13,17 @@ * @license MIT */ -class BattleLog { +import type {BattleScene} from './battle-animations'; + +// Caja +declare const html4: any; +declare const html: any; + +// defined in battle-log-misc +declare function MD5(input: string): string; +declare function formatText(input: string, isTrusted?: boolean): string; + +export class BattleLog { elem: HTMLDivElement; innerElem: HTMLDivElement; scene: BattleScene | null = null; @@ -358,7 +368,7 @@ class BattleLog { addSpacer() { this.addDiv('spacer battle-history', '
'); } - changeUhtml(id: string, html: string, forceAdd?: boolean) { + changeUhtml(id: string, htmlSrc: string, forceAdd?: boolean) { id = toID(id); const classContains = ' uhtml-' + id + ' '; let elements = [] as HTMLDivElement[]; @@ -374,9 +384,9 @@ class BattleLog { } } } - if (html && elements.length && !forceAdd) { + if (htmlSrc && elements.length && !forceAdd) { for (const element of elements) { - element.innerHTML = BattleLog.sanitizeHTML(html); + element.innerHTML = BattleLog.sanitizeHTML(htmlSrc); } this.updateScroll(); return; @@ -384,11 +394,11 @@ class BattleLog { for (const element of elements) { element.parentElement!.removeChild(element); } - if (!html) return; + if (!htmlSrc) return; if (forceAdd) { - this.addDiv('notice uhtml-' + id, BattleLog.sanitizeHTML(html)); + this.addDiv('notice uhtml-' + id, BattleLog.sanitizeHTML(htmlSrc)); } else { - this.prependDiv('notice uhtml-' + id, BattleLog.sanitizeHTML(html)); + this.prependDiv('notice uhtml-' + id, BattleLog.sanitizeHTML(htmlSrc)); } } hideChatFrom(userid: ID, showRevealButton = true, lineCount = 0) { @@ -634,8 +644,8 @@ class BattleLog { case 'uhtml': case 'uhtmlchange': let parts = target.split(','); - let html = parts.slice(1).join(',').trim(); - this.changeUhtml(parts[0], html, cmd === 'uhtml'); + let htmlSrc = parts.slice(1).join(',').trim(); + this.changeUhtml(parts[0], htmlSrc, cmd === 'uhtml'); return ['', '']; case 'raw': return ['chat', BattleLog.sanitizeHTML(target)]; diff --git a/src/battle-scene-stub.ts b/src/battle-scene-stub.ts index b27b7a74f..99a8dde09 100644 --- a/src/battle-scene-stub.ts +++ b/src/battle-scene-stub.ts @@ -1,4 +1,8 @@ -class BattleSceneStub { +import type {Pokemon, Side} from './battle'; +import type {ScenePos, PokemonSprite} from './battle-animations'; +import type {BattleLog} from './battle-log'; + +export class BattleSceneStub { animating: boolean = false; acceleration: number = NaN; gen: number = NaN; @@ -10,12 +14,12 @@ class BattleSceneStub { log: BattleLog = {add: (args: Args, kwargs?: KWArgs) => {}} as any; abilityActivateAnim(pokemon: Pokemon, result: string): void { } - addPokemonSprite(pokemon: Pokemon) { return null!; } + addPokemonSprite(pokemon: Pokemon): PokemonSprite { return null!; } addSideCondition(siden: number, id: ID, instant?: boolean | undefined): void { } animationOff(): void { } animationOn(): void { } maybeCloseMessagebar(args: Args, kwArgs: KWArgs): boolean { return false; } - closeMessagebar(): void { } + closeMessagebar(): boolean { return false; } damageAnim(pokemon: Pokemon, damage: string | number): void { } destroy(): void { } finishAnimations(): JQuery.Promise, any, any> | undefined { return void(0); } @@ -25,6 +29,7 @@ class BattleSceneStub { updateAcceleration(): void { } message(message: string, hiddenMessage?: string | undefined): void { } pause(): void { } + setMute(muted: boolean): void { } preemptCatchup(): void { } removeSideCondition(siden: number, id: ID): void { } reset(): void { } @@ -68,7 +73,6 @@ class BattleSceneStub { anim(pokemon: Pokemon, end: ScenePos, transition?: string) { } beforeMove(pokemon: Pokemon) { } afterMove(pokemon: Pokemon) { } - unlink(userid: string, showRevealButton = false) { } } if (typeof require === 'function') { diff --git a/src/battle-sound.ts b/src/battle-sound.ts index ae1bac2c2..5307e73f9 100644 --- a/src/battle-sound.ts +++ b/src/battle-sound.ts @@ -1,5 +1,5 @@ -class BattleBGM { +export class BattleBGM { /** * May be shared with other BGM objects: every battle has its own BattleBGM * object, but two battles with the same music will have the same HTMLAudioElement @@ -100,7 +100,7 @@ class BattleBGM { } } -const BattleSound = new class { +export const BattleSound = new class { soundCache: {[url: string]: HTMLAudioElement | undefined} = {}; bgm: BattleBGM[] = []; diff --git a/src/battle.ts b/src/battle.ts index 7e51d7a82..ceb23d287 100644 --- a/src/battle.ts +++ b/src/battle.ts @@ -27,13 +27,17 @@ * @license MIT */ -/** [id, element?, ...misc] */ -type EffectState = any[] & {0: ID}; -/** [name, minTimeLeft, maxTimeLeft] */ -type WeatherState = [string, number, number]; -type HPColor = 'r' | 'y' | 'g'; +import {BattleSceneStub} from './battle-scene-stub'; +import {BattleLog} from './battle-log'; +import {BattleScene, PokemonSprite, BattleStatusAnims} from './battle-animations'; -class Pokemon implements PokemonDetails, PokemonHealth { +/** [id, element?, ...misc] */ +export type EffectState = any[] & {0: ID}; +/** [name, minTimeLeft, maxTimeLeft] */ +export type WeatherState = [string, number, number]; +export type HPColor = 'r' | 'y' | 'g'; + +export class Pokemon implements PokemonDetails, PokemonHealth { name = ''; speciesForme = ''; @@ -570,6 +574,9 @@ class Pokemon implements PokemonDetails, PokemonHealth { } return percentage * maxWidth / 100; } + getHPText(precision = 1) { + return Pokemon.getHPText(this, precision); + } static getHPText(pokemon: PokemonHealth, precision = 1) { if (pokemon.maxhp === 100) return pokemon.hp + '%'; if (pokemon.maxhp !== 48) return (100 * pokemon.hp / pokemon.maxhp).toFixed(precision) + '%'; @@ -583,7 +590,7 @@ class Pokemon implements PokemonDetails, PokemonHealth { } } -class Side { +export class Side { battle: Battle; name = ''; id = ''; @@ -932,7 +939,7 @@ class Side { } } -interface PokemonDetails { +export interface PokemonDetails { details: string; name: string; speciesForme: string; @@ -942,14 +949,14 @@ interface PokemonDetails { ident: string; searchid: string; } -interface PokemonHealth { +export interface PokemonHealth { hp: number; maxhp: number; hpcolor: HPColor | ''; status: StatusName | 'tox' | '' | '???'; fainted?: boolean; } -interface ServerPokemon extends PokemonDetails, PokemonHealth { +export interface ServerPokemon extends PokemonDetails, PokemonHealth { ident: string; details: string; condition: string; @@ -976,8 +983,8 @@ interface ServerPokemon extends PokemonDetails, PokemonHealth { gigantamax: string | false; } -class Battle { - scene: BattleScene | BattleSceneStub; +export class Battle { + scene: BattleSceneStub; sidesSwitched = false; @@ -3669,7 +3676,7 @@ class Battle { } setMute(mute: boolean) { - BattleSound.setMute(mute); + this.scene.setMute(mute); } } diff --git a/src/globals.d.ts b/src/globals.d.ts index 67c82497e..b81224f6b 100644 --- a/src/globals.d.ts +++ b/src/globals.d.ts @@ -1,14 +1,5 @@ - - -// dependencies -/////////////// - -// Caja -declare var html4: any; -declare var html: any; - -// data -/////// +// dex data +/////////// declare var BattlePokedex: any; declare var BattleMovedex: any; @@ -16,21 +7,9 @@ declare var BattleAbilities: any; declare var BattleItems: any; declare var BattleAliases: any; declare var BattleStatuses: any; -// declare var BattleMoveAnims: any; -// declare var BattleStatusAnims: any; -// declare var BattleOtherAnims: any; -// declare var BattleBackdrops: any; -// declare var BattleBackdropsThree: any; -// declare var BattleBackdropsFour: any; -// declare var BattleBackdropsFive: any; -// declare var BattleEffects: any; declare var BattlePokemonSprites: any; declare var BattlePokemonSpritesBW: any; -// defined in battle-log-misc -declare function MD5(input: string): string; -declare function formatText(input: string, isTrusted?: boolean): string; - // PS globals ///////////// @@ -43,3 +22,18 @@ declare var app: {user: AnyObject, rooms: AnyObject, ignore?: AnyObject}; interface Window { [k: string]: any; } + +// Temporary globals (exported from modules, used by non-module files) + +// When creating now module files, these should all be commented out +// to make sure they're not being used globally in modules. + +declare var Battle: typeof import('./battle').Battle; +type Battle = import('./battle').Battle; +declare var BattleScene: typeof import('./battle-animations').BattleScene; +type BattleScene = import('./battle-animations').BattleScene; +declare var Pokemon: typeof import('./battle').Pokemon; +type Pokemon = import('./battle').Pokemon; +type ServerPokemon = import('./battle').ServerPokemon; +declare var BattleLog: typeof import('./battle-log').BattleLog; +type BattleLog = import('./battle-log').BattleLog; diff --git a/tslint.json b/tslint.json index 302df6498..280ac9e9a 100644 --- a/tslint.json +++ b/tslint.json @@ -36,6 +36,7 @@ "no-unnecessary-initializer": false, "object-literal-sort-keys": false, "object-literal-key-quotes": false, + "ordered-imports": false, "trailing-comma": [ true, {