Begin implementing abilities

pull/1/head
Flashfyre 2023-04-26 23:33:13 -04:00
parent f790a5ff2a
commit c614295b5e
6 changed files with 234 additions and 86 deletions

View File

@ -25,6 +25,7 @@ import { Gender } from "./data/gender";
import { Weather, WeatherType, getRandomWeatherType, getWeatherDamageMessage, getWeatherLapseMessage } from "./data/weather";
import { TempBattleStat } from "./data/temp-battle-stat";
import { ArenaTrapTag, TrickRoomTag } from "./data/arena-tag";
import { ProtectStatAttr, applyPreStatChangeAbilityAttrs } from "./data/ability";
export class SelectStarterPhase extends BattlePhase {
constructor(scene: BattleScene) {
@ -1080,9 +1081,10 @@ export class MoveAnimTestPhase extends BattlePhase {
export class StatChangePhase extends PokemonPhase {
private stats: BattleStat[];
private selfTarget: boolean;
private levels: integer;
constructor(scene: BattleScene, player: boolean, stats: BattleStat[], levels: integer) {
constructor(scene: BattleScene, player: boolean, selfTarget: boolean, stats: BattleStat[], levels: integer) {
super(scene, player);
const allStats = Utils.getEnumValues(BattleStat);
@ -1093,19 +1095,26 @@ export class StatChangePhase extends PokemonPhase {
start() {
const pokemon = this.getPokemon();
const filteredStats = this.stats.filter(stat => {
const cancelled = new Utils.BooleanHolder(false);
if (!this.selfTarget && this.levels < 0)
applyPreStatChangeAbilityAttrs(ProtectStatAttr, this.getPokemon(), stat, cancelled);
return !cancelled.value;
});
const battleStats = this.getPokemon().summonData.battleStats;
const relLevels = this.stats.map(stat => (this.levels >= 1 ? Math.min(battleStats[stat] + this.levels, 6) : Math.max(battleStats[stat] + this.levels, -6)) - battleStats[stat]);
const relLevels = filteredStats.map(stat => (this.levels >= 1 ? Math.min(battleStats[stat] + this.levels, 6) : Math.max(battleStats[stat] + this.levels, -6)) - battleStats[stat]);
const end = () => {
const messages = this.getStatChangeMessages(relLevels);
const messages = this.getStatChangeMessages(filteredStats, relLevels);
for (let message of messages)
this.scene.queueMessage(message);
for (let stat of this.stats)
for (let stat of filteredStats)
pokemon.summonData.battleStats[stat] = Math.max(Math.min(pokemon.summonData.battleStats[stat] + this.levels, 6), -6);
console.log(pokemon.summonData.battleStats);
this.end();
};
@ -1113,7 +1122,7 @@ export class StatChangePhase extends PokemonPhase {
pokemon.enableMask();
const pokemonMaskSprite = pokemon.maskSprite;
const statSprite = this.scene.add.tileSprite((this.player ? 106 : 236) * 6, ((this.player ? 148 : 84) + (this.levels >= 1 ? 160 : 0)) * 6, 156, 316, 'battle_stats', this.stats.length > 1 ? 'mix' : BattleStat[this.stats[0]].toLowerCase());
const statSprite = this.scene.add.tileSprite((this.player ? 106 : 236) * 6, ((this.player ? 148 : 84) + (this.levels >= 1 ? 160 : 0)) * 6, 156, 316, 'battle_stats', filteredStats.length > 1 ? 'mix' : BattleStat[filteredStats[0]].toLowerCase());
statSprite.setAlpha(0);
statSprite.setScale(6);
statSprite.setOrigin(0.5, 1);
@ -1150,11 +1159,11 @@ export class StatChangePhase extends PokemonPhase {
end();
}
getStatChangeMessages(relLevels: integer[]): string[] {
getStatChangeMessages(stats: BattleStat[], relLevels: integer[]): string[] {
const messages: string[] = [];
for (let s = 0; s < this.stats.length; s++)
messages.push(getPokemonMessage(this.getPokemon(), `'s ${getBattleStatName(this.stats[s])} ${getBattleStatLevelChangeDescription(Math.abs(relLevels[s]), this.levels >= 1)}!`));
for (let s = 0; s < stats.length; s++)
messages.push(getPokemonMessage(this.getPokemon(), `'s ${getBattleStatName(stats[s])} ${getBattleStatLevelChangeDescription(Math.abs(relLevels[s]), this.levels >= 1)}!`));
return messages;
}
}

View File

@ -1,14 +1,128 @@
import Pokemon, { PokemonMove } from "../pokemon";
import { Type } from "./type";
import * as Utils from "../utils";
import { BattleStat } from "./battle-stat";
import { StatChangePhase } from "../battle-phases";
export class Ability {
public id: Abilities;
public name: string;
public description: string;
public generation: integer;
public attrs: AbilityAttr[];
constructor(id: Abilities, name: string, description: string, generation: integer) {
this.id = id;
this.name = name;
this.description = description;
this.generation = generation;
this.attrs = [];
}
getAttrs(attrType: { new(...args: any[]): AbilityAttr }): AbilityAttr[] {
return this.attrs.filter(a => a instanceof attrType);
}
attr<T extends new (...args: any[]) => AbilityAttr>(AttrType: T, ...args: ConstructorParameters<T>): Ability {
const attr = new AttrType(...args);
this.attrs.push(attr);
return this;
}
}
export abstract class AbilityAttr { }
export class PreDefendAbilityAttr extends AbilityAttr {
applyPreDefend(pokemon: Pokemon, attacker: Pokemon, move: PokemonMove, cancelled: Utils.BooleanHolder, args: any[]): boolean {
return false;
}
}
export class TypeImmunityAttr extends PreDefendAbilityAttr {
private immuneType: Type;
constructor(immuneType: Type) {
super();
this.immuneType = immuneType;
}
applyPreDefend(pokemon: Pokemon, attacker: Pokemon, move: PokemonMove, cancelled: Utils.BooleanHolder, args: any[]): boolean {
if (move.getMove().type === this.immuneType) {
(args[0] as Utils.NumberHolder).value = 0;
return true;
}
return false;
}
}
class TypeImmunityStatChangeAttr extends TypeImmunityAttr {
private stat: BattleStat;
private levels: integer;
constructor(immuneType: Type, stat: BattleStat, levels: integer) {
super(immuneType);
this.stat = stat;
this.levels = levels;
}
applyPreDefend(pokemon: Pokemon, attacker: Pokemon, move: PokemonMove, cancelled: Utils.BooleanHolder, args: any[]): boolean {
const ret = super.applyPreDefend(pokemon, attacker, move, cancelled, args);
if (ret) {
cancelled.value = true;
pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.isPlayer(), true, [ this.stat ], this.levels));
}
return ret;
}
}
export class PreStatChangeAbilityAttr extends AbilityAttr {
applyPreStatChange(pokemon: Pokemon, stat: BattleStat, cancelled: Utils.BooleanHolder, args: any[]): boolean {
return false;
}
}
export class ProtectStatAttr extends PreStatChangeAbilityAttr {
private protectedStats: BattleStat[];
constructor(...stats: BattleStat[]) {
super();
this.protectedStats = stats;
}
applyPreStatChange(pokemon: Pokemon, stat: BattleStat, cancelled: Utils.BooleanHolder, args: any[]): boolean {
if (!this.protectedStats.length || this.protectedStats.indexOf(stat) > -1) {
cancelled.value = true;
return true;
}
return false;
}
}
export function applyPreDefendAbilityAttrs(attrType: { new(...args: any[]): PreDefendAbilityAttr },
pokemon: Pokemon, attacker: Pokemon, move: PokemonMove, cancelled: Utils.BooleanHolder, ...args: any[]): void {
const ability = pokemon.getAbility();
const attrs = ability.getAttrs(attrType) as PreDefendAbilityAttr[];
for (let attr of attrs) {
if (attr.applyPreDefend(pokemon, attacker, move, cancelled, args))
console.log('Applied', ability.name, attr);
}
}
export function applyPreStatChangeAbilityAttrs(attrType: { new(...args: any[]): PreStatChangeAbilityAttr },
pokemon: Pokemon, stat: BattleStat, cancelled: Utils.BooleanHolder, ...args: any[]) {
const ability = pokemon.getAbility();
const attrs = ability.getAttrs(attrType) as PreStatChangeAbilityAttr[];
for (let attr of attrs) {
if (attr.applyPreStatChange(pokemon, stat, cancelled, args))
console.log('Applied', ability.name, attr);
}
}
@ -193,7 +307,8 @@ export const abilities = [
new Ability(Abilities.BATTLE_ARMOR, "Battle Armor (N)", "The POKéMON is protected against critical hits.", 3),
new Ability(Abilities.BLAZE, "Blaze (N)", "Powers up FIRE-type moves in a pinch.", 3),
new Ability(Abilities.CHLOROPHYLL, "Chlorophyll (N)", "Boosts the POKéMON's SPEED in sunshine.", 3),
new Ability(Abilities.CLEAR_BODY, "Clear Body (N)", "Prevents other POKéMON from lowering its stats.", 3),
new Ability(Abilities.CLEAR_BODY, "Clear Body", "Prevents other POKéMON from lowering its stats.", 3)
.attr(ProtectStatAttr),
new Ability(Abilities.CLOUD_NINE, "Cloud Nine (N)", "Eliminates the effects of weather.", 3),
new Ability(Abilities.COLOR_CHANGE, "Color Change (N)", "Changes the POKéMON's type to the foe's move.", 3),
new Ability(Abilities.COMPOUND_EYES, "Compound Eyes (N)", "The POKéMON's accuracy is boosted.", 3),
@ -209,15 +324,19 @@ export const abilities = [
new Ability(Abilities.GUTS, "Guts (N)", "Boosts ATTACK if there is a status problem.", 3),
new Ability(Abilities.HUGE_POWER, "Huge Power (N)", "Raises the POKéMON's ATTACK stat.", 3),
new Ability(Abilities.HUSTLE, "Hustle (N)", "Boosts the ATTACK stat, but lowers accuracy.", 3),
new Ability(Abilities.HYPER_CUTTER, "Hyper Cutter (N)", "Prevents other POKéMON from lowering ATTACK stat.", 3),
new Ability(Abilities.HYPER_CUTTER, "Hyper Cutter", "Prevents other POKéMON from lowering ATTACK stat.", 3)
.attr(ProtectStatAttr, BattleStat.ATK),
new Ability(Abilities.ILLUMINATE, "Illuminate (N)", "Raises the likelihood of meeting wild POKéMON.", 3),
new Ability(Abilities.IMMUNITY, "Immunity (N)", "Prevents the POKéMON from getting poisoned.", 3),
new Ability(Abilities.INNER_FOCUS, "Inner Focus (N)", "The POKéMON is protected from flinching.", 3),
new Ability(Abilities.INSOMNIA, "Insomnia (N)", "Prevents the POKéMON from falling asleep.", 3),
new Ability(Abilities.INTIMIDATE, "Intimidate (N)", "Lowers the foe's ATTACK stat.", 3),
new Ability(Abilities.KEEN_EYE, "Keen Eye (N)", "Prevents other POKéMON from lowering accuracy.", 3),
new Ability(Abilities.LEVITATE, "Levitate (N)", "Gives immunity to GROUND-type moves.", 3),
new Ability(Abilities.LIGHTNING_ROD, "Lightning Rod (N)", "Draws in all ELECTRIC-type moves to up SP. ATK.", 3),
new Ability(Abilities.KEEN_EYE, "Keen Eye", "Prevents other POKéMON from lowering accuracy.", 3)
.attr(ProtectStatAttr, BattleStat.ACC),
new Ability(Abilities.LEVITATE, "Levitate", "Gives immunity to GROUND-type moves.", 3)
.attr(TypeImmunityAttr, Type.FLYING),
new Ability(Abilities.LIGHTNING_ROD, "Lightning Rod", "Draws in all ELECTRIC-type moves to up SP. ATK.", 3)
.attr(TypeImmunityStatChangeAttr, Type.ELECTRIC, BattleStat.SPATK, 1),
new Ability(Abilities.LIMBER, "Limber (N)", "The POKéMON is protected from paralysis.", 3),
new Ability(Abilities.LIQUID_OOZE, "Liquid Ooze (N)", "Damages attackers using any draining move.", 3),
new Ability(Abilities.MAGMA_ARMOR, "Magma Armor (N)", "Prevents the POKéMON from becoming frozen.", 3),
@ -262,7 +381,8 @@ export const abilities = [
new Ability(Abilities.VOLT_ABSORB, "Volt Absorb (N)", "Restores HP if hit by an ELECTRIC-type move.", 3),
new Ability(Abilities.WATER_ABSORB, "Water Absorb (N)", "Restores HP if hit by a WATER-type move.", 3),
new Ability(Abilities.WATER_VEIL, "Water Veil (N)", "Prevents the POKéMON from getting a burn.", 3),
new Ability(Abilities.WHITE_SMOKE, "White Smoke (N)", "Prevents other POKéMON from lowering its stats.", 3),
new Ability(Abilities.WHITE_SMOKE, "White Smoke", "Prevents other POKéMON from lowering its stats.", 3)
.attr(ProtectStatAttr),
new Ability(Abilities.WONDER_GUARD, "Wonder Guard (N)", "Only supereffective moves will hit.", 3),
new Ability(Abilities.ADAPTABILITY, "Adaptability (N)", "Powers up moves of the same type.", 4),
new Ability(Abilities.AFTERMATH, "Aftermath (N)", "Damages the attacker landing the finishing hit.", 4),
@ -304,7 +424,8 @@ export const abilities = [
new Ability(Abilities.SOLID_ROCK, "Solid Rock (N)", "Reduces damage from super-effective attacks.", 4),
new Ability(Abilities.STALL, "Stall (N)", "The POKéMON moves after all other POKéMON do.", 4),
new Ability(Abilities.STEADFAST, "Steadfast (N)", "Raises SPEED each time the POKéMON flinches.", 4),
new Ability(Abilities.STORM_DRAIN, "Storm Drain (N)", "Draws in all WATER-type moves to up SP. ATK.", 4),
new Ability(Abilities.STORM_DRAIN, "Storm Drain", "Draws in all WATER-type moves to up SP. ATK.", 4)
.attr(TypeImmunityStatChangeAttr, Type.WATER, BattleStat.SPATK, 1),
new Ability(Abilities.SUPER_LUCK, "Super Luck (N)", "Heightens the critical-hit ratios of moves.", 4),
new Ability(Abilities.TANGLED_FEET, "Tangled Feet (N)", "Raises evasion if the POKéMON is confused.", 4),
new Ability(Abilities.TECHNICIAN, "Technician (N)", "Powers up the POKéMON's weaker moves.", 4),
@ -312,7 +433,8 @@ export const abilities = [
new Ability(Abilities.UNAWARE, "Unaware (N)", "Ignores any stat changes in the POKéMON.", 4),
new Ability(Abilities.UNBURDEN, "Unburden (N)", "Raises SPEED if a held item is used.", 4),
new Ability(Abilities.ANALYTIC, "Analytic (N)", "Boosts move power when the POKéMON moves last.", 5),
new Ability(Abilities.BIG_PECKS, "Big Pecks (N)", "Protects the POKéMON from DEFENSE-lowering attacks.", 5),
new Ability(Abilities.BIG_PECKS, "Big Pecks", "Protects the POKéMON from DEFENSE-lowering attacks.", 5)
.attr(ProtectStatAttr, BattleStat.DEF),
new Ability(Abilities.CONTRARY, "Contrary (N)", "Makes stat changes have an opposite effect.", 5),
new Ability(Abilities.CURSED_BODY, "Cursed Body (N)", "May disable a move used on the POKéMON.", 5),
new Ability(Abilities.DEFEATIST, "Defeatist (N)", "Lowers stats when HP drops below half.", 5),

View File

@ -101,13 +101,13 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc {
case BerryType.APICOT:
return (pokemon: Pokemon) => {
const battleStat = (berryType - BerryType.LIECHI) as BattleStat;
pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.isPlayer(), [ battleStat ], 1));
pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.isPlayer(), true, [ battleStat ], 1));
};
case BerryType.LANSAT:
return (pokemon: Pokemon) => {
pokemon.addTag(BattlerTagType.CRIT_BOOST);
};
case BerryType.STARF:
return (pokemon: Pokemon) => pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.isPlayer(), [ BattleStat.RAND ], 2));
return (pokemon: Pokemon) => pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.isPlayer(), true, [ BattleStat.RAND ], 2));
}
}

View File

@ -9,7 +9,6 @@ import { Type } from "./type";
import * as Utils from "../utils";
import { WeatherType } from "./weather";
import { ArenaTagType, ArenaTrapTag } from "./arena-tag";
import { FlinchChanceModifier } from "../modifier/modifier";
export enum MoveCategory {
PHYSICAL,
@ -1095,7 +1094,7 @@ export class StatChangeAttr extends MoveEffectAttr {
if (move.chance < 0 || move.chance === 100 || Utils.randInt(100) < move.chance) {
const levels = this.getLevels(user);
user.scene.unshiftPhase(new StatChangePhase(user.scene, user.isPlayer() === this.selfTarget, this.stats, levels));
user.scene.unshiftPhase(new StatChangePhase(user.scene, user.isPlayer() === this.selfTarget, this.selfTarget, this.stats, levels));
return true;
}

View File

@ -23,6 +23,7 @@ import { WeatherType } from './data/weather';
import { TempBattleStat } from './data/temp-battle-stat';
import { WeakenMoveTypeTag } from './data/arena-tag';
import { Biome } from './data/biome';
import { Abilities, Ability, TypeImmunityAttr, abilities, applyPreDefendAbilityAttrs } from './data/ability';
export default abstract class Pokemon extends Phaser.GameObjects.Container {
public id: integer;
@ -345,6 +346,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
return this.getTypes().indexOf(type) > -1;
}
getAbility(): Ability {
return abilities[this.species.getAbility(this.abilityIndex)];
}
getAttackMoveEffectiveness(moveType: Type): TypeDamageMultiplier {
const types = this.getTypes();
return getTypeDamageMultiplier(moveType, types[0]) * (types.length ? getTypeDamageMultiplier(moveType, types[1]) : 1) as TypeDamageMultiplier;
@ -479,9 +484,15 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
case MoveCategory.PHYSICAL:
case MoveCategory.SPECIAL:
const isPhysical = moveCategory === MoveCategory.PHYSICAL;
const cancelled = new Utils.BooleanHolder(false);
const power = new Utils.NumberHolder(move.power);
const typeMultiplier = getTypeDamageMultiplier(move.type, this.getSpeciesForm().type1) * (this.getSpeciesForm().type2 !== null ? getTypeDamageMultiplier(move.type, this.getSpeciesForm().type2) : 1);
const typeMultiplier = new Utils.NumberHolder(getTypeDamageMultiplier(move.type, this.getSpeciesForm().type1) * (this.getSpeciesForm().type2 !== null ? getTypeDamageMultiplier(move.type, this.getSpeciesForm().type2) : 1));
const weatherTypeMultiplier = this.scene.arena.getAttackTypeMultiplier(move.type);
applyPreDefendAbilityAttrs(TypeImmunityAttr, this, source, battlerMove, cancelled, typeMultiplier);
if (cancelled.value)
result = MoveResult.NO_EFFECT;
else {
applyMoveAttrs(VariablePowerAttr, source, this, move, power);
this.scene.arena.applyTags(WeakenMoveTypeTag, move.type, power);
this.scene.applyModifiers(AttackTypeBoosterModifier, source.isPlayer(), source, power);
@ -496,7 +507,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
const targetDef = this.getBattleStat(isPhysical ? Stat.DEF : Stat.SPDEF);
const stabMultiplier = source.species.type1 === move.type || (source.species.type2 !== null && source.species.type2 === move.type) ? 1.5 : 1;
const criticalMultiplier = isCritical ? 2 : 1;
damage = Math.ceil(((((2 * source.level / 5 + 2) * power.value * sourceAtk / targetDef) / 50) + 2) * stabMultiplier * typeMultiplier * weatherTypeMultiplier * ((Utils.randInt(15) + 85) / 100)) * criticalMultiplier;
damage = Math.ceil(((((2 * source.level / 5 + 2) * power.value * sourceAtk / targetDef) / 50) + 2) * stabMultiplier * typeMultiplier.value * weatherTypeMultiplier * ((Utils.randInt(15) + 85) / 100)) * criticalMultiplier;
if (isPhysical && source.status && source.status.effect === StatusEffect.BURN)
damage = Math.floor(damage / 2);
move.getAttrs(HitsTagAttr).map(hta => hta as HitsTagAttr).filter(hta => hta.doubleDamage).forEach(hta => {
@ -515,11 +526,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
console.log('damage', damage, move.name, move.power, sourceAtk, targetDef);
if (!result) {
if (typeMultiplier >= 2)
if (typeMultiplier.value >= 2)
result = MoveResult.SUPER_EFFECTIVE;
else if (typeMultiplier >= 1)
else if (typeMultiplier.value >= 1)
result = MoveResult.EFFECTIVE;
else if (typeMultiplier > 0)
else if (typeMultiplier.value > 0)
result = MoveResult.NOT_VERY_EFFECTIVE;
else
result = MoveResult.NO_EFFECT;
@ -544,6 +555,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
this.scene.queueMessage(`It doesn\'t affect ${this.name}!`);
break;
}
}
break;
case MoveCategory.STATUS:
result = MoveResult.STATUS;

View File

@ -94,6 +94,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.pokemonAbilityLabelText = addTextObject(this.scene, 6, 126, 'ABILITY:', TextStyle.SUMMARY, { fontSize: '64px' });
this.pokemonAbilityLabelText.setOrigin(0, 0);
this.pokemonAbilityLabelText.setVisible(false);
this.starterSelectContainer.add(this.pokemonAbilityLabelText);
this.pokemonAbilityText = addTextObject(this.scene, 38, 126, '', TextStyle.SUMMARY, { fontSize: '64px' });
@ -454,11 +455,13 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
if (species && this.speciesStarterDexEntry) {
this.pokemonNumberText.setText(Utils.padInt(species.speciesId, 3));
this.pokemonNameText.setText(species.name.toUpperCase());
this.pokemonAbilityLabelText.setVisible(true);
this.setSpeciesDetails(species, !!this.speciesStarterDexEntry?.shiny, this.speciesStarterDexEntry?.formIndex, !!this.speciesStarterDexEntry?.female, this.speciesStarterDexEntry?.abilityIndex);
} else {
this.pokemonNumberText.setText(Utils.padInt(0, 3));
this.pokemonNameText.setText(species ? '???' : '');
this.pokemonAbilityLabelText.setVisible(false);
this.setSpeciesDetails(species, false, 0, false, 0);
}
@ -563,7 +566,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.canCycleAbility = false;
}
if (species.malePercent !== null) {
if (defaultDexEntry && species.malePercent !== null) {
const gender = !female ? Gender.MALE : Gender.FEMALE;
this.pokemonGenderText.setText(getGenderSymbol(gender));
this.pokemonGenderText.setColor(getGenderColor(gender));
@ -571,12 +574,15 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
} else
this.pokemonGenderText.setText('');
if (defaultDexEntry) {
const ability = this.lastSpecies.getAbility(abilityIndex);
this.pokemonAbilityText.setText(abilities[ability].name.toUpperCase());
const isHidden = ability === this.lastSpecies.abilityHidden;
this.pokemonAbilityText.setColor(getTextColor(!isHidden ? TextStyle.SUMMARY : TextStyle.SUMMARY_GOLD));
this.pokemonAbilityText.setShadowColor(getTextColor(!isHidden ? TextStyle.SUMMARY : TextStyle.SUMMARY_GOLD, true));
} else
this.pokemonAbilityText.setText('');
} else {
this.pokemonGenderText.setText('');
this.pokemonAbilityText.setText('');