mirror of
https://gitlab.com/Deukhoofd/BattleSim.git
synced 2025-10-27 18:00:03 +00:00
Lots of stuff
This commit is contained in:
13
shared/bias_rng.coffee
Normal file
13
shared/bias_rng.coffee
Normal file
@@ -0,0 +1,13 @@
|
||||
@makeBiasedRng = (battle) ->
|
||||
biasedRNGFuncs = {}
|
||||
for funcName in ['next', 'randInt']
|
||||
do (funcName) =>
|
||||
oldFunc = battle.rng[funcName].bind(battle.rng)
|
||||
battle.rng[funcName] = (args...) =>
|
||||
id = args[args.length - 1]
|
||||
func = biasedRNGFuncs[funcName]
|
||||
return (if id of func then func[id] else oldFunc(args...))
|
||||
|
||||
battle.rng.bias = (funcName, id, returns) ->
|
||||
biasedRNGFuncs[funcName] ||= {}
|
||||
biasedRNGFuncs[funcName][id] = returns
|
||||
187
shared/canned_text.coffee
Normal file
187
shared/canned_text.coffee
Normal file
@@ -0,0 +1,187 @@
|
||||
CannedText =
|
||||
bw:
|
||||
en:
|
||||
MOVE_MISS: "$p avoided the attack!"
|
||||
MOVE_FAIL: "But it failed!"
|
||||
SUPER_EFFECTIVE: "It's super effective!"
|
||||
NOT_VERY_EFFECTIVE: "It's not very effective..."
|
||||
CRITICAL_HIT: "A critical hit!"
|
||||
GOT_HIT: "$p took $1% damage!"
|
||||
DRAIN: "$p had its energy drained!"
|
||||
ABSORB: "$p absorbed some HP!"
|
||||
NO_TARGET: "But there was no target..."
|
||||
RECOIL: "$p was hit by recoil!"
|
||||
IMMUNITY: "But it doesn't affect $p..."
|
||||
FLINCH: "$p flinched!"
|
||||
IS_CONFUSED: "$p is confused!"
|
||||
CONFUSION_START: "$p became confused!"
|
||||
CONFUSION_END: "$p snapped out of confusion!"
|
||||
CONFUSION_HURT_SELF: "$p hurt itself in confusion!"
|
||||
FATIGUE: "$p became confused due to fatigue!"
|
||||
NO_MOVES_LEFT: "$p has no moves left!"
|
||||
NO_PP_LEFT: "But there was no PP left for the move!"
|
||||
SUN_START: "The sunlight turned harsh!"
|
||||
RAIN_START: "It started to rain!"
|
||||
SAND_START: "A sandstorm kicked up!"
|
||||
HAIL_START: "It started to hail!"
|
||||
SUN_END: "The sunlight faded."
|
||||
RAIN_END: "The rain stopped."
|
||||
SAND_END: "The sandstorm subsided."
|
||||
HAIL_END: "The hail stopped."
|
||||
SAND_CONTINUE: "The sandstorm rages."
|
||||
HAIL_CONTINUE: "The hail crashes down."
|
||||
SAND_HURT: "$p is buffeted by the sandstorm!"
|
||||
HAIL_HURT: "$p is buffeted by the hail!"
|
||||
DISABLE_START: "$p's $m was disabled!"
|
||||
DISABLE_CONTINUE: "$p's $m is disabled!"
|
||||
DISABLE_END: "$p is no longer disabled!"
|
||||
YAWN_BEGIN: "$p grew drowsy!"
|
||||
TAUNT_START: "$p fell for the taunt!"
|
||||
TAUNT_PREVENT: "$p can't use $m after the taunt!"
|
||||
TAUNT_END: "$p's taunt wore off!"
|
||||
WISH_END: "$1's wish came true!"
|
||||
PERISH_SONG_START: "All Pokemon hearing the song will faint in three turns!"
|
||||
PERISH_SONG_CONTINUE: "$p's perish count fell to $1!"
|
||||
TAILWIND_END: "The tailwind petered out!"
|
||||
ENCORE_END: "$p's Encore ended!"
|
||||
TORMENT_START: "$p was subjected to Torment!"
|
||||
SPIKES_START: "Spikes were scattered all around $ts's feet!"
|
||||
SPIKES_HURT: "$p is hurt by the spikes!"
|
||||
SPIKES_END: "The spikes disappeared from around $ts's feet!"
|
||||
STEALTH_ROCK_START: "Pointed stones float in the air around $ts!"
|
||||
STEALTH_ROCK_HURT: "Pointed stones dug into $p!"
|
||||
STEALTH_ROCK_END: "The pointed stones disappeared from around $ts!"
|
||||
TOXIC_SPIKES_START: "Poison spikes were scattered all around $ts's feet!"
|
||||
TOXIC_SPIKES_END: "The poison spikes disappeared from around $ts's feet!"
|
||||
TRAP_HURT: "$p is hurt by $m!"
|
||||
LEECH_SEED_START: "$p was seeded!"
|
||||
LEECH_SEED_HURT: "$p's health is sapped by Leech Seed!"
|
||||
PROTECT_CONTINUE: "$p protected itself!"
|
||||
DESTINY_BOND_START: "$p is trying to take its foe down with it!"
|
||||
DESTINY_BOND_CONTINUE: "$p took its attacker down with it!"
|
||||
SUBSTITUTE_START: "$p put in a substitute!"
|
||||
SUBSTITUTE_EXISTS: "$p already has a substitute!"
|
||||
SUBSTITUTE_WEAK: "It was too weak to make a substitute!"
|
||||
SUBSTITUTE_END: "$p's substitute faded!"
|
||||
SUBSTITUTE_HURT: "The substitute took damage for $p!"
|
||||
BOUNCE_MOVE: "$p bounced the $m back!"
|
||||
TRICK_ROOM_START: "$p twisted the dimensions!"
|
||||
TRICK_ROOM_END: "The twisted dimensions returned to normal!"
|
||||
PARALYZE_START: '$p was paralyzed!'
|
||||
FREEZE_START: '$p was frozen!'
|
||||
POISON_START: '$p was poisoned!'
|
||||
TOXIC_START: '$p was badly poisoned!'
|
||||
SLEEP_START: '$p fell asleep!'
|
||||
BURN_START: '$p was burned!'
|
||||
PARALYZE_CONTINUE: '$p is fully paralyzed!'
|
||||
FREEZE_CONTINUE: "$p is frozen solid!"
|
||||
POISON_CONTINUE: "$p was hurt by poison!"
|
||||
SLEEP_CONTINUE: "$p is fast asleep."
|
||||
BURN_CONTINUE: "$p was hurt by its burn!"
|
||||
RECOVER_HP: "$p's HP was restored."
|
||||
TRICK_START: "$p switched items with its target!"
|
||||
TRICK_END: "$p obtained one $i!"
|
||||
THIEF_START: "$p stole $p's $i!"
|
||||
RESET_STATS: "$p's stat changes were removed!"
|
||||
RESET_ALL_STATS: "All stat changes were eliminated!"
|
||||
JUMP_KICK_MISS: "$p kept going and crashed!"
|
||||
FREE_FROM: "$p was freed from $1!"
|
||||
TRANSFORM: '$p transformed!'
|
||||
TRANSFORM_INTO: '$p transformed into $p!'
|
||||
TRANSFORM_TYPE: "$p transformed into the $y type!"
|
||||
ACQUIRE_ABILITY: "$p acquired $a!"
|
||||
REFLECT_START: "Reflect raised $ts's defense!"
|
||||
LIGHT_SCREEN_START: "Light Screen raised $ts's special defense!"
|
||||
REFLECT_END: "$ts's Reflect wore off!"
|
||||
LIGHT_SCREEN_END: "$ts's Light Screen wore off!"
|
||||
STICKY_WEB_START: "A sticky web has been laid out beneath $ts's feet!"
|
||||
STICKY_WEB_CONTINUE: "$p was caught in a sticky web!"
|
||||
STICKY_WEB_END: "The sticky web has disappeared from beneath $ts's feet!"
|
||||
RATING_UPDATE: "$t's rating: $1 -> $2"
|
||||
KNOCK_OFF: "$p knocked off $p's $i!"
|
||||
PAIN_SPLIT: "The battlers shared their pain!"
|
||||
PAY_DAY: "Coins were scattered everywhere!"
|
||||
PSYCH_UP: "$p copied $p's stat changes!"
|
||||
MENTAL_HERB: "$p used its Mental Herb to come back to its senses!"
|
||||
WHITE_HERB: "$p restored its status using its White Herb!"
|
||||
RED_CARD: "$p held up its Red Card against $p!"
|
||||
EJECT_BUTTON: "$p is switched out with the Eject Button!"
|
||||
HANG_ON: "$p hung on using its $i!"
|
||||
MOVE_FIRST: "$p's $i let it move first!"
|
||||
SAFEGUARD_START: "$t's team became cloaked in a mystical veil!"
|
||||
SAFEGUARD_END: "$t's Safeguard wore off!"
|
||||
ITEM_RESTORE: "$p restored a little HP using its $i!"
|
||||
ITEM_WEAKEN: "The $i weakened the damage to $p!"
|
||||
POKEMON_HURT_BY_ITEM: "$p is hurt by $p's $i!"
|
||||
ITEM_SELF_HURT: "$p is hurt by its $i!"
|
||||
POKEMON_HURT: "$p is hurt!"
|
||||
BERRY_RESTORE: "$p restored its health using its $i!"
|
||||
BERRY_RAISE_STAT: "The $i raised $p's $1!"
|
||||
GEM_BOOST: "The $i strengthened $m's power!"
|
||||
ENDURE: "$p endured the hit!"
|
||||
ANCHOR: "$p anchors itself!"
|
||||
AVOID_ALLIES: "$p avoids attacks by its ally Pokemon!"
|
||||
TRACE: "It traced the foe's $a!"
|
||||
TRUANT: "$p is loafing around!"
|
||||
WEATHER_DISABLED: "The effects of weather disappeared."
|
||||
MOLD_BREAKER: "$p breaks the mold!"
|
||||
TERAVOLT: "$p is radiating a bursting aura!"
|
||||
TURBOBLAZE: "$p is radiating a blazing aura!"
|
||||
ANTICIPATION: "$p shuddered!"
|
||||
BAD_DREAMS: "$p is tormented!"
|
||||
COLOR_CHANGE: "$p's Color Change made it the $1 type!"
|
||||
FLASH_FIRE: "The power of $p's Fire-type moves rose!"
|
||||
FOREWARN: "It was alerted to $p's $m!"
|
||||
FRISK: "$p frisked its target and found one $i!"
|
||||
HARVEST: "$p harvested one $i!"
|
||||
PRESSURE: "$p is exerting its pressure!"
|
||||
MUMMY: "$p's ability became Mummy!"
|
||||
PICKPOCKET: "$p stole $p's $i!"
|
||||
SLOW_START_START: "$p can't get it going!"
|
||||
SLOW_START_END: "$p finally got its act together!"
|
||||
WITHDREW: "$t withdrew $p!"
|
||||
SENT_OUT: "$t sent out $p!"
|
||||
SWAP_ABILITY: "$p swapped Abilities with its target!"
|
||||
TELEKINESIS_START: "$p was hurled into the air!"
|
||||
TELEKINESIS_END: "$p was freed from the telekinesis!"
|
||||
HEAL_BLOCK_START: "$p was prevented from healing!"
|
||||
HEAL_BLOCK_END: "$p's Heal Block wore off!"
|
||||
HEAL_BLOCK_PREVENT: "$p can't use $m because of Heal Block!"
|
||||
HEAL_BLOCK_TRY_HEAL: "$p was prevented from healing due to Heal Block!"
|
||||
HEAL_BLOCK_FAIL: "But it failed to affect $p!"
|
||||
FOUND_ITEM: "$p found one $i!"
|
||||
MOON_START: "$p's Noctem darkened the sky!"
|
||||
MOON_END: "The sky brightened again."
|
||||
MOON_CONTINUE: "The sky is dark."
|
||||
LIVEWIRE_START: "A wire was set at the feet of the foe"
|
||||
LIVEWIRE_END: "$p absorbed the Livewire!"
|
||||
LIVEWIRE_HURT: "$p was shocked by the Livewire!"
|
||||
LIVEWIRE_MISS: "$p avoided the Livewire!"
|
||||
FIRE_ROCK_START: "Molten rocks float in the air around $ts!"
|
||||
FIRE_ROCK_HURT: "$p is hurt by molten rocks!"
|
||||
FIRE_ROCK_END: "The molten rocks disappeared from around $ts!"
|
||||
ILLUSION_BROKE: "The foes $p broke it's illusion!"
|
||||
|
||||
cannedMap = {}
|
||||
cannedMapReverse = {}
|
||||
allTexts = []
|
||||
counter = 0
|
||||
|
||||
cannedTextNames = []
|
||||
for generationName, generation of CannedText
|
||||
for language, cannedTexts of generation
|
||||
for cannedTextName in Object.keys(cannedTexts)
|
||||
if cannedTextName not in cannedTextNames
|
||||
cannedTextNames.push(cannedTextName)
|
||||
|
||||
# Sort canned text, so that the integers are consistent everywhere.
|
||||
cannedTextNames.sort()
|
||||
|
||||
for cannedTextName, i in cannedTextNames
|
||||
counter = (i + 1)
|
||||
cannedMap[cannedTextName] = counter
|
||||
cannedMapReverse[counter] = cannedTextName
|
||||
|
||||
this.CannedText = cannedMap
|
||||
this.CannedMap = CannedText
|
||||
this.CannedMapReverse = cannedMapReverse
|
||||
82
shared/conditions.coffee
Normal file
82
shared/conditions.coffee
Normal file
@@ -0,0 +1,82 @@
|
||||
@Conditions =
|
||||
TEAM_PREVIEW : 1
|
||||
RATED_BATTLE : 2
|
||||
PBV_1000 : 3
|
||||
TIMED_BATTLE : 4
|
||||
SLEEP_CLAUSE : 5
|
||||
SPECIES_CLAUSE : 6
|
||||
EVASION_CLAUSE : 7
|
||||
OHKO_CLAUSE : 8
|
||||
UNRELEASED_BAN : 9
|
||||
PRANKSTER_SWAGGER_CLAUSE : 10
|
||||
PBV_500 : 11
|
||||
VISIBLE_TEAM : 12
|
||||
|
||||
@SelectableConditions = [
|
||||
@Conditions.VISIBLE_TEAM
|
||||
@Conditions.TIMED_BATTLE
|
||||
@Conditions.SLEEP_CLAUSE
|
||||
@Conditions.EVASION_CLAUSE
|
||||
@Conditions.SPECIES_CLAUSE
|
||||
@Conditions.PRANKSTER_SWAGGER_CLAUSE
|
||||
@Conditions.OHKO_CLAUSE
|
||||
@Conditions.UNRELEASED_BAN
|
||||
]
|
||||
|
||||
@HumanizedConditions =
|
||||
en:
|
||||
VISIBLE_TEAM : "Visible Teams"
|
||||
TEAM_PREVIEW : "Team Preview"
|
||||
SLEEP_CLAUSE : "Sleep Clause"
|
||||
RATED_BATTLE : "Rated Battle"
|
||||
TIMED_BATTLE : "Timed Battle"
|
||||
SPECIES_CLAUSE : "Species Clause"
|
||||
EVASION_CLAUSE : "Evasion Clause"
|
||||
OHKO_CLAUSE : "One-Hit KO Clause"
|
||||
UNRELEASED_BAN : "Unreleased Ban"
|
||||
PRANKSTER_SWAGGER_CLAUSE : "Prankster + Swagger Clause"
|
||||
|
||||
@Formats =
|
||||
insur1000:
|
||||
humanName: 'Insurgence 1000'
|
||||
generation: 'in'
|
||||
conditions: [ @Conditions.PBV_1000, @Conditions.TEAM_PREVIEW ]
|
||||
xy1000:
|
||||
humanName: '1,000 PBV XY'
|
||||
generation: 'xy'
|
||||
conditions: [ @Conditions.PBV_1000, @Conditions.TEAM_PREVIEW ]
|
||||
xy500:
|
||||
humanName: '500 PBV XY'
|
||||
generation: 'xy'
|
||||
conditions: [ @Conditions.PBV_500, @Conditions.TEAM_PREVIEW ]
|
||||
|
||||
@DEFAULT_FORMAT = 'insur1000'
|
||||
|
||||
@tiers =
|
||||
PA:
|
||||
humanName: "Pathetic"
|
||||
tierRank: 0
|
||||
LC:
|
||||
humanName: "Little Cup"
|
||||
tierRank: 1
|
||||
PU:
|
||||
humanName: "Poorly Used"
|
||||
tierRank: 2
|
||||
NU:
|
||||
humanName: "Never Used"
|
||||
tierRank: 3
|
||||
RU:
|
||||
humanName: "Rarely Used"
|
||||
tierRank: 4
|
||||
UU:
|
||||
humanName: "Under Used"
|
||||
tierRank: 5
|
||||
OU:
|
||||
humanName: "Over Used"
|
||||
tierRank: 6
|
||||
Uber:
|
||||
humanName: "Ubers"
|
||||
tierRank: 7
|
||||
AG:
|
||||
humanName: "Anything Goes"
|
||||
tierRank: 8
|
||||
13
shared/errors.coffee
Normal file
13
shared/errors.coffee
Normal file
@@ -0,0 +1,13 @@
|
||||
self = (module?.exports || window.PokeBattle.errors = {})
|
||||
|
||||
errors = """
|
||||
FIND_BATTLE
|
||||
BATTLE_DNE
|
||||
INVALID_SESSION
|
||||
BANNED
|
||||
COMMAND_ERROR
|
||||
PRIVATE_MESSAGE
|
||||
INVALID_ALT_NAME
|
||||
"""
|
||||
for error, i in errors.trim().split(/\s+/)
|
||||
self[error] = (i + 1) # Let's not start at 0, just in case.
|
||||
8025
shared/event_pokemon.json
Normal file
8025
shared/event_pokemon.json
Normal file
File diff suppressed because it is too large
Load Diff
84
shared/hidden_power.coffee
Normal file
84
shared/hidden_power.coffee
Normal file
@@ -0,0 +1,84 @@
|
||||
self = (if module? then module.exports else window.HiddenPower ?= {})
|
||||
|
||||
self.BW ?= {}
|
||||
|
||||
self.BW.types = [
|
||||
'Fighting', 'Flying', 'Poison', 'Ground', 'Rock', 'Bug', 'Ghost',
|
||||
'Steel', 'Fire', 'Water', 'Grass', 'Electric', 'Psychic', 'Ice',
|
||||
'Dragon', 'Dark'
|
||||
]
|
||||
|
||||
self.BW.basePower = (ivs) ->
|
||||
base = 0
|
||||
base += 1 if ivs['hp'] % 4 > 1
|
||||
base += 2 if ivs['attack'] % 4 > 1
|
||||
base += 4 if ivs['defense'] % 4 > 1
|
||||
base += 8 if ivs['speed'] % 4 > 1
|
||||
base += 16 if ivs['specialAttack'] % 4 > 1
|
||||
base += 32 if ivs['specialDefense'] % 4 > 1
|
||||
Math.floor(base * (40 / 63) + 30)
|
||||
|
||||
self.BW.type = (ivs) ->
|
||||
value = 0
|
||||
value += 1 if ivs['hp'] % 2 == 1
|
||||
value += 2 if ivs['attack'] % 2 == 1
|
||||
value += 4 if ivs['defense'] % 2 == 1
|
||||
value += 8 if ivs['speed'] % 2 == 1
|
||||
value += 16 if ivs['specialAttack'] % 2 == 1
|
||||
value += 32 if ivs['specialDefense'] % 2 == 1
|
||||
self.BW.types[Math.floor(value * 15 / 63)]
|
||||
|
||||
self.BW.ivs =
|
||||
bug:
|
||||
attack: 30
|
||||
defense: 30
|
||||
specialDefense: 30
|
||||
dark: {}
|
||||
dragon:
|
||||
attack: 30
|
||||
electric:
|
||||
specialAttack: 30
|
||||
fighting:
|
||||
defense: 30
|
||||
specialAttack: 30
|
||||
specialDefense: 30
|
||||
speed: 30
|
||||
fire:
|
||||
attack: 30
|
||||
specialAttack: 30
|
||||
speed: 30
|
||||
flying:
|
||||
hp: 30
|
||||
attack: 30
|
||||
defense: 30
|
||||
specialAttack: 30
|
||||
specialDefense: 30
|
||||
ghost:
|
||||
defense: 30
|
||||
specialDefense: 30
|
||||
grass:
|
||||
attack: 30
|
||||
specialAttack: 30
|
||||
ground:
|
||||
specialAttack: 30
|
||||
specialDefense: 30
|
||||
ice:
|
||||
attack: 30
|
||||
defense: 30
|
||||
poison:
|
||||
defense: 30
|
||||
specialAttack: 30
|
||||
specialDefense: 30
|
||||
psychic:
|
||||
attack: 30
|
||||
speed: 30
|
||||
rock:
|
||||
defense: 30
|
||||
specialDefense: 30
|
||||
speed: 30
|
||||
steel:
|
||||
specialDefense: 30
|
||||
water:
|
||||
attack: 30
|
||||
defense: 30
|
||||
specialAttack: 30
|
||||
11
shared/ladders.coffee
Normal file
11
shared/ladders.coffee
Normal file
@@ -0,0 +1,11 @@
|
||||
@ALL_GENERATIONS = [ 'rb', 'gs', 'rs', 'dp', 'bw', 'xy', 'in' ]
|
||||
@SUPPORTED_GENERATIONS = ['xy', 'in' ]
|
||||
@DEFAULT_GENERATION = 'in'
|
||||
|
||||
@INT_TO_GENERATION = {}
|
||||
for gen, i in @ALL_GENERATIONS
|
||||
@INT_TO_GENERATION[i + 1] = gen
|
||||
|
||||
@GENERATION_TO_INT = {}
|
||||
for gen, i in @ALL_GENERATIONS
|
||||
@GENERATION_TO_INT[gen] = (i + 1)
|
||||
227
shared/learnsets.coffee
Normal file
227
shared/learnsets.coffee
Normal file
@@ -0,0 +1,227 @@
|
||||
self = (module?.exports || window)
|
||||
|
||||
if module?.exports
|
||||
EventPokemon = require('./event_pokemon')
|
||||
{INT_TO_GENERATION} = require('./ladders')
|
||||
{_} = require('underscore')
|
||||
else
|
||||
EventPokemon = window.EventPokemon ? {}
|
||||
INT_TO_GENERATION = window.INT_TO_GENERATION
|
||||
_ = window._
|
||||
|
||||
unportableGenerations = [ 1, 3 ]
|
||||
unportableGenerations.sort((a, b) -> b - a) # numeric, descending
|
||||
|
||||
switchableFormes = [
|
||||
"Deoxys"
|
||||
"Rotom"
|
||||
"Shaymin"
|
||||
]
|
||||
|
||||
unsketchableMoves = [
|
||||
"Chatter"
|
||||
"Hyperspace Hole"
|
||||
"Light of Ruin"
|
||||
"Steam Eruption"
|
||||
"Struggle"
|
||||
"Thousand Arrows"
|
||||
"Thousand Waves"
|
||||
]
|
||||
|
||||
mustLearnMove =
|
||||
"Mamoswine" : "AncientPower"
|
||||
"Yanmega" : "AncientPower"
|
||||
"Tangrowth" : "AncientPower"
|
||||
"Mr. Mime" : "Mimic"
|
||||
"Sudowoodo" : "Mimic" # Note: Only 6 egg moves exist; 4 can be learned.
|
||||
"Ambipom" : "Double Hit"
|
||||
"Lickilicky" : "Rollout"
|
||||
|
||||
getMinimumGeneration = (generation) ->
|
||||
for unportableGen in unportableGenerations
|
||||
if unportableGen <= generation
|
||||
return unportableGen
|
||||
minGeneration = Math.min(unportableGenerations...)
|
||||
throw new Error("Gen. '#{generation}' must be greater than #{minGeneration}.")
|
||||
|
||||
getGenerationFromInt = (generationInteger) ->
|
||||
INT_TO_GENERATION[generationInteger].toUpperCase()
|
||||
|
||||
# A helper method to loop through the learnsets for this pokemon and all
|
||||
# prevolutions, and then runs an iterator function (that you give) on those
|
||||
# learnsets. The iterator function takes one parameter, `learnset`, the learnset
|
||||
# for a given generation for the Pokemon's current forme.
|
||||
#
|
||||
# All generations that can be used are taken into consideration. If the Pokemon
|
||||
# has a hidden ability, but the generation doesn't support it, the iterator
|
||||
# skips over that gneration.
|
||||
loopLearnsets = (Generations, pokemon, forGeneration, iterator) ->
|
||||
minimumGeneration = getMinimumGeneration(forGeneration)
|
||||
{species, forme, ability} = pokemon
|
||||
formeName = forme || "default"
|
||||
# Find pre-evolutions and formes
|
||||
thePokemon = []
|
||||
theFormes = [ formeName ]
|
||||
{SpeciesData, FormeData} = Generations[getGenerationFromInt(forGeneration)]
|
||||
finalForme = FormeData[species][formeName]
|
||||
while species
|
||||
thePokemon.push(species)
|
||||
if species in switchableFormes && species not in theFormes
|
||||
theFormes.push((forme for forme of FormeData[species])...)
|
||||
species = SpeciesData[species].evolvedFrom
|
||||
|
||||
# The Pokemon may not have a default ability (due to tests, etc)
|
||||
ability ?= finalForme.abilities[0]
|
||||
hasHiddenAbility = (ability == finalForme.hiddenAbility &&
|
||||
ability not in finalForme.abilities)
|
||||
|
||||
# Loop through pre-evolutions and formes
|
||||
for species in thePokemon
|
||||
for formeName in theFormes
|
||||
# Loop through all available generations
|
||||
for generation in [minimumGeneration..forGeneration]
|
||||
{FormeData} = Generations[getGenerationFromInt(generation)]
|
||||
# Skip if this pokemon has no data.
|
||||
continue if !FormeData[species]?
|
||||
# Since we check pre-evos, the pre-evo may not have the forme that its
|
||||
# parent has. We check if no forme exists; if so, we revert to default.
|
||||
formeName = "default" if formeName not of FormeData[species]
|
||||
# The current forme may not have a learnset (Zen mode, megas), so we
|
||||
# do another check to see if it has a learnset. If not, use default.
|
||||
forme = FormeData[species][formeName]
|
||||
formeName = "default" if !forme.learnset
|
||||
learnset = forme.learnset
|
||||
# Skip if this Pokemon has no learnset for this generation.
|
||||
continue if !learnset
|
||||
|
||||
# Skip if this Pokemon's ability is hidden and this generation has no
|
||||
# hidden abilities for this forme.
|
||||
continue if hasHiddenAbility && !forme.hiddenAbility?
|
||||
return true if iterator(learnset, species, formeName, generation) == true
|
||||
return false
|
||||
|
||||
# Returns an array of moves that this Pokemon can learn for a given generation.
|
||||
self.learnableMoves = (Generations, pokemon, forGeneration) ->
|
||||
learnable = []
|
||||
loopLearnsets Generations, pokemon, forGeneration, (learnset, pokemonSpecies, formeName) ->
|
||||
# Push event moves
|
||||
events = EventPokemon[pokemonSpecies] || []
|
||||
events = events.filter((event) -> event.forme == formeName)
|
||||
for event in events
|
||||
learnable.push(event.moves)
|
||||
|
||||
# Push learnset moves
|
||||
for method, moves of learnset
|
||||
if method in [ 'level-up', 'tutor', 'machine', 'egg' ] ||
|
||||
((pokemon.forme || "default") == formeName) # e.g. Hydro Pump Rotom-w
|
||||
learnable.push((moveName for moveName of moves))
|
||||
|
||||
# If the learnset includes Sketch, then we include every move.
|
||||
if learnset["level-up"]?["Sketch"]
|
||||
for moveName of Generations[getGenerationFromInt(forGeneration)].MoveData
|
||||
if moveName not in unsketchableMoves
|
||||
learnable.push(moveName)
|
||||
|
||||
_.chain(learnable).flatten().sort().unique().value()
|
||||
|
||||
# Checks the moveset of a given Pokemon for a given generation, with the given
|
||||
# species and forme data for all Pokemon.
|
||||
#
|
||||
# Returns true if the moveset is valid, false otherwise.
|
||||
self.checkMoveset = (Generations, pokemon, generation, moves) ->
|
||||
looper = loopLearnsets.bind(null, Generations, pokemon, generation)
|
||||
pokemonSpecies = pokemon.species
|
||||
pokemonForme = pokemon.forme || "default"
|
||||
pokemonLevel = (pokemon.level || 100)
|
||||
{FormeData} = Generations[getGenerationFromInt(generation)]
|
||||
forme = FormeData[pokemonSpecies][pokemonForme]
|
||||
|
||||
# In gen 4, pokemon must know *all* moves inside the `form-change` learnset.
|
||||
if generation == 4
|
||||
rsForme = Generations.DP.FormeData[pokemonSpecies]?[pokemonForme] || {}
|
||||
learnset = rsForme.learnset?['form-change'] || {}
|
||||
for move, level of learnset
|
||||
return false if move not in moves || pokemonLevel < level
|
||||
|
||||
# Get a list of all moves that the Pokemon can't learn
|
||||
# through level-up, tutoring, machines, or Sketch.
|
||||
leftoverMoves = (m for m in moves when !checkMove(looper, pokemon, m))
|
||||
|
||||
# Continuing the `forme-change` learnset group.
|
||||
# Get rid of leftover moves if this pokemon can learn it in this generation.
|
||||
learnset = forme.learnset?['form-change'] || {}
|
||||
lsetLeftovers = leftoverMoves.filter((move) -> pokemonLevel >= learnset[move])
|
||||
return true if lsetLeftovers.length == leftoverMoves.length
|
||||
|
||||
# Check against event Pokemon
|
||||
# TODO: Event Pokemon require more stringent checks, e.g. gender/ability etc.
|
||||
checksOut = looper (learnset, pokemonSpecies, formeName) ->
|
||||
events = EventPokemon[pokemonSpecies] || []
|
||||
events = events.filter((event) -> event.forme == formeName)
|
||||
for event in events
|
||||
lsetLeftovers = leftoverMoves.filter (move) ->
|
||||
move in event.moves && pokemonLevel >= event.level
|
||||
return true if lsetLeftovers.length == leftoverMoves.length
|
||||
return true if checksOut
|
||||
|
||||
# These learnset groups are non-standard but can be used. If a non-standard
|
||||
# group completely overlaps the leftover moves, the moveset is valid.
|
||||
nonstandardGroups = [ "light-ball-egg", "stadium-surfing-pikachu" ]
|
||||
checksOut = looper (learnset) ->
|
||||
for group in nonstandardGroups
|
||||
continue if !learnset[group]
|
||||
total = (m for m in leftoverMoves when m of learnset[group]).length
|
||||
return true if total == leftoverMoves.length
|
||||
return true if checksOut
|
||||
|
||||
# If the remaining moves are all dream world moves, it's a valid moveset.
|
||||
checksOut = looper (learnset) ->
|
||||
return if !learnset['dreamWorld']
|
||||
dreamWorldMoves = []
|
||||
for moveName of learnset['dreamWorld']
|
||||
continue if moveName in dreamWorldMoves || moveName not in leftoverMoves
|
||||
dreamWorldMoves.push(moveName)
|
||||
return true if leftoverMoves.length == dreamWorldMoves.length
|
||||
return true if checksOut
|
||||
|
||||
# If the remaining moves are all egg moves, the moveset is valid.
|
||||
# TODO: Check chain-breeding for gens 5 and under.
|
||||
eggMoves = []
|
||||
looper (learnset) ->
|
||||
return if !learnset['egg']
|
||||
for moveName of learnset['egg']
|
||||
continue if moveName in eggMoves || moveName not in leftoverMoves
|
||||
eggMoves.push(moveName)
|
||||
|
||||
# If the Pokemon has to know a certain move to evolve, check the egg moves
|
||||
# since you cannot have a moveset made completely of pure egg moves.
|
||||
# A magic constant of 4 is used to imitate the game's maximum of 4 moves.
|
||||
return false if eggMoves.length == 4 && mustLearnMove[pokemon.species]
|
||||
return true if eggMoves.length == leftoverMoves.length
|
||||
|
||||
# This Pokemon cannot learn all these moves. Sorry.
|
||||
return false
|
||||
|
||||
# Checks a single move to see if the Pokemon can learn it through level-up,
|
||||
# tutors, machines, Sketch, or pre-evolutions.
|
||||
checkMove = (looper, pokemon, move) ->
|
||||
{level} = pokemon
|
||||
level ||= 100
|
||||
|
||||
checksOut = looper (learnset) ->
|
||||
# Check level-up, TM/HM, and tutors.
|
||||
return true if learnset["level-up"]?[move] <= level ||
|
||||
learnset["machine"]?[move] <= level ||
|
||||
learnset["tutor"]?[move] <= level
|
||||
|
||||
# If the Pokemon can learn Sketch, then by golly, it can learn anything!
|
||||
# ... Except Chatter and Struggle. NOTE: Bogus moves are considered valid,
|
||||
# so you must take care of them at a higher level.
|
||||
# Unreleased event moves are also unsketchable until release.
|
||||
return true if learnset["level-up"]?["Sketch"] <= level &&
|
||||
move not in unsketchableMoves
|
||||
return true if checksOut
|
||||
|
||||
# TODO: Skip unavailable Pokemon (due to being a generation later).
|
||||
# TODO: level-up moves can be bred.
|
||||
return false
|
||||
34
shared/pokebattle_values.coffee
Normal file
34
shared/pokebattle_values.coffee
Normal file
@@ -0,0 +1,34 @@
|
||||
self = (if window? then window.PokeBattle.PBV ?= {} else this)
|
||||
|
||||
BATON_PASS_PBV = 15
|
||||
|
||||
self.determinePBV = (genData, pokemonArray) ->
|
||||
if pokemonArray not instanceof Array then pokemonArray = [ pokemonArray ]
|
||||
total = 0
|
||||
for pokemon in pokemonArray
|
||||
species = pokemon.species
|
||||
forme = pokemon.forme || "default"
|
||||
item = pokemon.item
|
||||
speciesData = genData?.FormeData[species]
|
||||
|
||||
# Handle megas
|
||||
mega = genData?.ItemData[item]?.mega
|
||||
if mega
|
||||
[ megaSpecies, megaForme ] = mega
|
||||
if species == megaSpecies
|
||||
forme = megaForme
|
||||
|
||||
# Get PBV of the Pokemon's forme
|
||||
pbv = speciesData?[forme]?.pokeBattleValue || 0
|
||||
|
||||
# Handle Eviolite
|
||||
pbv = Math.round(1.3 * pbv / 5) * 5 if item == 'Eviolite'
|
||||
|
||||
# Add to total
|
||||
total += pbv
|
||||
|
||||
# Handle Baton Pass. Baton Pass cray.
|
||||
bpers = (p for p in pokemonArray when "Baton Pass" in (p.moves || []))
|
||||
total += BATON_PASS_PBV * Math.pow(2, bpers.length - 1) if bpers.length > 0
|
||||
|
||||
return total
|
||||
40
shared/protocol.coffee
Normal file
40
shared/protocol.coffee
Normal file
@@ -0,0 +1,40 @@
|
||||
@Protocol =
|
||||
CHANGE_HP : 1
|
||||
SWITCH_IN : 2
|
||||
CHANGE_PP : 3
|
||||
REQUEST_ACTIONS : 4
|
||||
START_TURN : 5
|
||||
RAW_MESSAGE : 6
|
||||
FAINT : 7
|
||||
MAKE_MOVE : 8
|
||||
END_BATTLE : 9
|
||||
FORFEIT_BATTLE : 10
|
||||
MOVE_SUCCESS : 11
|
||||
SWITCH_OUT : 12
|
||||
POKEMON_ATTACH : 13
|
||||
TEAM_ATTACH : 14
|
||||
BATTLE_ATTACH : 15
|
||||
POKEMON_UNATTACH : 16
|
||||
TEAM_UNATTACH : 17
|
||||
BATTLE_UNATTACH : 18
|
||||
START_BATTLE : 19
|
||||
RECEIVE_TEAM : 20
|
||||
CHANGE_EXACT_HP : 21
|
||||
SPRITE_CHANGE : 22
|
||||
BOOSTS : 23
|
||||
RESET_BOOSTS : 24
|
||||
MOVESET_UPDATE : 26
|
||||
TEAM_PREVIEW : 27
|
||||
INITIALIZE : 28
|
||||
REARRANGE_TEAMS : 29
|
||||
TIMER_WIN : 30
|
||||
WEATHER_CHANGE : 32
|
||||
ACTIVATE_ABILITY : 35
|
||||
CANNED_TEXT : 36
|
||||
CONTINUE_TURN : 37
|
||||
BATTLE_EXPIRED : 38
|
||||
SET_BOOSTS : 39
|
||||
END_MOVE : 40
|
||||
NAME_CHANGE : 41
|
||||
ILLUSION_CHANGE : 42
|
||||
VISIBLE_TEAM : 43
|
||||
12
shared/weather.coffee
Normal file
12
shared/weather.coffee
Normal file
@@ -0,0 +1,12 @@
|
||||
self = (module?.exports || window)
|
||||
|
||||
self.Weather =
|
||||
SUN: 'Sun'
|
||||
RAIN: 'Rain'
|
||||
HAIL: 'Hail'
|
||||
SAND: 'Sand'
|
||||
NONE: 'None'
|
||||
MOON: 'Moon'
|
||||
DELTASTREAM: 'DeltaStream'
|
||||
HARSHSUN: 'HarshSun'
|
||||
|
||||
Reference in New Issue
Block a user