1
0
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:
Deukhoofd
2016-02-01 23:19:30 +01:00
commit d7316d5799
6681 changed files with 527969 additions and 0 deletions

13
shared/bias_rng.coffee Normal file
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

View 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
View 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
View 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

View 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
View 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
View 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'