Last active
February 13, 2023 20:54
-
-
Save revoice1/203fed43d43cf26de357c1a23a3d6746 to your computer and use it in GitHub Desktop.
Function that leverages PokéAPI to quickly retrieve damage relationships for any given Pokémon, from any given generation. Wrote this for myself and my son to use while running soullink nuzlockes from various generations. Super helpful when you don't have the damage tables for a given generation memorized.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function Get-PokemonDamage { | |
<# | |
.SYNOPSIS | |
Retrieve damage information of a Pokemon based on its type(s) | |
.DESCRIPTION | |
The `Get-PokemonDamage` function retrieves information about the damage a Pokemon takes from different types of attacks, based on its type(s). | |
It can be invoked using either the name of the Pokemon or its type(s). | |
By default, the function returns information about the most recent generation of the Pokemon, but it can also be configured to return information about past generations using the `Generation` parameter. | |
An extra info switch can also be specified to include more details about the Pokemon. | |
.PARAMETER Pokemon | |
The name of a pokemon that you would like to receive damage relationship information for | |
.PARAMETER ExtraInfo | |
This switch used with the Pokemon parameter that pulls extra info from PokeAPI about the selected Pokemon. | |
This information includes: | |
* The generation they were introduced | |
* The genus of the Pokemon | |
* The BST of the Pokemon | |
* The weight of the Pokemon in pounds | |
* The damage this Pokemon receives from weight based attacks e.g. "low kick" | |
* A list of alternate forms for the Pokemon | |
* What the Pokemon evolves from | |
* Any special types of the Pokemon e.g. Baby, Legendary, Mythical | |
* A list of possible abilities that the Pokemon can have | |
.PARAMETER Generation | |
An integer used with the Pokemon or Types parameter that specifies the generation that you would like to receive damage information for. This is due to some damage relationships changing over different generations. | |
.PARAMETER Types | |
A list of types that you want to receive damage relationship information for | |
.NOTES | |
This function uses the PokeAPI (https://pokeapi.co) to retrieve information about Pokemon and their types. | |
.LINK | |
https://pokeapi.co/ | |
.EXAMPLE | |
# Returns damage information about Pikachu in the most recent generation, along with extra details about the Pokemon. | |
PS> Get-PokemonDamage Pikachu -ExtraInfo | |
*** Pikachu Is Electric Type *** | |
Serebii Link : https://www.serebii.net/pokemon/pikachu/ | |
--- Stats --- | |
Introduced : Generation-I | |
Genus : Mouse Pokémon | |
BST : 320 | |
Weight (Lbs) : 13.23 | |
Weight Damage : 20 | |
Alt-Forms : Pikachu-Rock-Star, Pikachu-Belle, Pikachu-Pop-Star, Pikachu-Phd, Pikachu-Libre, Pikachu-Cosplay, Pikachu-Original-Cap, Pikachu-Hoenn-Cap, Pikachu-Sinnoh-Cap, Pikachu-Unova-Cap, Pikachu-Kalos-Cap, Pikachu-Alola-Cap, Pikachu-Partner-Cap, Pikachu-Starter, Pikachu-World-Cap, Pikachu-Gmax | |
Evolves From : Pichu | |
--- Abilities --- | |
Static : Has a 30% chance of paralyzing attacking Pokémon on contact. | |
Lightning Rod* : Redirects single-target electric moves to this Pokémon where possible. Absorbs Electric moves, raising Special Attack one stage. | |
[* = Hidden] | |
--- Electric Damage In --- | |
Double : Ground | |
Half : Flying, Electric, Steel | |
--- Electric Damage Out --- | |
Double : Flying, Water | |
Half : Grass, Electric, Dragon | |
None : Ground | |
.EXAMPLE | |
# Returns damage information about the Fire type in Generation III. | |
PS> Get-PokemonDamage Fire -Generation 3 | |
--- Fire Damage In [III] --- | |
Double : Rock, Water, Ground | |
Half : Fairy, Grass, Ice, Steel, Bug, Fire | |
--- Fire Damage Out [III] --- | |
Double : Bug, Steel, Grass, Ice | |
Half : Rock, Fire, Water, Dragon | |
.EXAMPLE | |
# Returns damage information about Charmander in Generation II. | |
PS> Get-PokemonDamage Charmander -Generation 2 | |
*** Charmander Is Fire Type [II] *** | |
Serebii Link : https://www.serebii.net/pokedex-gs/004.shtml | |
--- Fire Damage In [II] --- | |
Double : Rock, Water, Ground | |
Half : Fairy, Grass, Ice, Steel, Bug, Fire | |
--- Fire Damage Out [II] --- | |
Double : Bug, Steel, Grass, Ice | |
Half : Rock, Fire, Water, Dragon | |
#> | |
[CmdletBinding(DefaultParameterSetName = 'Pokemon')] | |
param( | |
[Parameter(Mandatory = $true, ParameterSetName = 'Pokemon', Position = 0)] | |
[ArgumentCompleter({ | |
param ($commandName, $parameterName, $wordToComplete) | |
$Pokemon = $(Invoke-RestMethod "https://pokeapi.co/api/v2/pokemon?limit=2000").results | |
$Pokemon.name -like "$wordToComplete*" | |
})] | |
[string]$Pokemon, | |
[ArgumentCompleter({ | |
param ($commandName, $parameterName, $wordToComplete) | |
$Pokemon = $(Invoke-RestMethod "https://pokeapi.co/api/v2/type").results | |
$Pokemon.name -like "$wordToComplete*" | |
})] | |
[Parameter(Mandatory = $true, ParameterSetName = 'Type')] | |
$Types, | |
[Parameter(ParameterSetName = 'Pokemon')] | |
[switch]$ExtraInfo, | |
[Parameter(ParameterSetName = 'Type')] | |
[Parameter(ParameterSetName = 'Pokemon')] | |
[int]$Generation | |
) | |
$StringOutput = @() | |
$DamageInTypes = "quad_damage_from", "double_damage_from", "half_damage_from", "quarter_damage_from", "no_damage_from" | |
$DamageOutTypes = "double_damage_to", "half_damage_to", "no_damage_to" | |
if ($Pokemon) { | |
$Types = $null | |
try { | |
$PokemonData = (Invoke-RestMethod "https://pokeapi.co/api/v2/pokemon/$($Pokemon.tolower())") | |
} | |
catch { | |
Write-Warning "Pokemon not valid: $Pokemon" | |
Write-Verbose "Note: you can use tab-completion with the Pokemon and Type parameters to ensure valid values." -Verbose | |
continue | |
} | |
if ($Generation) { | |
$PastGenTypes = $PokemonData.past_types | |
if ($PastGenTypes) { | |
$AvailableGenerations = $PastGenTypes.generation.url -replace ".*/(\d)/$", '$1' | Where-Object { $_ -ge $Generation } | Sort-Object | |
if ($AvailableGenerations) { | |
$Types = ($PastGenTypes | Where-Object { $_.generation.url -match "/$($AvailableGenerations[0])/$" }).types.type.name | |
} | |
} | |
} | |
if (!$Types) { | |
$Types = $PokemonData.types.type.name | |
} | |
$Dex = switch ($Generation) { | |
1 { "pokedex/$($PokemonData.id.tostring().padleft(3,"0")).shtml" } | |
2 { "pokedex-gs/$($PokemonData.id.tostring().padleft(3,"0")).shtml" } | |
3 { "pokedex-rs/$($PokemonData.id.tostring().padleft(3,"0")).shtml" } | |
4 { "pokedex-dp/$($PokemonData.id.tostring().padleft(3,"0")).shtml" } | |
5 { "pokedex-bw/$($PokemonData.id.tostring().padleft(3,"0")).shtml" } | |
6 { "pokedex-xy/$($PokemonData.id.tostring().padleft(3,"0")).shtml" } | |
7 { "pokedex-sm/$($PokemonData.id.tostring().padleft(3,"0")).shtml" } | |
8 { "pokedex-swsh/$($PokemonData.species.name)/" } | |
9 { "pokedex-sv/$($PokemonData.species.name)/" } | |
default { "pokemon/$($PokemonData.species.name)/" } | |
} | |
Write-Output "" | |
Write-Output "*** $((Get-Culture).TextInfo.ToTitleCase("$Pokemon is $($Types -join "/") type")) $(if($Generation){"[$(Convert-IntToRomanNumeral $Generation)] "})***" | |
([PSCustomObject]@{"Serebii Link" = "https://www.serebii.net/$Dex" } | Format-List | Out-String).trim() | |
Write-Output "" | |
if ($ExtraInfo) { | |
$PokemonInfoString = @() | |
$PokemonInfoString += "--- Stats ---" | |
$SpeciesInfo = Invoke-RestMethod $PokemonData.species.url | |
$StatTable = [PSCustomObject]@{ | |
Introduced = "Generation-$(($SpeciesInfo.generation.name -replace ".*-(.*)", '$1').ToUpper())" | |
Genus = ($SpeciesInfo.genera | Where-Object { $_.language.name -eq "en" }).genus | |
BST = $($PokemonData.stats.base_stat | Measure-Object -Sum).Sum | |
"Weight (Lbs)" = [math]::Round((($PokemonData.weight / 10) * 2.20462262), 2) | |
"Weight Damage" = switch ($PokemonData.weight) { | |
{ 0..100 -contains $_ } { 20 ; break } | |
{ 101..250 -contains $_ } { 40 ; break } | |
{ 251..500 -contains $_ } { 60 ; break } | |
{ 501..1000 -contains $_ } { 80 ; break } | |
{ 1001..2000 -contains $_ } { 100 ; break } | |
{ $_ -gt 2000 } { 120 } | |
} | |
} | |
switch ($SpeciesInfo) { | |
{ $_.is_baby } { | |
Add-Member -InputObject $StatTable -NotePropertyName "Special Type" -NotePropertyValue "Baby" | |
break | |
} | |
{ $_.is_legendary } { | |
Add-Member -InputObject $StatTable -NotePropertyName "Special Type" -NotePropertyValue "Legendary" | |
break | |
} | |
{ $_.is_mythical } { | |
Add-Member -InputObject $StatTable -NotePropertyName "Special Type" -NotePropertyValue "Mythical" | |
break | |
} | |
} | |
if ($SpeciesInfo.varieties.count -gt 1) { | |
Add-Member -InputObject $StatTable -NotePropertyName "Alt-Forms" -NotePropertyValue $((Get-Culture).TextInfo.ToTitleCase($($SpeciesInfo.varieties | Where-Object { -not $_.is_default }).pokemon.name -join ", ")) | |
} | |
if ($SpeciesInfo.evolves_from_species) { | |
Add-Member -InputObject $StatTable -NotePropertyName "Evolves From" -NotePropertyValue $((Get-Culture).TextInfo.ToTitleCase($SpeciesInfo.evolves_from_species.name)) | |
} | |
$PokemonInfoString += ($StatTable | Format-List | Out-String).trim() | |
$PokemonInfoString += "" | |
$AbilityLine = "--- Abilities ---" | |
$AbilityTable = [PSCustomObject]@{} | |
foreach ($Ability in $PokemonData.abilities) { | |
$AbilityData = Invoke-RestMethod $Ability.ability.url | |
$AbilityName = $((Get-Culture).TextInfo.ToTitleCase(($Ability.ability.name -replace "-", " "))) + $(if ($Ability.is_hidden) { $HasHidden = $True; "*" }) | |
if ($null -like $($AbilityData.effect_entries)) { | |
$AbilityValue = $($AbilityData.flavor_text_entries | Where-Object { $_.language.name -eq "en" }).flavor_text -replace "`n+", " " | |
} | |
else { | |
$AbilityValue = $($AbilityData.effect_entries | Where-Object { $_.language.name -eq "en" }).short_effect -replace "`n+", " " | |
} | |
Add-Member -InputObject $AbilityTable -NotePropertyName $AbilityName -NotePropertyValue $AbilityValue | |
} | |
$PokemonInfoString += $AbilityLine | |
$PokemonInfoString += ($AbilityTable | Format-List | Out-String).trim() | |
if ($HasHidden) { | |
$PokemonInfoString += Write-Output "[* = Hidden]" | |
} | |
Write-Output $PokemonInfoString | |
Write-Output "" | |
} | |
} | |
if ($Types) { | |
$DamageFrom = @{} | |
$DamageTo = @{} | |
foreach ($Type in $Types) { | |
$damage_relations = $null | |
Try { | |
$TypeData = Invoke-RestMethod "https://pokeapi.co/api/v2/type/$($type.tolower())" | |
} | |
catch { | |
Write-Warning "Type not valid: $Type" | |
Write-Verbose "Note: you can use tab-completion with the Pokemon and Type parameters to ensure valid values." -Verbose | |
continue | |
} | |
if ($Generation) { | |
$past_damage_relations = $TypeData.past_damage_relations | |
if ($past_damage_relations) { | |
$TargetGeneration = $past_damage_relations.generation.url -replace ".*/(\d)/$", '$1' | Where-Object { $_ -eq $Generation } | |
$EarlierGenerations = $past_damage_relations.generation.url -replace ".*/(\d)/$", '$1' | Where-Object { $_ -le $Generation } | Sort-Object -Descending | |
$LaterGenerations = $past_damage_relations.generation.url -replace ".*/(\d)/$", '$1' | Where-Object { $_ -gt $Generation } | Sort-Object -Descending | |
if ($TargetGeneration) { | |
$damage_relations = ($past_damage_relations | Where-Object { $_.generation.url -match "/$TargetGeneration/$" }).damage_relations | |
} | |
elseif ($EarlierGenerations -and $LaterGenerations) { | |
$damage_relations = ($past_damage_relations | Where-Object { $_.generation.url -match "/$($EarlierGenerations[0])/$" }).damage_relations | |
} | |
} | |
} | |
if (!$damage_relations) { | |
$damage_relations = $TypeData.damage_relations | |
} | |
foreach ($Property in $damage_relations.psobject.properties) { | |
$damage_relations.$($Property.name) = $Property.value.name | |
if ($Property.name -match "from$") { | |
$Mod = switch -Regex ($Property.name) { | |
"^double" { 2; break } | |
"^half" { .5; break } | |
"^no" { 0; break } | |
} | |
foreach ($DamageType in $damage_relations.$($Property.name)) { | |
if ($null -ne $DamageFrom[$DamageType]) { | |
$DamageFrom[$DamageType] = $DamageFrom[$DamageType] * $Mod | |
} | |
else { | |
$DamageFrom[$DamageType] = $Mod | |
} | |
} | |
} | |
} | |
$DamageTo += @{ | |
$Type = $damage_relations | Select-Object "*_to" | |
} | |
} | |
$FromChart = [PSCustomObject]@{} | |
Foreach ($DamageType in $DamageInTypes) { | |
Add-Member -InputObject $FromChart -NotePropertyName $DamageType -NotePropertyValue @() | |
} | |
foreach ($Type in $DamageFrom.keys) { | |
switch ($DamageFrom[$Type]) { | |
1 { break } | |
2 { $FromChart."double_damage_from" += $Type ; break } | |
.5 { $FromChart."half_damage_from" += $Type ; break } | |
4 { $FromChart."quad_damage_from" += $Type ; break } | |
0 { $FromChart."no_damage_from" += $Type ; break } | |
.25 { $FromChart."quarter_damage_from" += $Type ; break } | |
} | |
} | |
$DamageIn = [PSCustomObject]@{} | |
foreach ($DamageType in $DamageInTypes) { | |
if ($FromChart.$DamageType -ne @()) { | |
Add-Member -InputObject $DamageIn -NotePropertyName (Get-Culture).TextInfo.ToTitleCase(($DamageType -replace "damage_from", "" -replace "_", " " -replace "no", "none")) -NotePropertyValue (Get-Culture).TextInfo.ToTitleCase(($FromChart.$DamageType -join ", ")) | |
} | |
} | |
$StringOutput += (Get-Culture).TextInfo.ToTitleCase("--- $($Types -join "/") damage in $(if($Generation){"[$(Convert-IntToRomanNumeral $Generation)] "})---") | |
$StringOutput += ($DamageIn | Format-List | Out-String).trim() | |
$StringOutput += "" | |
Foreach ($Type in $DamageTo.keys) { | |
$StringOutput += (Get-Culture).TextInfo.ToTitleCase("--- $($Type) damage out $(if($Generation){"[$(Convert-IntToRomanNumeral $Generation)] "})---") | |
$DamageOut = [PSCustomObject]@{} | |
foreach ($DamageType in $DamageOutTypes) { | |
if ($null -ne $DamageTo[$Type].$DamageType) { | |
Add-Member -InputObject $DamageOut -NotePropertyName (Get-Culture).TextInfo.ToTitleCase(($DamageType -replace "damage_to", "" -replace "_", " " -replace "no", "none")) -NotePropertyValue (Get-Culture).TextInfo.ToTitleCase(($DamageTo[$Type].$DamageType -join ", ")) | |
} | |
} | |
$StringOutput += ($DamageOut | Format-List | Out-String).trim() | |
$StringOutput += "" | |
} | |
} | |
return $StringOutput | |
} | |
function Convert-IntToRomanNumeral { | |
[CmdletBinding()] | |
param ( | |
[Parameter(Mandatory = $true, Position = 0)] | |
[int]$Number | |
) | |
$numerals = @{ | |
1000 = "M" | |
900 = "CM" | |
500 = "D" | |
400 = "CD" | |
100 = "C" | |
90 = "XC" | |
50 = "L" | |
40 = "XL" | |
10 = "X" | |
9 = "IX" | |
5 = "V" | |
4 = "IV" | |
1 = "I" | |
} | |
$result = "" | |
foreach ($key in ($numerals.Keys | Sort-Object -Descending)) { | |
while ($Number -ge $key) { | |
$result += $numerals[$key] | |
$Number -= $key | |
} | |
} | |
return $result | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment