Add Fortemons (#9305)

* Add Fortemons

* Fix validation

* Apply suggestions from code review

Co-authored-by: Alexander B. <4866817+MathyFurret@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: Alexander B. <4866817+MathyFurret@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: Alexander B. <4866817+MathyFurret@users.noreply.github.com>

* Do some suggestion things

* Apply suggestions from code review

Co-authored-by: Alexander B. <4866817+MathyFurret@users.noreply.github.com>

* ficks build

Co-authored-by: Alexander B. <4866817+MathyFurret@users.noreply.github.com>
This commit is contained in:
Kris Johnson 2023-01-13 23:46:25 -07:00 committed by GitHub
parent 0921ba3112
commit 65c2c96009
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -895,6 +895,135 @@ export const Formats: FormatList = [
}
},
},
{
name: "[Gen 9] Fortemons",
desc: `Put an attacking move in the item slot to have all of a Pok&eacute;mon's attacks inherit its properties.`,
threads: [
`&bullet; <a href="https://www.smogon.com/forums/threads/3713983/">Fortemons</a>`,
],
mod: 'gen9',
searchShow: false,
ruleset: ['Standard OMs', 'Sleep Clause Mod', 'Min Source Gen = 9'],
banlist: ['Koraidon', 'Miraidon', 'Palafin', 'Covert Cloak', 'Fake Out'],
restricted: ['Dynamic Punch', 'Inferno', 'Mud Slap', 'Nuzzle', 'Power Trip', 'Rapid Spin', 'Stored Power', 'Zap Cannon'],
validateSet(set, teamHas) {
const item = set.item;
const species = this.dex.species.get(set.species);
const move = this.dex.moves.get(item);
if (!move.exists || move.id === 'metronome' || move.category === 'Status') {
return this.validateSet(set, teamHas);
}
set.item = '';
const problems = this.validateSet(set, teamHas) || [];
set.item = item;
if (this.checkCanLearn(move, species, this.allSources(species), set)) {
problems.push(`${species.name} can't learn ${move.name}.`);
}
if ((move.secondaries?.some(secondary => secondary.boosts?.accuracy && secondary.boosts.accuracy < 0) ||
move.multihit || move.id === 'beatup' || move.flags['charge'] || move.priority > 0 || move.damageCallback) &&
!this.ruleTable.has(`+move:${move.id}`)) {
problems.push(`The move ${move.name} can't be used as an item.`);
}
return problems.length ? problems : null;
},
onBegin() {
for (const pokemon of this.getAllPokemon()) {
const move = this.dex.getActiveMove(pokemon.set.item);
if (move.exists && move.category !== 'Status') {
pokemon.m.forte = move;
pokemon.item = 'mail' as ID;
}
}
},
onModifyMovePriority: 1,
onModifyMove(move, pokemon, target) {
const forte: ActiveMove = pokemon.m.forte;
if (move.category !== 'Status' && forte) {
move.flags = {...move.flags, ...forte.flags};
if (forte.self) {
if (forte.self.onHit && move.self?.onHit) {
for (const i in forte.self) {
if (i.startsWith('onHit')) continue;
(move.self as any)[i] = (forte.self as any)[i];
}
} else {
move.self = {...(move.self || {}), ...forte.self};
}
}
if (forte.selfBoost?.boosts) {
if (!move.selfBoost?.boosts) move.selfBoost = {boosts: {}};
let boostid: BoostID;
for (boostid in forte.selfBoost.boosts) {
if (!move.selfBoost.boosts![boostid]) move.selfBoost.boosts![boostid] = 0;
move.selfBoost.boosts![boostid]! += forte.selfBoost.boosts[boostid]!;
}
}
if (forte.secondaries) {
move.secondaries = [...(move.secondaries || []), ...forte.secondaries];
}
move.critRatio = (move.critRatio || 1) + (forte.critRatio || 1) - 1;
const VALID_PROPERTIES = [
'alwaysHit', 'basePowerCallback', 'breaksProtect', 'drain', 'forceSTAB', 'forceSwitch', 'hasCrashDamage', 'hasSheerForce',
'ignoreAbility', 'ignoreAccuracy', 'ignoreDefensive', 'ignoreEvasion', 'ignoreImmunity', 'mindBlownRecoil', 'noDamageVariance',
'ohko', 'overrideDefensivePokemon', 'overrideDefensiveStat', 'overrideOffensivePokemon', 'overrideOffensiveStat', 'pseudoWeather',
'recoil', 'selfdestruct', 'selfSwitch', 'sleepUsable', 'smartTarget', 'stealsBoosts', 'thawsTarget', 'volatileStatus', 'willCrit',
] as const;
for (const property of VALID_PROPERTIES) {
if (forte[property]) {
move[property] = forte[property] as any;
}
}
}
},
onModifyPriority(priority, source, target, move) {
if (move.category !== 'Status' && source?.m.forte) {
if (source.hasAbility('Triage') && source.m.forte.flags['heal']) {
return priority + (move.flags['heal'] ? 0 : 3);
}
return priority + source.m.forte.priority;
}
},
onHitPriority: 1,
onHit(target, source, move) {
const forte = source.m.forte;
if (move?.category !== 'Status' && forte) {
if (forte.onHit) this.singleEvent('Hit', forte, {}, target, source, move);
if (forte.self?.onHit) this.singleEvent('Hit', forte.self, {}, source, source, move);
if (forte.onAfterHit) this.singleEvent('AfterHit', forte, {}, target, source, move);
}
},
onAfterSubDamage(damage, target, source, move) {
const forte = source.m.forte;
if (move?.category !== 'Status' && forte?.onAfterSubDamage) {
this.singleEvent('AfterSubDamage', forte, null, target, source, move);
}
},
onModifySecondaries(secondaries, target, source, move) {
if (secondaries.some(s => !!s.self)) move.selfDropped = false;
},
onAfterMoveSecondaryPriority: 1,
onAfterMoveSecondarySelf(source, target, move) {
const forte = source.m.forte;
if (move?.category !== 'Status' && forte?.onAfterMoveSecondarySelf) {
this.singleEvent('AfterMoveSecondarySelf', forte, null, source, target, move);
}
},
onBasePowerPriority: 1,
onBasePower(basePower, source, target, move) {
const forte = source.m.forte;
if (move.category !== 'Status' && forte?.onBasePower) {
this.singleEvent('BasePower', forte, null, source, target, move, basePower);
}
},
pokemon: {
getItem() {
const move = this.battle.dex.moves.get(this.m.forte);
if (!move.exists) return Object.getPrototypeOf(this).getItem.call(this);
return {...this.battle.dex.items.get('mail'), ignoreKlutz: true, onTakeItem: false};
},
},
},
{
name: "[Gen 9] Full Potential",
desc: `Pok&eacute;mon's moves hit off of their highest stat.`,