diff --git a/.babelrc b/.babelrc index 20f9821dc..27ee33e22 100644 --- a/.babelrc +++ b/.babelrc @@ -5,6 +5,7 @@ ["@babel/plugin-proposal-class-properties", {"loose": true}], + ["@babel/plugin-proposal-optional-chaining", {"loose": true}], ["@babel/plugin-proposal-object-rest-spread", {"loose": true, "useBuiltIns": true}], "@babel/plugin-proposal-optional-catch-binding", diff --git a/package.json b/package.json index 24fc6151c..67fb1cec4 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "@babel/cli": "^7.2.3", "@babel/core": "^7.3.3", "@babel/plugin-proposal-class-properties": "^7.3.3", + "@babel/plugin-proposal-optional-chaining": "^7.6.0", "@babel/plugin-transform-member-expression-literals": "^7.2.0", "@babel/plugin-transform-property-literals": "^7.2.0", "@babel/plugin-transform-react-jsx": "^7.3.0", @@ -33,7 +34,7 @@ "mocha": "^6.0.2", "preact": "^8.3.1", "tslint": "^5.13.0", - "typescript": "^3.4.5" + "typescript": "^3.7.0-dev.20191011" }, "private": true } diff --git a/src/battle-animations.ts b/src/battle-animations.ts index 02a27c344..23c0a43db 100644 --- a/src/battle-animations.ts +++ b/src/battle-animations.ts @@ -557,7 +557,7 @@ class BattleScene { if (Dex.prefs('nopastgens')) gen = 6; if (Dex.prefs('bwgfx') && gen > 5) gen = 5; this.gen = gen; - this.activeCount = this.battle.mySide && this.battle.mySide.active.length || 1; + this.activeCount = this.battle.mySide?.active.length || 1; const isSPL = (typeof this.battle.rated === 'string' && this.battle.rated.startsWith("Smogon Premier League")); let bg: string; @@ -584,7 +584,7 @@ class BattleScene { } getDetailsText(pokemon: Pokemon) { - let name = pokemon.side && pokemon.side.n && + let name = pokemon.side?.n && (this.battle.ignoreOpponent || this.battle.ignoreNicks) ? pokemon.species : pokemon.name; if (name !== pokemon.species) { name += ' (' + pokemon.species + ')'; @@ -618,9 +618,9 @@ class BattleScene { let poke = side.pokemon[i]; if (i >= side.totalPokemon && i >= side.pokemon.length) { pokemonhtml += ``; - } else if (noShow && poke && poke.fainted) { + } else if (noShow && poke?.fainted) { pokemonhtml += ``; - } else if (noShow && poke && poke.status) { + } else if (noShow && poke?.status) { pokemonhtml += ``; } else if (noShow) { pokemonhtml += ``; @@ -1322,9 +1322,7 @@ class BattleScene { return pokemon.sprite.afterMove(); } updateSpritesForSide(side: Side) { - if (side.missedPokemon && side.missedPokemon.sprite) { - side.missedPokemon.sprite.destroy(); - } + side.missedPokemon?.sprite?.destroy(); side.missedPokemon = { sprite: new PokemonSprite(null, { diff --git a/src/battle-dex.ts b/src/battle-dex.ts index 0ca2cc8ce..9b875fb31 100644 --- a/src/battle-dex.ts +++ b/src/battle-dex.ts @@ -133,9 +133,9 @@ function getString(str: any) { } function toID(text: any) { - if (text && text.id) { + if (text?.id) { text = text.id; - } else if (text && text.userid) { + } else if (text?.userid) { text = text.userid; } if (typeof text !== 'string' && typeof text !== 'number') return '' as ID; @@ -220,16 +220,16 @@ const Dex = new class implements ModdedDex { resourcePrefix = (() => { let prefix = ''; - if (!window.document || !document.location || document.location.protocol !== 'http:') prefix = 'https:'; - return prefix + '//play.pokemonshowdown.com/'; + if (window.document?.location?.protocol !== 'http:') prefix = 'https:'; + return `${prefix}//play.pokemonshowdown.com/`; })(); fxPrefix = (() => { - if (window.document && document.location && document.location.protocol === 'file:') { - if (window.Replays) return 'https://play.pokemonshowdown.com/fx/'; - return 'fx/'; + if (window.document?.location?.protocol === 'file:') { + if (window.Replays) return `https://play.pokemonshowdown.com/fx/`; + return `fx/`; } - return '//play.pokemonshowdown.com/fx/'; + return `//play.pokemonshowdown.com/fx/`; })(); loadedSpriteData = {xy: 1, bw: 0}; @@ -255,7 +255,7 @@ const Dex = new class implements ModdedDex { if (avatar.charAt(0) === '#') { return Dex.resourcePrefix + 'sprites/trainers-custom/' + toID(avatar.substr(1)) + '.png'; } - if (avatar.includes('.') && window.Config && Config.server && Config.server.registered) { + if (avatar.includes('.') && window.Config?.server?.registered) { // custom avatar served by the server let protocol = (Config.server.port === 443) ? 'https' : 'http'; return protocol + '://' + Config.server.host + ':' + Config.server.port + @@ -284,8 +284,7 @@ const Dex = new class implements ModdedDex { prefs(prop: string, value?: any, save?: boolean) { // @ts-ignore - if (window.Storage && Storage.prefs) return Storage.prefs(prop, value, save); - return undefined; + return window.Storage?.prefs?.(prop, value, save); } getShortName(name: string) { @@ -661,9 +660,9 @@ const Dex = new class implements ModdedDex { getPokemonIconNum(id: ID, isFemale?: boolean, facingLeft?: boolean) { let num = 0; - if (window.BattlePokemonSprites && BattlePokemonSprites[id] && BattlePokemonSprites[id].num) { + if (window.BattlePokemonSprites?.[id]?.num) { num = BattlePokemonSprites[id].num; - } else if (window.BattlePokedex && window.BattlePokedex[id] && BattlePokedex[id].num) { + } else if (window.BattlePokedex?.[id]?.num) { num = BattlePokedex[id].num; } if (num < 0) num = 0; @@ -688,26 +687,26 @@ const Dex = new class implements ModdedDex { getPokemonIcon(pokemon: any, facingLeft?: boolean) { if (pokemon === 'pokeball') { - return 'background:transparent url(' + Dex.resourcePrefix + 'sprites/pokemonicons-pokeball-sheet.png) no-repeat scroll -0px 4px'; + return `background:transparent url(${Dex.resourcePrefix}sprites/pokemonicons-pokeball-sheet.png) no-repeat scroll -0px 4px`; } else if (pokemon === 'pokeball-statused') { - return 'background:transparent url(' + Dex.resourcePrefix + 'sprites/pokemonicons-pokeball-sheet.png) no-repeat scroll -40px 4px'; + return `background:transparent url(${Dex.resourcePrefix}sprites/pokemonicons-pokeball-sheet.png) no-repeat scroll -40px 4px`; } else if (pokemon === 'pokeball-fainted') { - return 'background:transparent url(' + Dex.resourcePrefix + 'sprites/pokemonicons-pokeball-sheet.png) no-repeat scroll -80px 4px;opacity:.4;filter:contrast(0)'; + return `background:transparent url(${Dex.resourcePrefix}sprites/pokemonicons-pokeball-sheet.png) no-repeat scroll -80px 4px;opacity:.4;filter:contrast(0)`; } else if (pokemon === 'pokeball-none') { - return 'background:transparent url(' + Dex.resourcePrefix + 'sprites/pokemonicons-pokeball-sheet.png) no-repeat scroll -80px 4px'; + return `background:transparent url(${Dex.resourcePrefix}sprites/pokemonicons-pokeball-sheet.png) no-repeat scroll -80px 4px`; } let id = toID(pokemon); - if (pokemon && pokemon.species) id = toID(pokemon.species); - if (pokemon && pokemon.volatiles && pokemon.volatiles.formechange && !pokemon.volatiles.transform) { + if (pokemon?.species) id = toID(pokemon.species); + if (pokemon?.volatiles?.formechange && !pokemon.volatiles.transform) { id = toID(pokemon.volatiles.formechange[1]); } - let num = this.getPokemonIconNum(id, pokemon && pokemon.gender === 'F', facingLeft); + let num = this.getPokemonIconNum(id, pokemon?.gender === 'F', facingLeft); let top = Math.floor(num / 12) * 30; let left = (num % 12) * 40; - let fainted = (pokemon && pokemon.fainted ? ';opacity:.3;filter:grayscale(100%) brightness(.5)' : ''); - return 'background:transparent url(' + Dex.resourcePrefix + 'sprites/pokemonicons-sheet.png?a6) no-repeat scroll -' + left + 'px -' + top + 'px' + fainted; + let fainted = (pokemon?.fainted ? `;opacity:.3;filter:grayscale(100%) brightness(.5)` : ``); + return `background:transparent url(${Dex.resourcePrefix}sprites/pokemonicons-sheet.png?a6) no-repeat scroll -${left}px -${top}px${fainted}`; } getTeambuilderSprite(pokemon: any, gen: number = 0) { @@ -723,7 +722,7 @@ const Dex = new class implements ModdedDex { } let shiny = (pokemon.shiny ? '-shiny' : ''); // let sdata; - // if (BattlePokemonSprites[id] && BattlePokemonSprites[id].front && !Dex.prefs('bwgfx')) { + // if (BattlePokemonSprites[id]?.front && !Dex.prefs('bwgfx')) { // if (BattlePokemonSprites[id].front.anif && pokemon.gender === 'F') { // spriteid += '-f'; // sdata = BattlePokemonSprites[id].front.anif; @@ -757,7 +756,7 @@ const Dex = new class implements ModdedDex { getItemIcon(item: any) { let num = 0; if (typeof item === 'string' && exports.BattleItems) item = exports.BattleItems[toID(item)]; - if (item && item.spritenum) num = item.spritenum; + if (item?.spritenum) num = item.spritenum; let top = Math.floor(num / 16) * 24; let left = (num % 16) * 24; diff --git a/src/battle-log.ts b/src/battle-log.ts index 55c4673ed..e4086c4ee 100644 --- a/src/battle-log.ts +++ b/src/battle-log.ts @@ -63,13 +63,13 @@ class BattleLog { this.elem.onscroll = null; } add(args: Args, kwArgs?: KWArgs, preempt?: boolean) { - if (kwArgs && kwArgs.silent) return; + if (kwArgs?.silent) return; let divClass = 'chat'; let divHTML = ''; let noNotify: boolean | undefined; switch (args[0]) { case 'chat': case 'c': case 'c:': - let battle = this.scene && this.scene.battle; + let battle = this.scene?.battle; let name; let message; if (args[0] === 'c:') { @@ -80,12 +80,12 @@ class BattleLog { message = args[2]; } let rank = name.charAt(0); - if (battle && battle.ignoreSpects && ' +'.includes(rank)) return; - if (battle && battle.ignoreOpponent) { + if (battle?.ignoreSpects && ' +'.includes(rank)) return; + if (battle?.ignoreOpponent) { if ('\u2605\u2606'.includes(rank) && toUserid(name) !== app.user.get('userid')) return; } - if (window.app && app.ignore && app.ignore[toUserid(name)] && ' +\u2605\u2606'.includes(rank)) return; - let isHighlighted = window.app && app.rooms && app.rooms[battle!.roomid].getHighlight(message); + if (window.app?.ignore?.[toUserid(name)] && ' +\u2605\u2606'.includes(rank)) return; + let isHighlighted = window.app?.rooms?.[battle!.roomid].getHighlight(message); [divClass, divHTML, noNotify] = this.parseChatMessage(message, name, '', isHighlighted); if (!noNotify && isHighlighted) { let notifyTitle = "Mentioned by " + name + " in " + battle!.roomid; @@ -403,7 +403,7 @@ class BattleLog { static usernameColor(name: ID) { if (this.colorCache[name]) return this.colorCache[name]; let hash; - if (window.Config && Config.customcolors && Config.customcolors[name]) { + if (window.Config?.customcolors?.[name]) { hash = MD5(Config.customcolors[name]); } else { hash = MD5(name); @@ -460,7 +460,7 @@ class BattleLog { static prefs(name: string) { // @ts-ignore - if (window.Storage && Storage.prefs) return Storage.prefs(name); + if (window.Storage?.prefs) return Storage.prefs(name); // @ts-ignore if (window.PS) return PS.prefs[name]; return undefined; @@ -469,7 +469,7 @@ class BattleLog { parseChatMessage( message: string, name: string, timestamp: string, isHighlighted?: boolean ): [string, string, boolean?] { - let showMe = !(BattleLog.prefs('chatformatting') || {}).hideme; + let showMe = !BattleLog.prefs('chatformatting')?.hideme; let group = ' '; if (!/[A-Za-z0-9]/.test(name.charAt(0))) { // Backwards compatibility @@ -479,8 +479,7 @@ class BattleLog { const colorStyle = ` style="color:${BattleLog.usernameColor(toID(name))}"`; const clickableName = `${BattleLog.escapeHTML(group)}${BattleLog.escapeHTML(name)}`; let hlClass = isHighlighted ? ' highlighted' : ''; - let isMine = (window.app && app.user && app.user.get('name') === name) || - (window.PS && PS.user.name === name); + let isMine = (window.app?.user?.get('name') === name) || (window.PS?.user.name === name); let mineClass = isMine ? ' mine' : ''; let cmd = ''; @@ -589,7 +588,7 @@ class BattleLog { } static interstice = (() => { - const whitelist: string[] = (window.Config && Config.whitelist) ? Config.whitelist : []; + const whitelist: string[] = window.Config?.whitelist || []; const patterns = whitelist.map(entry => new RegExp( `^(https?:)?//([A-Za-z0-9-]*\\.)?${entry}(/.*)?`, 'i')); @@ -610,7 +609,7 @@ class BattleLog { }; })(); - static tagPolicy: (tagName: string, attribs: string[]) => any = null!; + static tagPolicy: ((tagName: string, attribs: string[]) => any) | null = null; static initSanitizeHTML() { if (this.tagPolicy) return; if (!('html4' in window)) { @@ -755,7 +754,7 @@ class BattleLog { let formattedTime; // Try using Intl API if it exists - if (window.Intl && Intl.DateTimeFormat) { + if (window.Intl?.DateTimeFormat) { formattedTime = new Intl.DateTimeFormat(undefined, { month: 'long', day: 'numeric', hour: 'numeric', minute: 'numeric', }).format(parsedTime); diff --git a/src/battle-search.ts b/src/battle-search.ts index 63bf94aae..ff675d30c 100644 --- a/src/battle-search.ts +++ b/src/battle-search.ts @@ -732,7 +732,7 @@ class BattleSearch { let uselessMoves: SearchRow[] = []; let sketchedMoves: SearchRow[] = []; for (const id of moves) { - let isViable: boolean = BattleMovedex[id] && BattleMovedex[id].isViable; + let isViable: boolean = BattleMovedex[id]?.isViable; if (id === 'aerialace') isViable = ['scyther', 'aerodactylmega', 'kricketune'].includes(toID(set.species)); if (id === 'ancientpower') { isViable = ( @@ -813,7 +813,7 @@ class BattleSearch { 'acidarmor', 'amnesia', 'barrier', 'bind', 'clamp', 'confuseray', 'counter', 'firespin', 'hyperbeam', 'mirrormove', 'pinmissile', 'razorleaf', 'sing', 'slash', 'sludge', 'twineedle', 'wrap', - ].includes) { + ].includes(id)) { isViable = true; } @@ -904,7 +904,7 @@ class BattleSearch { let poorAbilities: SearchRow[] = [['header', "Situational Abilities"]]; let badAbilities: SearchRow[] = [['header', "Unviable Abilities"]]; for (const id of abilities) { - let rating = BattleAbilities[id] && BattleAbilities[id].rating; + let rating = BattleAbilities[id]?.rating; if (id === 'normalize') rating = 3; if (rating >= 3) { goodAbilities.push(['ability', id]); diff --git a/src/battle-text-parser.ts b/src/battle-text-parser.ts index 8cdb5cca4..ccc0303b0 100644 --- a/src/battle-text-parser.ts +++ b/src/battle-text-parser.ts @@ -521,7 +521,7 @@ class BattleTextParser { if (kwArgs.block) templateId = 'block'; if (kwArgs.upkeep) templateId = 'upkeep'; if (id === 'reflect' || id === 'lightscreen') templateId = 'startGen1'; - if (templateId === 'start' && kwArgs.from && kwArgs.from.startsWith('item:')) { + if (templateId === 'start' && kwArgs.from?.startsWith('item:')) { templateId += 'FromItem'; } const template = this.template(templateId, effect); @@ -538,7 +538,7 @@ class BattleTextParser { } let templateId = 'end'; let template = ''; - if (kwArgs.from && kwArgs.from.startsWith('item:')) { + if (kwArgs.from?.startsWith('item:')) { template = this.template('endFromItem', effect); } if (!template) template = this.template(templateId, effect); @@ -654,7 +654,7 @@ class BattleTextParser { return template.replace('[POKEMON]', this.pokemon(pokemon)); } const line1 = this.maybeAbility(kwArgs.from, kwArgs.of || pokemon); - if (kwArgs.from && kwArgs.from.startsWith('item:')) { + if (kwArgs.from?.startsWith('item:')) { const template = this.template('endFromItem', status); return line1 + template.replace('[POKEMON]', this.pokemon(pokemon)).replace('[ITEM]', this.effect(kwArgs.from)); } @@ -859,7 +859,7 @@ class BattleTextParser { else if (amount === 0) templateId += '0'; if (amount && kwArgs.zeffect) { templateId += (kwArgs.multiple ? 'MultipleFromZEffect' : 'FromZEffect'); - } else if (amount && kwArgs.from && kwArgs.from.startsWith('item:')) { + } else if (amount && kwArgs.from?.startsWith('item:')) { templateId += 'FromItem'; } const template = this.template(templateId, kwArgs.from); diff --git a/src/battle-tooltips.ts b/src/battle-tooltips.ts index d0fb6c3e9..1c2fbeba4 100644 --- a/src/battle-tooltips.ts +++ b/src/battle-tooltips.ts @@ -26,7 +26,7 @@ class ModifiableValue { this.serverPokemon = serverPokemon; this.itemName = Dex.getItem(serverPokemon.item).name; - const ability = serverPokemon.ability || (pokemon && pokemon.ability) || serverPokemon.baseAbility; + const ability = serverPokemon.ability || pokemon?.ability || serverPokemon.baseAbility; this.abilityName = Dex.getAbility(ability).name; this.weatherName = Dex.getMove(battle.weather).exists ? Dex.getMove(battle.weather).name : Dex.getAbility(battle.weather).name; @@ -43,7 +43,7 @@ class ModifiableValue { this.comment.push(` (${itemName} suppressed by Magic Room)`); return false; } - if (this.pokemon && this.pokemon.volatiles['embargo']) { + if (this.pokemon?.volatiles['embargo']) { this.comment.push(` (${itemName} suppressed by Embargo)`); return false; } @@ -58,7 +58,7 @@ class ModifiableValue { } tryAbility(abilityName: string) { if (abilityName !== this.abilityName) return false; - if (this.pokemon && this.pokemon.volatiles['gastroacid']) { + if (this.pokemon?.volatiles['gastroacid']) { this.comment.push(` (${abilityName} suppressed by Gastro Acid)`); return false; } @@ -620,7 +620,7 @@ class BattleTooltips { text += '

' + name + genderBuf + (pokemon.level !== 100 ? ' L' + pokemon.level + '' : '') + '
'; - if (clientPokemon && clientPokemon.volatiles.formechange) { + if (clientPokemon?.volatiles.formechange) { if (clientPokemon.volatiles.transform) { text += '(Transformed into ' + clientPokemon.volatiles.formechange[1] + ')
'; } else { @@ -672,7 +672,7 @@ class BattleTooltips { } let itemText = ''; - if (serverPokemon && serverPokemon.item) { + if (serverPokemon?.item) { itemText = 'Item: ' + Dex.getItem(serverPokemon.item).name; } else if (clientPokemon) { let item = ''; @@ -706,7 +706,7 @@ class BattleTooltips { for (const moveid of serverPokemon.moves) { let move = Dex.getMove(moveid); let moveName = '• ' + move.name; - if (battlePokemon && battlePokemon.moveTrack) { + if (battlePokemon?.moveTrack) { for (const row of battlePokemon.moveTrack) { if (moveName === row[0]) { moveName = this.getPPUseText(row, true); @@ -717,7 +717,7 @@ class BattleTooltips { text += moveName + '
'; } text += '

'; - } else if (!this.battle.hardcoreMode && clientPokemon && clientPokemon.moveTrack.length) { + } else if (!this.battle.hardcoreMode && clientPokemon?.moveTrack.length) { // move list (guessed) text += '

'; for (const row of clientPokemon.moveTrack) { @@ -739,7 +739,7 @@ class BattleTooltips { calculateModifiedStats(clientPokemon: Pokemon | null, serverPokemon: ServerPokemon) { let stats = {...serverPokemon.stats}; let pokemon = clientPokemon || serverPokemon; - const isPowerTrick = clientPokemon && clientPokemon.volatiles['powertrick']; + const isPowerTrick = clientPokemon?.volatiles['powertrick']; for (const statName of Dex.statNamesExceptHP) { let sourceStatName = statName; if (isPowerTrick) { @@ -857,7 +857,7 @@ class BattleTooltips { if (ability === 'solarpower') { stats.spa = Math.floor(stats.spa * 1.5); } - let allyActive = clientPokemon && clientPokemon.side.active; + let allyActive = clientPokemon?.side.active; if (allyActive) { for (const ally of allyActive) { if (!ally || ally.fainted) continue; @@ -955,7 +955,7 @@ class BattleTooltips { } renderStats(clientPokemon: Pokemon | null, serverPokemon?: ServerPokemon | null, short?: boolean) { - const isTransformed = clientPokemon && clientPokemon.volatiles.transform; + const isTransformed = clientPokemon?.volatiles.transform; if (!serverPokemon || isTransformed) { if (!clientPokemon) throw new Error('Must pass either clientPokemon or serverPokemon'); let [min, max] = this.getSpeedRange(clientPokemon); @@ -1164,7 +1164,7 @@ class BattleTooltips { } return value; } - if (pokemon && pokemon.boosts.accuracy) { + if (pokemon?.boosts.accuracy) { if (pokemon.boosts.accuracy > 0) { value.modify((pokemon.boosts.accuracy + 3) / 3); } else { @@ -1238,7 +1238,7 @@ class BattleTooltips { else basePower = 20; value.set(basePower); } - if (move.id === 'hex' && target && target.status) { + if (move.id === 'hex' && target?.status) { value.modify(2, 'Hex + status'); } if (move.id === 'punishment' && target) { @@ -1582,7 +1582,7 @@ class BattleTooltips { abilityData.baseAbility = clientPokemon.baseAbility; } } else { - const species = clientPokemon.getSpecies() || (serverPokemon && serverPokemon.species) || ''; + const species = clientPokemon.getSpecies() || serverPokemon?.species || ''; const template = this.battle.dex.getTemplate(species); if (template.exists && template.abilities) { abilityData.possibilities = [template.abilities['0']]; @@ -2242,9 +2242,9 @@ class BattleStatGuesser { } if (natureOverride) { val *= natureOverride; - } else if (BattleNatures[set.nature!] && BattleNatures[set.nature!].plus === stat) { + } else if (BattleNatures[set.nature!]?.plus === stat) { val *= 1.1; - } else if (BattleNatures[set.nature!] && BattleNatures[set.nature!].minus === stat) { + } else if (BattleNatures[set.nature!]?.minus === stat) { val *= 0.9; } if (!this.supportsEVs) { diff --git a/src/battle.ts b/src/battle.ts index 725334614..133bd96ce 100644 --- a/src/battle.ts +++ b/src/battle.ts @@ -392,7 +392,7 @@ class Pokemon implements PokemonDetails, PokemonHealth { return '' + badBoostTable[-this.boosts[boostStat]] + ' ' + boostStatTable[boostStat]; } getWeightKg(serverPokemon?: ServerPokemon) { - let autotomizeFactor = this.volatiles.autotomize ? this.volatiles.autotomize[1] * 100 : 0; + let autotomizeFactor = this.volatiles.autotomize?.[1] * 100 || 0; return Math.max(this.getTemplate(serverPokemon).weightkg - autotomizeFactor, 0.1); } getBoostType(boostStat: BoostStatName) { @@ -486,7 +486,7 @@ class Pokemon implements PokemonDetails, PokemonHealth { } let item = toID(serverPokemon ? serverPokemon.item : this.item); - let ability = toID(this.ability || (serverPokemon && serverPokemon.ability)); + let ability = toID(this.ability || serverPokemon?.ability); if (battle.hasPseudoWeather('Magic Room') || this.volatiles['embargo'] || ability === 'klutz') { item = '' as ID; } @@ -779,8 +779,8 @@ class Side { pokemon.clearVolatile(); pokemon.lastMove = ''; this.battle.lastMove = 'switch-in'; - if (this.lastPokemon && (this.lastPokemon.lastMove === 'batonpass' || this.lastPokemon.lastMove === 'zbatonpass')) { - pokemon.copyVolatileFrom(this.lastPokemon); + if (['batonpass', 'zbatonpass'].includes(this.lastPokemon?.lastMove!)) { + pokemon.copyVolatileFrom(this.lastPokemon!); } this.battle.scene.animSummon(pokemon, slot); @@ -1271,7 +1271,7 @@ class Battle { updateToxicTurns() { for (const side of this.sides) { for (const poke of side.active) { - if (poke && poke.status === 'tox') poke.statusData.toxicTurns++; + if (poke?.status === 'tox') poke.statusData.toxicTurns++; } } } @@ -1783,7 +1783,7 @@ class Battle { let poke = this.getPokemon(args[1]); if (poke) { this.scene.resultAnim(poke, 'Super-effective', 'bad'); - if (window.Config && Config.server && Config.server.afd) { + if (window.Config?.server?.afd) { this.scene.runOtherAnim('hitmark' as ID, [poke]); } } @@ -2969,7 +2969,7 @@ class Battle { // search p1's pokemon if (siden !== this.p2.n && !isNew) { const active = this.p1.active[slot]; - if (active && active.searchid === searchid && !isSwitch) { + if (active?.searchid === searchid && !isSwitch) { active.slot = slot; return active; } @@ -2996,7 +2996,7 @@ class Battle { // search p2's pokemon if (siden !== this.p1.n && !isNew) { const active = this.p2.active[slot]; - if (active && active.searchid === searchid && !isSwitch) { + if (active?.searchid === searchid && !isSwitch) { if (slot >= 0) active.slot = slot; return active; } @@ -3188,7 +3188,7 @@ class Battle { return; } else if (args[1].slice(-14) === ' seconds left.') { let hasIndex = args[1].indexOf(' has '); - let userid = (window.app && app!.user && app!.user.get('userid')); + let userid = window.app?.user?.get('userid'); if (toID(args[1].slice(0, hasIndex)) === userid) { this.kickingInactive = parseInt(args[1].slice(hasIndex + 5), 10) || true; } @@ -3407,7 +3407,7 @@ class Battle { let nextArgs: Args = ['']; let nextKwargs: KWArgs = {}; const nextLine = this.activityQueue[this.activityStep + 1] || ''; - if (nextLine && nextLine.substr(0, 2) === '|-') { + if (nextLine.slice(0, 2) === '|-') { ({args: nextArgs, kwArgs: nextKwargs} = BattleTextParser.parseLine(nextLine)); } diff --git a/src/client-main.ts b/src/client-main.ts index 431839325..fe9140f43 100644 --- a/src/client-main.ts +++ b/src/client-main.ts @@ -159,10 +159,7 @@ class PSTeams extends PSStreamModel<'team' | 'format'> { const formatid = toID(format); if (!window.BattleFormats) return formatid; const formatEntry = BattleFormats[formatid]; - if (formatEntry && formatEntry.teambuilderFormat) { - return formatEntry.teambuilderFormat; - } - return formatid; + return formatEntry?.teambuilderFormat || formatid; } getKey(team: Team | null) { if (!team) return ''; @@ -209,7 +206,7 @@ class PSTeams extends PSStreamModel<'team' | 'format'> { let slashIndex = line.lastIndexOf('/', pipeIndex); if (slashIndex < 0) slashIndex = bracketIndex; // line.slice(slashIndex + 1, pipeIndex) will be '' let format = bracketIndex > 0 ? line.slice(0, bracketIndex) : 'gen7'; - if (format && format.slice(0, 3) !== 'gen') format = 'gen6' + format; + if (format.slice(0, 3) !== 'gen') format = 'gen6' + format; return { name: line.slice(slashIndex + 1, pipeIndex), format: format as ID, @@ -786,7 +783,7 @@ const PS = new class extends PSModel { } const roomType = this.roomTypes[options.type]; - if (roomType && roomType.title) options.title = roomType.title; + if (roomType?.title) options.title = roomType.title; const Model = roomType ? roomType.Model : PlaceholderRoom; return new Model(options); } diff --git a/src/panel-mainmenu.tsx b/src/panel-mainmenu.tsx index 81e6f2039..db19ea846 100644 --- a/src/panel-mainmenu.tsx +++ b/src/panel-mainmenu.tsx @@ -73,11 +73,11 @@ class MainMenuRoom extends PSRoom { if (!room.pmTarget) continue; const targetUserid = toID(room.pmTarget); if (!room.challengedFormat && !(targetUserid in json.challengesFrom) && - !room.challengingFormat && (json.challengeTo || {}).to !== targetUserid) { + !room.challengingFormat && json.challengeTo?.to !== targetUserid) { continue; } room.challengedFormat = json.challengesFrom[targetUserid] || null; - room.challengingFormat = (json.challengeTo || {}).to === targetUserid ? json.challengeTo.format : null; + room.challengingFormat = json.challengeTo?.to === targetUserid ? json.challengeTo.format : null; room.update(''); } } @@ -164,7 +164,7 @@ class MainMenuRoom extends PSRoom { isTeambuilderFormat = false; } } - if (BattleFormats[id] && BattleFormats[id].isTeambuilderFormat) { + if (BattleFormats[id]?.isTeambuilderFormat) { isTeambuilderFormat = true; } // make sure formats aren't out-of-order @@ -332,10 +332,7 @@ class MainMenuPanel extends PSRoomPanel { class FormatDropdown extends preact.Component<{format?: string, onChange?: JSX.EventHandler}> { base?: HTMLButtonElement; getFormat() { - if (this.base && this.base.value) { - return this.base.value; - } - return '[Gen 7] Random Battle'; + return this.base?.value || '[Gen 7] Random Battle'; } componentDidMount() { this.base!.value = this.getFormat(); @@ -379,7 +376,7 @@ class TeamDropdown extends preact.Component<{format: string}> { change = () => this.forceUpdate(); render() { const formatid = PS.teams.teambuilderFormat(this.props.format); - const formatData = window.BattleFormats && BattleFormats[formatid]; + const formatData = window.BattleFormats?.[formatid]; if (formatData && formatData.team) { return