localdex 0.2.40__py3-none-any.whl → 0.2.45__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- localdex/core.py +672 -5
- localdex-0.2.45.dist-info/METADATA +196 -0
- {localdex-0.2.40.dist-info → localdex-0.2.45.dist-info}/RECORD +7 -6
- localdex-0.2.45.dist-info/licenses/LICENSE +21 -0
- localdex-0.2.40.dist-info/METADATA +0 -270
- {localdex-0.2.40.dist-info → localdex-0.2.45.dist-info}/WHEEL +0 -0
- {localdex-0.2.40.dist-info → localdex-0.2.45.dist-info}/entry_points.txt +0 -0
- {localdex-0.2.40.dist-info → localdex-0.2.45.dist-info}/top_level.txt +0 -0
localdex/core.py
CHANGED
@@ -6,10 +6,11 @@ Pokemon data with caching, search capabilities, and data loading.
|
|
6
6
|
"""
|
7
7
|
|
8
8
|
import json
|
9
|
+
import math
|
9
10
|
import os
|
10
11
|
import glob
|
11
12
|
from pathlib import Path
|
12
|
-
from typing import Dict, List, Optional, Union, Any, Set
|
13
|
+
from typing import Dict, List, Optional, Union, Any, Set, Tuple
|
13
14
|
from functools import lru_cache
|
14
15
|
|
15
16
|
from .models import Pokemon, Move, Ability, Item, BaseStats
|
@@ -435,8 +436,8 @@ class LocalDex:
|
|
435
436
|
hp=base_stats_data.get("hp", 0),
|
436
437
|
attack=base_stats_data.get("attack", 0),
|
437
438
|
defense=base_stats_data.get("defense", 0),
|
438
|
-
special_attack=base_stats_data.get("
|
439
|
-
special_defense=base_stats_data.get("
|
439
|
+
special_attack=base_stats_data.get("special_attack", 0),
|
440
|
+
special_defense=base_stats_data.get("special_defense", 0),
|
440
441
|
speed=base_stats_data.get("speed", 0),
|
441
442
|
)
|
442
443
|
return Pokemon(
|
@@ -510,7 +511,7 @@ class LocalDex:
|
|
510
511
|
"""Create an Item object from raw data."""
|
511
512
|
return Item(
|
512
513
|
name=data.get("name", ""),
|
513
|
-
description=data.get("desc"),
|
514
|
+
description=data.get("description", data.get("desc", "")),
|
514
515
|
short_description=data.get("shortDesc"),
|
515
516
|
generation=data.get("gen"),
|
516
517
|
num=data.get("num"),
|
@@ -548,5 +549,671 @@ class LocalDex:
|
|
548
549
|
"abilities": len(self._ability_cache),
|
549
550
|
"items": len(self._item_cache)
|
550
551
|
}
|
552
|
+
def get_base_stats_from_species(self, species: str):
|
553
|
+
"""Get base stats from species name"""
|
554
|
+
return self.get_pokemon(name_or_id=species).base_stats
|
555
|
+
|
556
|
+
def get_hp_stat_from_species(self, species: str, iv: int, ev: int, level: int = 100) -> int:
|
557
|
+
"""Calculate HP stat for a species with given IVs, EVs, and level"""
|
558
|
+
base_stats = self.get_base_stats_from_species(species)
|
559
|
+
return self.calculate_hp(base_stats.hp, iv, ev, level)
|
560
|
+
|
561
|
+
def get_attack_stat_from_species(self, species: str, iv: int, ev: int, level: int = 100, nature_modifier: float = 1.0) -> int:
|
562
|
+
"""Calculate Attack stat for a species with given IVs, EVs, and level"""
|
563
|
+
base_stats = self.get_base_stats_from_species(species)
|
564
|
+
return self.calculate_other_stat(base_stats.attack, iv, ev, level, nature_modifier)
|
565
|
+
|
566
|
+
def get_defense_stat_from_species(self, species: str, iv: int, ev: int, level: int = 100, nature_modifier: float = 1.0) -> int:
|
567
|
+
"""Calculate Defense stat for a species with given IVs, EVs, and level"""
|
568
|
+
base_stats = self.get_base_stats_from_species(species)
|
569
|
+
return self.calculate_other_stat(base_stats.defense, iv, ev, level, nature_modifier)
|
570
|
+
|
571
|
+
def get_special_attack_stat_from_species(self, species: str, iv: int, ev: int, level: int = 100, nature_modifier: float = 1.0) -> int:
|
572
|
+
"""Calculate Special Attack stat for a species with given IVs, EVs, and level"""
|
573
|
+
base_stats = self.get_base_stats_from_species(species)
|
574
|
+
return self.calculate_other_stat(base_stats.special_attack, iv, ev, level, nature_modifier)
|
575
|
+
|
576
|
+
def get_special_defense_stat_from_species(self, species: str, iv: int, ev: int, level: int = 100, nature_modifier: float = 1.0) -> int:
|
577
|
+
"""Calculate Special Defense stat for a species with given IVs, EVs, and level"""
|
578
|
+
base_stats = self.get_base_stats_from_species(species)
|
579
|
+
return self.calculate_other_stat(base_stats.special_defense, iv, ev, level, nature_modifier)
|
580
|
+
|
581
|
+
def get_speed_stat_from_species(self, species: str, iv: int, ev: int, level: int = 100, nature_modifier: float = 1.0) -> int:
|
582
|
+
"""Calculate Speed stat for a species with given IVs, EVs, and level"""
|
583
|
+
base_stats = self.get_base_stats_from_species(species)
|
584
|
+
return self.calculate_other_stat(base_stats.speed, iv, ev, level, nature_modifier)
|
585
|
+
|
586
|
+
def get_substitute_health_from_species(self, species: str, iv: int, ev: int, level: int = 100) -> int:
|
587
|
+
"""Calculate substitute health for a species (1/4 of max HP)"""
|
588
|
+
max_hp = self.get_hp_stat_from_species(species, iv, ev, level)
|
589
|
+
return int(max_hp / 4)
|
590
|
+
|
591
|
+
def calculate_hp(self, base: int, iv: int, ev: int, level: int = 100) -> int:
|
592
|
+
"""
|
593
|
+
Calculate HP using the Pokemon HP formula.
|
594
|
+
|
595
|
+
Args:
|
596
|
+
base (int): Base HP stat
|
597
|
+
iv (int): Individual Value (0-31)
|
598
|
+
ev (int): Effort Value (0-252)
|
599
|
+
level (int): Pokemon level (1-100)
|
600
|
+
|
601
|
+
Returns:
|
602
|
+
int: Calculated HP value
|
603
|
+
"""
|
604
|
+
hp = math.floor(((2 * base + iv + math.floor(ev / 4)) * level) / 100) + level + 10
|
605
|
+
return hp
|
606
|
+
|
607
|
+
def calculate_other_stat(self, base: int, iv: int, ev: int, level: int = 100, nature_modifier: float = 1.0) -> int:
|
608
|
+
"""
|
609
|
+
Calculate other stats (Attack, Defense, Sp. Attack, Sp. Defense, Speed) using the Pokemon stat formula.
|
610
|
+
|
611
|
+
Args:
|
612
|
+
base (int): Base stat value
|
613
|
+
iv (int): Individual Value (0-31)
|
614
|
+
ev (int): Effort Value (0-252)
|
615
|
+
level (int): Pokemon level (1-100)
|
616
|
+
nature_modifier (float): Nature modifier (0.9 for hindering, 1.0 for neutral, 1.1 for beneficial)
|
617
|
+
|
618
|
+
Returns:
|
619
|
+
int: Calculated stat value
|
620
|
+
"""
|
621
|
+
stat = math.floor((math.floor(((2 * base + iv + math.floor(ev / 4)) * level) / 100) + 5) * nature_modifier)
|
622
|
+
return stat
|
623
|
+
|
624
|
+
def calculate_hp_ev(self, total_hp: int, base_hp: int, iv: int, level: int = 100) -> int:
|
625
|
+
"""
|
626
|
+
Calculate HP EV from total HP stat using the reverse of the Pokemon HP formula.
|
627
|
+
|
628
|
+
If the target HP is impossible to achieve with any EV value, returns the EV that
|
629
|
+
produces the closest possible HP value. For impossibly high HP values, returns 252 EVs.
|
630
|
+
For impossibly low HP values, returns 0 EVs.
|
631
|
+
|
632
|
+
Args:
|
633
|
+
total_hp (int): Total HP stat value
|
634
|
+
base_hp (int): Base HP stat
|
635
|
+
iv (int): Individual Value (0-31)
|
636
|
+
level (int): Pokemon level (1-100)
|
637
|
+
|
638
|
+
Returns:
|
639
|
+
int: Required EV value (0-252) - closest possible value if target is impossible
|
640
|
+
"""
|
641
|
+
if level <= 0:
|
642
|
+
raise ValueError("Level must be greater than 0")
|
643
|
+
|
644
|
+
# Calculate the minimum and maximum possible HP values
|
645
|
+
min_hp = self.calculate_hp(base_hp, iv, 0, level)
|
646
|
+
max_hp = self.calculate_hp(base_hp, iv, 252, level)
|
647
|
+
|
648
|
+
# If target HP is impossible, return the closest boundary
|
649
|
+
if total_hp <= min_hp:
|
650
|
+
return 0 # Return 0 EVs for impossibly low HP
|
651
|
+
elif total_hp >= max_hp:
|
652
|
+
return 252 # Return 252 EVs for impossibly high HP
|
653
|
+
|
654
|
+
# Find the EV that gives us the closest HP value
|
655
|
+
best_ev = 0
|
656
|
+
best_diff = float('inf')
|
657
|
+
|
658
|
+
for test_ev in range(0, 253, 4): # EVs are always multiples of 4
|
659
|
+
test_hp = self.calculate_hp(base_hp, iv, test_ev, level)
|
660
|
+
diff = abs(test_hp - total_hp)
|
661
|
+
|
662
|
+
if diff < best_diff:
|
663
|
+
best_diff = diff
|
664
|
+
best_ev = test_ev
|
665
|
+
elif diff == best_diff and test_ev < best_ev:
|
666
|
+
# If we have the same difference, prefer the lower EV
|
667
|
+
best_ev = test_ev
|
668
|
+
|
669
|
+
return best_ev
|
670
|
+
|
671
|
+
def calculate_other_stat_ev(self, total_stat: int, base_stat: int, iv: int, level: int = 100, nature_modifier: float = 1.0) -> int:
|
672
|
+
"""
|
673
|
+
Calculate EV for other stats (Attack, Defense, Sp. Attack, Sp. Defense, Speed) using the reverse of the Pokemon stat formula.
|
674
|
+
|
675
|
+
If the target stat is impossible to achieve with any EV value, returns the EV that
|
676
|
+
produces the closest possible stat value. For impossibly high stat values, returns 252 EVs.
|
677
|
+
For impossibly low stat values, returns 0 EVs.
|
678
|
+
|
679
|
+
Args:
|
680
|
+
total_stat (int): Total stat value
|
681
|
+
base_stat (int): Base stat value
|
682
|
+
iv (int): Individual Value (0-31)
|
683
|
+
level (int): Pokemon level (1-100)
|
684
|
+
nature_modifier (float): Nature modifier (0.9 for hindering, 1.0 for neutral, 1.1 for beneficial)
|
685
|
+
|
686
|
+
Returns:
|
687
|
+
int: Required EV value (0-252) - closest possible value if target is impossible
|
688
|
+
"""
|
689
|
+
if level <= 0:
|
690
|
+
raise ValueError("Level must be greater than 0")
|
691
|
+
if nature_modifier <= 0:
|
692
|
+
raise ValueError("Nature modifier must be greater than 0")
|
693
|
+
|
694
|
+
# Calculate the minimum and maximum possible stat values
|
695
|
+
min_stat = self.calculate_other_stat(base_stat, iv, 0, level, nature_modifier)
|
696
|
+
max_stat = self.calculate_other_stat(base_stat, iv, 252, level, nature_modifier)
|
697
|
+
|
698
|
+
# If target stat is impossible, return the closest boundary
|
699
|
+
if total_stat <= min_stat:
|
700
|
+
return 0 # Return 0 EVs for impossibly low stat
|
701
|
+
elif total_stat >= max_stat:
|
702
|
+
return 252 # Return 252 EVs for impossibly high stat
|
703
|
+
|
704
|
+
# Find the EV that gives us the closest stat value
|
705
|
+
best_ev = 0
|
706
|
+
best_diff = float('inf')
|
707
|
+
|
708
|
+
for test_ev in range(0, 253, 4): # EVs are always multiples of 4
|
709
|
+
test_stat = self.calculate_other_stat(base_stat, iv, test_ev, level, nature_modifier)
|
710
|
+
diff = abs(test_stat - total_stat)
|
711
|
+
|
712
|
+
if diff < best_diff:
|
713
|
+
best_diff = diff
|
714
|
+
best_ev = test_ev
|
715
|
+
elif diff == best_diff and test_ev < best_ev:
|
716
|
+
# If we have the same difference, prefer the lower EV
|
717
|
+
best_ev = test_ev
|
718
|
+
|
719
|
+
return best_ev
|
720
|
+
|
721
|
+
def calculate_attack_ev(self, total_attack: int, base_attack: int, iv: int, level: int = 100, nature_modifier: float = 1.0) -> int:
|
722
|
+
"""
|
723
|
+
Calculate Attack EV from total Attack stat.
|
724
|
+
|
725
|
+
If the target Attack is impossible to achieve with any EV value, returns the EV that
|
726
|
+
produces the closest possible Attack value. For impossibly high Attack values, returns 252 EVs.
|
727
|
+
For impossibly low Attack values, returns 0 EVs.
|
728
|
+
|
729
|
+
Args:
|
730
|
+
total_attack (int): Total Attack stat value
|
731
|
+
base_attack (int): Base Attack stat
|
732
|
+
iv (int): Individual Value (0-31)
|
733
|
+
level (int): Pokemon level (1-100)
|
734
|
+
nature_modifier (float): Nature modifier (0.9 for hindering, 1.0 for neutral, 1.1 for beneficial)
|
735
|
+
|
736
|
+
Returns:
|
737
|
+
int: Required EV value (0-252) - closest possible value if target is impossible
|
738
|
+
"""
|
739
|
+
return self.calculate_other_stat_ev(total_attack, base_attack, iv, level, nature_modifier)
|
740
|
+
|
741
|
+
def calculate_defense_ev(self, total_defense: int, base_defense: int, iv: int, level: int = 100, nature_modifier: float = 1.0) -> int:
|
742
|
+
"""
|
743
|
+
Calculate Defense EV from total Defense stat.
|
744
|
+
|
745
|
+
If the target Defense is impossible to achieve with any EV value, returns the EV that
|
746
|
+
produces the closest possible Defense value. For impossibly high Defense values, returns 252 EVs.
|
747
|
+
For impossibly low Defense values, returns 0 EVs.
|
748
|
+
|
749
|
+
Args:
|
750
|
+
total_defense (int): Total Defense stat value
|
751
|
+
base_defense (int): Base Defense stat
|
752
|
+
iv (int): Individual Value (0-31)
|
753
|
+
level (int): Pokemon level (1-100)
|
754
|
+
nature_modifier (float): Nature modifier (0.9 for hindering, 1.0 for neutral, 1.1 for beneficial)
|
755
|
+
|
756
|
+
Returns:
|
757
|
+
int: Required EV value (0-252) - closest possible value if target is impossible
|
758
|
+
"""
|
759
|
+
return self.calculate_other_stat_ev(total_defense, base_defense, iv, level, nature_modifier)
|
760
|
+
|
761
|
+
def calculate_special_attack_ev(self, total_special_attack: int, base_special_attack: int, iv: int, level: int = 100, nature_modifier: float = 1.0) -> int:
|
762
|
+
"""
|
763
|
+
Calculate Special Attack EV from total Special Attack stat.
|
764
|
+
|
765
|
+
If the target Special Attack is impossible to achieve with any EV value, returns the EV that
|
766
|
+
produces the closest possible Special Attack value. For impossibly high Special Attack values, returns 252 EVs.
|
767
|
+
For impossibly low Special Attack values, returns 0 EVs.
|
768
|
+
|
769
|
+
Args:
|
770
|
+
total_special_attack (int): Total Special Attack stat value
|
771
|
+
base_special_attack (int): Base Special Attack stat
|
772
|
+
iv (int): Individual Value (0-31)
|
773
|
+
level (int): Pokemon level (1-100)
|
774
|
+
nature_modifier (float): Nature modifier (0.9 for hindering, 1.0 for neutral, 1.1 for beneficial)
|
775
|
+
|
776
|
+
Returns:
|
777
|
+
int: Required EV value (0-252) - closest possible value if target is impossible
|
778
|
+
"""
|
779
|
+
return self.calculate_other_stat_ev(total_special_attack, base_special_attack, iv, level, nature_modifier)
|
780
|
+
|
781
|
+
def calculate_special_defense_ev(self, total_special_defense: int, base_special_defense: int, iv: int, level: int = 100, nature_modifier: float = 1.0) -> int:
|
782
|
+
"""
|
783
|
+
Calculate Special Defense EV from total Special Defense stat.
|
784
|
+
|
785
|
+
If the target Special Defense is impossible to achieve with any EV value, returns the EV that
|
786
|
+
produces the closest possible Special Defense value. For impossibly high Special Defense values, returns 252 EVs.
|
787
|
+
For impossibly low Special Defense values, returns 0 EVs.
|
788
|
+
|
789
|
+
Args:
|
790
|
+
total_special_defense (int): Total Special Defense stat value
|
791
|
+
base_special_defense (int): Base Special Defense stat
|
792
|
+
iv (int): Individual Value (0-31)
|
793
|
+
level (int): Pokemon level (1-100)
|
794
|
+
nature_modifier (float): Nature modifier (0.9 for hindering, 1.0 for neutral, 1.1 for beneficial)
|
795
|
+
|
796
|
+
Returns:
|
797
|
+
int: Required EV value (0-252) - closest possible value if target is impossible
|
798
|
+
"""
|
799
|
+
return self.calculate_other_stat_ev(total_special_defense, base_special_defense, iv, level, nature_modifier)
|
800
|
+
|
801
|
+
def calculate_speed_ev(self, total_speed: int, base_speed: int, iv: int, level: int = 100, nature_modifier: float = 1.0) -> int:
|
802
|
+
"""
|
803
|
+
Calculate Speed EV from total Speed stat.
|
804
|
+
|
805
|
+
If the target Speed is impossible to achieve with any EV value, returns the EV that
|
806
|
+
produces the closest possible Speed value. For impossibly high Speed values, returns 252 EVs.
|
807
|
+
For impossibly low Speed values, returns 0 EVs.
|
808
|
+
|
809
|
+
Args:
|
810
|
+
total_speed (int): Total Speed stat value
|
811
|
+
base_speed (int): Base Speed stat
|
812
|
+
iv (int): Individual Value (0-31)
|
813
|
+
level (int): Pokemon level (1-100)
|
814
|
+
nature_modifier (float): Nature modifier (0.9 for hindering, 1.0 for neutral, 1.1 for beneficial)
|
815
|
+
|
816
|
+
Returns:
|
817
|
+
int: Required EV value (0-252) - closest possible value if target is impossible
|
818
|
+
"""
|
819
|
+
return self.calculate_other_stat_ev(total_speed, base_speed, iv, level, nature_modifier)
|
820
|
+
|
821
|
+
def calculate_hp_ev_from_species(self, species: str, total_hp: int, iv: int, level: int = 100) -> int:
|
822
|
+
"""
|
823
|
+
Calculate HP EV from total HP stat using species name.
|
824
|
+
|
825
|
+
If the target HP is impossible to achieve with any EV value, returns the EV that
|
826
|
+
produces the closest possible HP value. For impossibly high HP values, returns 252 EVs.
|
827
|
+
For impossibly low HP values, returns 0 EVs.
|
828
|
+
|
829
|
+
Args:
|
830
|
+
species (str): Pokemon species name
|
831
|
+
total_hp (int): Total HP stat value
|
832
|
+
iv (int): Individual Value (0-31)
|
833
|
+
level (int): Pokemon level (1-100)
|
834
|
+
|
835
|
+
Returns:
|
836
|
+
int: Required EV value (0-252) - closest possible value if target is impossible
|
837
|
+
"""
|
838
|
+
base_stats = self.get_base_stats_from_species(species)
|
839
|
+
return self.calculate_hp_ev(total_hp, base_stats.hp, iv, level)
|
840
|
+
|
841
|
+
def calculate_attack_ev_from_species(self, species: str, total_attack: int, iv: int, level: int = 100, nature_modifier: float = 1.0) -> int:
|
842
|
+
"""
|
843
|
+
Calculate Attack EV from total Attack stat using species name.
|
844
|
+
|
845
|
+
If the target Attack is impossible to achieve with any EV value, returns the EV that
|
846
|
+
produces the closest possible Attack value. For impossibly high Attack values, returns 252 EVs.
|
847
|
+
For impossibly low Attack values, returns 0 EVs.
|
848
|
+
|
849
|
+
Args:
|
850
|
+
species (str): Pokemon species name
|
851
|
+
total_attack (int): Total Attack stat value
|
852
|
+
iv (int): Individual Value (0-31)
|
853
|
+
level (int): Pokemon level (1-100)
|
854
|
+
nature_modifier (float): Nature modifier (0.9 for hindering, 1.0 for neutral, 1.1 for beneficial)
|
855
|
+
|
856
|
+
Returns:
|
857
|
+
int: Required EV value (0-252) - closest possible value if target is impossible
|
858
|
+
"""
|
859
|
+
base_stats = self.get_base_stats_from_species(species)
|
860
|
+
return self.calculate_attack_ev(total_attack, base_stats.attack, iv, level, nature_modifier)
|
861
|
+
|
862
|
+
def calculate_defense_ev_from_species(self, species: str, total_defense: int, iv: int, level: int = 100, nature_modifier: float = 1.0) -> int:
|
863
|
+
"""
|
864
|
+
Calculate Defense EV from total Defense stat using species name.
|
865
|
+
|
866
|
+
If the target Defense is impossible to achieve with any EV value, returns the EV that
|
867
|
+
produces the closest possible Defense value. For impossibly high Defense values, returns 252 EVs.
|
868
|
+
For impossibly low Defense values, returns 0 EVs.
|
869
|
+
|
870
|
+
Args:
|
871
|
+
species (str): Pokemon species name
|
872
|
+
total_defense (int): Total Defense stat value
|
873
|
+
iv (int): Individual Value (0-31)
|
874
|
+
level (int): Pokemon level (1-100)
|
875
|
+
nature_modifier (float): Nature modifier (0.9 for hindering, 1.0 for neutral, 1.1 for beneficial)
|
876
|
+
|
877
|
+
Returns:
|
878
|
+
int: Required EV value (0-252) - closest possible value if target is impossible
|
879
|
+
"""
|
880
|
+
base_stats = self.get_base_stats_from_species(species)
|
881
|
+
return self.calculate_defense_ev(total_defense, base_stats.defense, iv, level, nature_modifier)
|
882
|
+
|
883
|
+
def calculate_special_attack_ev_from_species(self, species: str, total_special_attack: int, iv: int, level: int = 100, nature_modifier: float = 1.0) -> int:
|
884
|
+
"""
|
885
|
+
Calculate Special Attack EV from total Special Attack stat using species name.
|
886
|
+
|
887
|
+
If the target Special Attack is impossible to achieve with any EV value, returns the EV that
|
888
|
+
produces the closest possible Special Attack value. For impossibly high Special Attack values, returns 252 EVs.
|
889
|
+
For impossibly low Special Attack values, returns 0 EVs.
|
890
|
+
|
891
|
+
Args:
|
892
|
+
species (str): Pokemon species name
|
893
|
+
total_special_attack (int): Total Special Attack stat value
|
894
|
+
iv (int): Individual Value (0-31)
|
895
|
+
level (int): Pokemon level (1-100)
|
896
|
+
nature_modifier (float): Nature modifier (0.9 for hindering, 1.0 for neutral, 1.1 for beneficial)
|
897
|
+
|
898
|
+
Returns:
|
899
|
+
int: Required EV value (0-252) - closest possible value if target is impossible
|
900
|
+
"""
|
901
|
+
base_stats = self.get_base_stats_from_species(species)
|
902
|
+
return self.calculate_special_attack_ev(total_special_attack, base_stats.special_attack, iv, level, nature_modifier)
|
903
|
+
|
904
|
+
def calculate_special_defense_ev_from_species(self, species: str, total_special_defense: int, iv: int, level: int = 100, nature_modifier: float = 1.0) -> int:
|
905
|
+
"""
|
906
|
+
Calculate Special Defense EV from total Special Defense stat using species name.
|
907
|
+
|
908
|
+
If the target Special Defense is impossible to achieve with any EV value, returns the EV that
|
909
|
+
produces the closest possible Special Defense value. For impossibly high Special Defense values, returns 252 EVs.
|
910
|
+
For impossibly low Special Defense values, returns 0 EVs.
|
911
|
+
|
912
|
+
Args:
|
913
|
+
species (str): Pokemon species name
|
914
|
+
total_special_defense (int): Total Special Defense stat value
|
915
|
+
iv (int): Individual Value (0-31)
|
916
|
+
level (int): Pokemon level (1-100)
|
917
|
+
nature_modifier (float): Nature modifier (0.9 for hindering, 1.0 for neutral, 1.1 for beneficial)
|
918
|
+
|
919
|
+
Returns:
|
920
|
+
int: Required EV value (0-252) - closest possible value if target is impossible
|
921
|
+
"""
|
922
|
+
base_stats = self.get_base_stats_from_species(species)
|
923
|
+
return self.calculate_special_defense_ev(total_special_defense, base_stats.special_defense, iv, level, nature_modifier)
|
924
|
+
|
925
|
+
def calculate_speed_ev_from_species(self, species: str, total_speed: int, iv: int, level: int = 100, nature_modifier: float = 1.0) -> int:
|
926
|
+
"""
|
927
|
+
Calculate Speed EV from total Speed stat using species name.
|
928
|
+
|
929
|
+
If the target Speed is impossible to achieve with any EV value, returns the EV that
|
930
|
+
produces the closest possible Speed value. For impossibly high Speed values, returns 252 EVs.
|
931
|
+
For impossibly low Speed values, returns 0 EVs.
|
932
|
+
|
933
|
+
Args:
|
934
|
+
species (str): Pokemon species name
|
935
|
+
total_speed (int): Total Speed stat value
|
936
|
+
iv (int): Individual Value (0-31)
|
937
|
+
level (int): Pokemon level (1-100)
|
938
|
+
nature_modifier (float): Nature modifier (0.9 for hindering, 1.0 for neutral, 1.1 for beneficial)
|
939
|
+
|
940
|
+
Returns:
|
941
|
+
int: Required EV value (0-252) - closest possible value if target is impossible
|
942
|
+
"""
|
943
|
+
base_stats = self.get_base_stats_from_species(species)
|
944
|
+
return self.calculate_speed_ev(total_speed, base_stats.speed, iv, level, nature_modifier)
|
945
|
+
|
946
|
+
def calculate_all_evs_from_species(self, species: str, stats: Dict[str, int], ivs: Dict[str, int], level: int = 100, nature_modifier: float = 1.0) -> Dict[str, int]:
|
947
|
+
"""
|
948
|
+
Calculate all EV values for a Pokemon using species name and target stats.
|
949
|
+
|
950
|
+
If any target stat is impossible to achieve with any EV value, returns the EV that
|
951
|
+
produces the closest possible stat value. For impossibly high stat values, returns 252 EVs.
|
952
|
+
For impossibly low stat values, returns 0 EVs.
|
953
|
+
|
954
|
+
Args:
|
955
|
+
species (str): Pokemon species name
|
956
|
+
stats (Dict[str, int]): Dictionary of target stat values with keys: 'hp', 'attack', 'defense', 'special_attack', 'special_defense', 'speed'
|
957
|
+
ivs (Dict[str, int]): Dictionary of IV values with keys: 'hp', 'attack', 'defense', 'special_attack', 'special_defense', 'speed'
|
958
|
+
level (int): Pokemon level (1-100)
|
959
|
+
nature_modifier (float): Nature modifier (0.9 for hindering, 1.0 for neutral, 1.1 for beneficial)
|
960
|
+
|
961
|
+
Returns:
|
962
|
+
Dict[str, int]: Dictionary of required EV values for each stat - closest possible values if targets are impossible
|
963
|
+
"""
|
964
|
+
base_stats = self.get_base_stats_from_species(species)
|
965
|
+
|
966
|
+
evs = {}
|
967
|
+
|
968
|
+
# Calculate HP EV (no nature modifier)
|
969
|
+
if 'hp' in stats:
|
970
|
+
evs['hp'] = self.calculate_hp_ev(stats['hp'], base_stats.hp, ivs.get('hp', 31), level)
|
971
|
+
|
972
|
+
# Calculate other stat EVs (with nature modifier)
|
973
|
+
if 'attack' in stats:
|
974
|
+
evs['attack'] = self.calculate_attack_ev(stats['attack'], base_stats.attack, ivs.get('attack', 31), level, nature_modifier)
|
975
|
+
|
976
|
+
if 'defense' in stats:
|
977
|
+
evs['defense'] = self.calculate_defense_ev(stats['defense'], base_stats.defense, ivs.get('defense', 31), level, nature_modifier)
|
978
|
+
|
979
|
+
if 'special_attack' in stats:
|
980
|
+
evs['special_attack'] = self.calculate_special_attack_ev(stats['special_attack'], base_stats.special_attack, ivs.get('special_attack', 31), level, nature_modifier)
|
981
|
+
|
982
|
+
if 'special_defense' in stats:
|
983
|
+
evs['special_defense'] = self.calculate_special_defense_ev(stats['special_defense'], base_stats.special_defense, ivs.get('special_defense', 31), level, nature_modifier)
|
984
|
+
|
985
|
+
if 'speed' in stats:
|
986
|
+
evs['speed'] = self.calculate_speed_ev(stats['speed'], base_stats.speed, ivs.get('speed', 31), level, nature_modifier)
|
987
|
+
|
988
|
+
return evs
|
989
|
+
|
990
|
+
def calculate_hp_ev_and_nature_combinations(self, total_hp: int, base_hp: int, iv: int, level: int = 100) -> List[Tuple[int, float]]:
|
991
|
+
"""
|
992
|
+
Calculate all possible EV and nature modifier combinations for HP.
|
993
|
+
Note: HP is not affected by nature, so this returns only the EV value with nature_modifier=1.0.
|
994
|
+
|
995
|
+
Args:
|
996
|
+
total_hp (int): Total HP stat value
|
997
|
+
base_hp (int): Base HP stat
|
998
|
+
iv (int): Individual Value (0-31)
|
999
|
+
level (int): Pokemon level (1-100)
|
1000
|
+
|
1001
|
+
Returns:
|
1002
|
+
List[Tuple[int, float]]: List of (EV, nature_modifier) combinations
|
1003
|
+
"""
|
1004
|
+
# HP is not affected by nature, so there's only one combination
|
1005
|
+
ev = self.calculate_hp_ev(total_hp, base_hp, iv, level)
|
1006
|
+
return [(ev, 1.0)]
|
1007
|
+
|
1008
|
+
def calculate_other_stat_ev_and_nature_combinations(self, total_stat: int, base_stat: int, iv: int, level: int = 100) -> List[Tuple[int, float]]:
|
1009
|
+
"""
|
1010
|
+
Calculate all possible EV and nature modifier combinations for other stats.
|
1011
|
+
|
1012
|
+
Args:
|
1013
|
+
total_stat (int): Total stat value
|
1014
|
+
base_stat (int): Base stat value
|
1015
|
+
iv (int): Individual Value (0-31)
|
1016
|
+
level (int): Pokemon level (1-100)
|
1017
|
+
|
1018
|
+
Returns:
|
1019
|
+
List[Tuple[int, float]]: List of (EV, nature_modifier) combinations
|
1020
|
+
"""
|
1021
|
+
if level <= 0:
|
1022
|
+
raise ValueError("Level must be greater than 0")
|
1023
|
+
|
1024
|
+
combinations = []
|
1025
|
+
|
1026
|
+
# Try each nature modifier: hindering (0.9), neutral (1.0), beneficial (1.1)
|
1027
|
+
nature_modifiers = [0.9, 1.0, 1.1]
|
1028
|
+
|
1029
|
+
for nature_modifier in nature_modifiers:
|
1030
|
+
try:
|
1031
|
+
ev = self.calculate_other_stat_ev(total_stat, base_stat, iv, level, nature_modifier)
|
1032
|
+
|
1033
|
+
# Verify this combination actually produces the target stat (or closest possible)
|
1034
|
+
calculated_stat = self.calculate_other_stat(base_stat, iv, ev, level, nature_modifier)
|
1035
|
+
|
1036
|
+
# Accept the combination if it produces the target stat or the closest possible value
|
1037
|
+
if calculated_stat == total_stat or abs(calculated_stat - total_stat) <= 1:
|
1038
|
+
combinations.append((ev, nature_modifier))
|
1039
|
+
|
1040
|
+
except (ValueError, ZeroDivisionError):
|
1041
|
+
# Skip invalid combinations
|
1042
|
+
continue
|
1043
|
+
|
1044
|
+
# Remove duplicates and sort by EV (ascending)
|
1045
|
+
unique_combinations = list(set(combinations))
|
1046
|
+
unique_combinations.sort(key=lambda x: x[0])
|
1047
|
+
|
1048
|
+
return unique_combinations
|
1049
|
+
|
1050
|
+
def calculate_attack_ev_and_nature_combinations(self, total_attack: int, base_attack: int, iv: int, level: int = 100) -> List[Tuple[int, float]]:
|
1051
|
+
"""
|
1052
|
+
Calculate all possible Attack EV and nature modifier combinations.
|
1053
|
+
|
1054
|
+
Args:
|
1055
|
+
total_attack (int): Total Attack stat value
|
1056
|
+
base_attack (int): Base Attack stat
|
1057
|
+
iv (int): Individual Value (0-31)
|
1058
|
+
level (int): Pokemon level (1-100)
|
1059
|
+
|
1060
|
+
Returns:
|
1061
|
+
List[Tuple[int, float]]: List of (EV, nature_modifier) combinations
|
1062
|
+
"""
|
1063
|
+
return self.calculate_other_stat_ev_and_nature_combinations(total_attack, base_attack, iv, level)
|
551
1064
|
|
552
|
-
|
1065
|
+
def calculate_defense_ev_and_nature_combinations(self, total_defense: int, base_defense: int, iv: int, level: int = 100) -> List[Tuple[int, float]]:
|
1066
|
+
"""
|
1067
|
+
Calculate all possible Defense EV and nature modifier combinations.
|
1068
|
+
|
1069
|
+
Args:
|
1070
|
+
total_defense (int): Total Defense stat value
|
1071
|
+
base_defense (int): Base Defense stat
|
1072
|
+
iv (int): Individual Value (0-31)
|
1073
|
+
level (int): Pokemon level (1-100)
|
1074
|
+
|
1075
|
+
Returns:
|
1076
|
+
List[Tuple[int, float]]: List of (EV, nature_modifier) combinations
|
1077
|
+
"""
|
1078
|
+
return self.calculate_other_stat_ev_and_nature_combinations(total_defense, base_defense, iv, level)
|
1079
|
+
|
1080
|
+
def calculate_special_attack_ev_and_nature_combinations(self, total_special_attack: int, base_special_attack: int, iv: int, level: int = 100) -> List[Tuple[int, float]]:
|
1081
|
+
"""
|
1082
|
+
Calculate all possible Special Attack EV and nature modifier combinations.
|
1083
|
+
|
1084
|
+
Args:
|
1085
|
+
total_special_attack (int): Total Special Attack stat value
|
1086
|
+
base_special_attack (int): Base Special Attack stat
|
1087
|
+
iv (int): Individual Value (0-31)
|
1088
|
+
level (int): Pokemon level (1-100)
|
1089
|
+
|
1090
|
+
Returns:
|
1091
|
+
List[Tuple[int, float]]: List of (EV, nature_modifier) combinations
|
1092
|
+
"""
|
1093
|
+
return self.calculate_other_stat_ev_and_nature_combinations(total_special_attack, base_special_attack, iv, level)
|
1094
|
+
|
1095
|
+
def calculate_special_defense_ev_and_nature_combinations(self, total_special_defense: int, base_special_defense: int, iv: int, level: int = 100) -> List[Tuple[int, float]]:
|
1096
|
+
"""
|
1097
|
+
Calculate all possible Special Defense EV and nature modifier combinations.
|
1098
|
+
|
1099
|
+
Args:
|
1100
|
+
total_special_defense (int): Total Special Defense stat value
|
1101
|
+
base_special_defense (int): Base Special Defense stat
|
1102
|
+
iv (int): Individual Value (0-31)
|
1103
|
+
level (int): Pokemon level (1-100)
|
1104
|
+
|
1105
|
+
Returns:
|
1106
|
+
List[Tuple[int, float]]: List of (EV, nature_modifier) combinations
|
1107
|
+
"""
|
1108
|
+
return self.calculate_other_stat_ev_and_nature_combinations(total_special_defense, base_special_defense, iv, level)
|
1109
|
+
|
1110
|
+
def calculate_speed_ev_and_nature_combinations(self, total_speed: int, base_speed: int, iv: int, level: int = 100) -> List[Tuple[int, float]]:
|
1111
|
+
"""
|
1112
|
+
Calculate all possible Speed EV and nature modifier combinations.
|
1113
|
+
|
1114
|
+
Args:
|
1115
|
+
total_speed (int): Total Speed stat value
|
1116
|
+
base_speed (int): Base Speed stat
|
1117
|
+
iv (int): Individual Value (0-31)
|
1118
|
+
level (int): Pokemon level (1-100)
|
1119
|
+
|
1120
|
+
Returns:
|
1121
|
+
List[Tuple[int, float]]: List of (EV, nature_modifier) combinations
|
1122
|
+
"""
|
1123
|
+
return self.calculate_other_stat_ev_and_nature_combinations(total_speed, base_speed, iv, level)
|
1124
|
+
|
1125
|
+
def calculate_hp_ev_and_nature_combinations_from_species(self, species: str, total_hp: int, iv: int, level: int = 100) -> List[Tuple[int, float]]:
|
1126
|
+
"""
|
1127
|
+
Calculate all possible HP EV and nature modifier combinations using species name.
|
1128
|
+
|
1129
|
+
Args:
|
1130
|
+
species (str): Pokemon species name
|
1131
|
+
total_hp (int): Total HP stat value
|
1132
|
+
iv (int): Individual Value (0-31)
|
1133
|
+
level (int): Pokemon level (1-100)
|
1134
|
+
|
1135
|
+
Returns:
|
1136
|
+
List[Tuple[int, float]]: List of (EV, nature_modifier) combinations
|
1137
|
+
"""
|
1138
|
+
base_stats = self.get_base_stats_from_species(species)
|
1139
|
+
return self.calculate_hp_ev_and_nature_combinations(total_hp, base_stats.hp, iv, level)
|
1140
|
+
|
1141
|
+
def calculate_attack_ev_and_nature_combinations_from_species(self, species: str, total_attack: int, iv: int, level: int = 100) -> List[Tuple[int, float]]:
|
1142
|
+
"""
|
1143
|
+
Calculate all possible Attack EV and nature modifier combinations using species name.
|
1144
|
+
|
1145
|
+
Args:
|
1146
|
+
species (str): Pokemon species name
|
1147
|
+
total_attack (int): Total Attack stat value
|
1148
|
+
iv (int): Individual Value (0-31)
|
1149
|
+
level (int): Pokemon level (1-100)
|
1150
|
+
|
1151
|
+
Returns:
|
1152
|
+
List[Tuple[int, float]]: List of (EV, nature_modifier) combinations
|
1153
|
+
"""
|
1154
|
+
base_stats = self.get_base_stats_from_species(species)
|
1155
|
+
return self.calculate_attack_ev_and_nature_combinations(total_attack, base_stats.attack, iv, level)
|
1156
|
+
|
1157
|
+
def calculate_defense_ev_and_nature_combinations_from_species(self, species: str, total_defense: int, iv: int, level: int = 100) -> List[Tuple[int, float]]:
|
1158
|
+
"""
|
1159
|
+
Calculate all possible Defense EV and nature modifier combinations using species name.
|
1160
|
+
|
1161
|
+
Args:
|
1162
|
+
species (str): Pokemon species name
|
1163
|
+
total_defense (int): Total Defense stat value
|
1164
|
+
iv (int): Individual Value (0-31)
|
1165
|
+
level (int): Pokemon level (1-100)
|
1166
|
+
|
1167
|
+
Returns:
|
1168
|
+
List[Tuple[int, float]]: List of (EV, nature_modifier) combinations
|
1169
|
+
"""
|
1170
|
+
base_stats = self.get_base_stats_from_species(species)
|
1171
|
+
return self.calculate_defense_ev_and_nature_combinations(total_defense, base_stats.defense, iv, level)
|
1172
|
+
|
1173
|
+
def calculate_special_attack_ev_and_nature_combinations_from_species(self, species: str, total_special_attack: int, iv: int, level: int = 100) -> List[Tuple[int, float]]:
|
1174
|
+
"""
|
1175
|
+
Calculate all possible Special Attack EV and nature modifier combinations using species name.
|
1176
|
+
|
1177
|
+
Args:
|
1178
|
+
species (str): Pokemon species name
|
1179
|
+
total_special_attack (int): Total Special Attack stat value
|
1180
|
+
iv (int): Individual Value (0-31)
|
1181
|
+
level (int): Pokemon level (1-100)
|
1182
|
+
|
1183
|
+
Returns:
|
1184
|
+
List[Tuple[int, float]]: List of (EV, nature_modifier) combinations
|
1185
|
+
"""
|
1186
|
+
base_stats = self.get_base_stats_from_species(species)
|
1187
|
+
return self.calculate_special_attack_ev_and_nature_combinations(total_special_attack, base_stats.special_attack, iv, level)
|
1188
|
+
|
1189
|
+
def calculate_special_defense_ev_and_nature_combinations_from_species(self, species: str, total_special_defense: int, iv: int, level: int = 100) -> List[Tuple[int, float]]:
|
1190
|
+
"""
|
1191
|
+
Calculate all possible Special Defense EV and nature modifier combinations using species name.
|
1192
|
+
|
1193
|
+
Args:
|
1194
|
+
species (str): Pokemon species name
|
1195
|
+
total_special_defense (int): Total Special Defense stat value
|
1196
|
+
iv (int): Individual Value (0-31)
|
1197
|
+
level (int): Pokemon level (1-100)
|
1198
|
+
|
1199
|
+
Returns:
|
1200
|
+
List[Tuple[int, float]]: List of (EV, nature_modifier) combinations
|
1201
|
+
"""
|
1202
|
+
base_stats = self.get_base_stats_from_species(species)
|
1203
|
+
return self.calculate_special_defense_ev_and_nature_combinations(total_special_defense, base_stats.special_defense, iv, level)
|
1204
|
+
|
1205
|
+
def calculate_speed_ev_and_nature_combinations_from_species(self, species: str, total_speed: int, iv: int, level: int = 100) -> List[Tuple[int, float]]:
|
1206
|
+
"""
|
1207
|
+
Calculate all possible Speed EV and nature modifier combinations using species name.
|
1208
|
+
|
1209
|
+
Args:
|
1210
|
+
species (str): Pokemon species name
|
1211
|
+
total_speed (int): Total Speed stat value
|
1212
|
+
iv (int): Individual Value (0-31)
|
1213
|
+
level (int): Pokemon level (1-100)
|
1214
|
+
|
1215
|
+
Returns:
|
1216
|
+
List[Tuple[int, float]]: List of (EV, nature_modifier) combinations
|
1217
|
+
"""
|
1218
|
+
base_stats = self.get_base_stats_from_species(species)
|
1219
|
+
return self.calculate_speed_ev_and_nature_combinations(total_speed, base_stats.speed, iv, level)
|
@@ -0,0 +1,196 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: localdex
|
3
|
+
Version: 0.2.45
|
4
|
+
Summary: A local Pokemon data repository/Pokedex with fast offline access
|
5
|
+
Author-email: LocalDex Team <localdex@example.com>
|
6
|
+
License: MIT
|
7
|
+
Project-URL: Homepage, https://github.com/colefoster/localdex
|
8
|
+
Project-URL: Documentation, https://localdex.readthedocs.io/
|
9
|
+
Project-URL: Repository, https://github.com/colefoster/localdex
|
10
|
+
Project-URL: Bug Tracker, https://github.com/colefoster/localdex/issues
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
12
|
+
Classifier: Intended Audience :: Developers
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
14
|
+
Classifier: Programming Language :: Python :: 3.8
|
15
|
+
Classifier: Programming Language :: Python :: 3.9
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
19
|
+
Classifier: Topic :: Games/Entertainment
|
20
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
21
|
+
Requires-Python: >=3.8
|
22
|
+
Description-Content-Type: text/markdown
|
23
|
+
License-File: LICENSE
|
24
|
+
Requires-Dist: requests
|
25
|
+
Requires-Dist: typing-extensions
|
26
|
+
Provides-Extra: core
|
27
|
+
Provides-Extra: gen1
|
28
|
+
Provides-Extra: gen2
|
29
|
+
Provides-Extra: gen3
|
30
|
+
Provides-Extra: gen4
|
31
|
+
Provides-Extra: gen5
|
32
|
+
Provides-Extra: gen6
|
33
|
+
Provides-Extra: gen7
|
34
|
+
Provides-Extra: gen8
|
35
|
+
Provides-Extra: gen9
|
36
|
+
Provides-Extra: learnsets
|
37
|
+
Provides-Extra: items
|
38
|
+
Provides-Extra: abilities
|
39
|
+
Provides-Extra: full
|
40
|
+
Requires-Dist: localdex[abilities,gen1,gen2,gen3,gen4,gen5,gen6,gen7,gen8,gen9,items,learnsets]; extra == "full"
|
41
|
+
Provides-Extra: dev
|
42
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
43
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
|
44
|
+
Requires-Dist: black>=22.0.0; extra == "dev"
|
45
|
+
Requires-Dist: isort>=5.0.0; extra == "dev"
|
46
|
+
Requires-Dist: mypy>=1.0.0; extra == "dev"
|
47
|
+
Requires-Dist: flake8>=5.0.0; extra == "dev"
|
48
|
+
Dynamic: license-file
|
49
|
+
|
50
|
+
# LocalDex
|
51
|
+
|
52
|
+
A fast, offline-first Python library for Pokemon data access. LocalDex provides comprehensive Pokemon information without requiring network requests.
|
53
|
+
|
54
|
+
[](https://badge.fury.io/py/localdex)
|
55
|
+
[](https://pypi.org/project/localdex/)
|
56
|
+
[](https://opensource.org/licenses/MIT)
|
57
|
+
|
58
|
+
## Features
|
59
|
+
|
60
|
+
- **Offline Access**: All data stored locally - no network requests required
|
61
|
+
- **Fast Lookups**: Optimized caching and search capabilities
|
62
|
+
- **Comprehensive Data**: Pokemon, moves, abilities, and items
|
63
|
+
- **CLI Interface**: Command-line access to all data
|
64
|
+
- **Type Hints**: Full type support for better development experience
|
65
|
+
- **Stat Calculations**: Built-in stat calculation methods
|
66
|
+
|
67
|
+
## Installation
|
68
|
+
|
69
|
+
```bash
|
70
|
+
pip install localdex
|
71
|
+
```
|
72
|
+
|
73
|
+
## Quick Start
|
74
|
+
|
75
|
+
```python
|
76
|
+
from localdex import LocalDex
|
77
|
+
|
78
|
+
# Initialize the dex
|
79
|
+
dex = LocalDex()
|
80
|
+
|
81
|
+
# Get Pokemon by name or ID
|
82
|
+
pikachu = dex.get_pokemon("pikachu")
|
83
|
+
charizard = dex.get_pokemon_by_id(6)
|
84
|
+
|
85
|
+
# Get moves and abilities
|
86
|
+
thunderbolt = dex.get_move("thunderbolt")
|
87
|
+
lightning_rod = dex.get_ability("lightning-rod")
|
88
|
+
|
89
|
+
# Search Pokemon
|
90
|
+
fire_types = dex.search_pokemon(type="fire")
|
91
|
+
fast_pokemon = dex.search_pokemon(min_speed=120)
|
92
|
+
legendary_fire = dex.search_pokemon(type="fire", is_legendary=True)
|
93
|
+
|
94
|
+
# Get all data
|
95
|
+
all_pokemon = dex.get_all_pokemon()
|
96
|
+
all_moves = dex.get_all_moves()
|
97
|
+
```
|
98
|
+
|
99
|
+
## CLI Usage
|
100
|
+
|
101
|
+
```bash
|
102
|
+
# Get Pokemon information
|
103
|
+
localdex pokemon pikachu
|
104
|
+
localdex pokemon 25
|
105
|
+
|
106
|
+
# Search Pokemon
|
107
|
+
localdex search --type Fire --generation 1
|
108
|
+
localdex search --legendary --min-attack 100
|
109
|
+
|
110
|
+
# Get move and ability info
|
111
|
+
localdex move thunderbolt
|
112
|
+
localdex ability lightningrod
|
113
|
+
|
114
|
+
# List data
|
115
|
+
localdex list-pokemon --generation 1
|
116
|
+
localdex list-moves --type Electric
|
117
|
+
|
118
|
+
# Export data
|
119
|
+
localdex export --format json --output pokemon_data.json
|
120
|
+
|
121
|
+
# Run demo
|
122
|
+
localdex demo
|
123
|
+
```
|
124
|
+
|
125
|
+
## API Reference
|
126
|
+
|
127
|
+
### Core Methods
|
128
|
+
|
129
|
+
- `get_pokemon(name_or_id)` - Get Pokemon by name or ID
|
130
|
+
- `get_pokemon_by_id(id)` - Get Pokemon by ID
|
131
|
+
- `get_pokemon_by_name(name)` - Get Pokemon by name
|
132
|
+
- `get_move(name)` - Get move by name
|
133
|
+
- `get_ability(name)` - Get ability by name
|
134
|
+
- `get_item(name)` - Get item by name
|
135
|
+
- `search_pokemon(**filters)` - Search Pokemon with filters
|
136
|
+
- `get_all_pokemon()` - Get all Pokemon
|
137
|
+
- `get_all_moves()` - Get all moves
|
138
|
+
- `get_all_abilities()` - Get all abilities
|
139
|
+
- `get_all_items()` - Get all items
|
140
|
+
|
141
|
+
### Search Filters
|
142
|
+
|
143
|
+
```python
|
144
|
+
# Available filters for search_pokemon()
|
145
|
+
dex.search_pokemon(
|
146
|
+
type="Fire", # Pokemon type
|
147
|
+
generation=1, # Generation number
|
148
|
+
is_legendary=True, # Legendary Pokemon
|
149
|
+
is_mythical=True, # Mythical Pokemon
|
150
|
+
min_attack=100, # Minimum attack stat
|
151
|
+
max_speed=50, # Maximum speed stat
|
152
|
+
name_contains="char" # Name contains text
|
153
|
+
)
|
154
|
+
```
|
155
|
+
|
156
|
+
### Data Models
|
157
|
+
|
158
|
+
```python
|
159
|
+
# Pokemon model
|
160
|
+
pokemon = dex.get_pokemon("pikachu")
|
161
|
+
print(f"{pokemon.name} - {pokemon.types}")
|
162
|
+
print(f"HP: {pokemon.base_stats.hp}")
|
163
|
+
print(f"Attack: {pokemon.base_stats.attack}")
|
164
|
+
|
165
|
+
# Move model
|
166
|
+
move = dex.get_move("thunderbolt")
|
167
|
+
print(f"{move.name} - Power: {move.base_power}, Type: {move.type}")
|
168
|
+
|
169
|
+
# Ability model
|
170
|
+
ability = dex.get_ability("lightning-rod")
|
171
|
+
print(f"{ability.name} - {ability.description}")
|
172
|
+
```
|
173
|
+
|
174
|
+
## Stat Calculations
|
175
|
+
|
176
|
+
LocalDex includes methods for calculating Pokemon stats:
|
177
|
+
|
178
|
+
```python
|
179
|
+
# Calculate stats with IVs, EVs, and level
|
180
|
+
hp = dex.get_hp_stat_from_species("pikachu", iv=31, ev=252, level=100)
|
181
|
+
attack = dex.get_attack_stat_from_species("pikachu", iv=31, ev=252, level=100)
|
182
|
+
|
183
|
+
# Generic stat calculation
|
184
|
+
hp = dex.calculate_hp(base=35, iv=31, ev=252, level=100)
|
185
|
+
attack = dex.calculate_other_stat(base=55, iv=31, ev=252, level=100, nature_modifier=1.1)
|
186
|
+
```
|
187
|
+
|
188
|
+
## License
|
189
|
+
|
190
|
+
MIT License - see [LICENSE](LICENSE) file for details.
|
191
|
+
|
192
|
+
## Data Sources
|
193
|
+
|
194
|
+
Data sourced from [Pokemon Showdown](https://github.com/smogon/pokemon-showdown) and [PokeAPI](https://pokeapi.co/).
|
195
|
+
|
196
|
+
|
@@ -1,6 +1,6 @@
|
|
1
1
|
localdex/__init__.py,sha256=TTeh9Eys8nLtcw7Dg2equDqnouthIUyfsqvABtzR2vA,403
|
2
2
|
localdex/cli.py,sha256=WqBCyA0akAFJNrYa8jCA3zoZgYEptDYDMGfAGkvKyZc,19317
|
3
|
-
localdex/core.py,sha256=
|
3
|
+
localdex/core.py,sha256=fXalY6GyZ94QhD_M0KW_l9tdhq-bb785O14sMmvzenI,54495
|
4
4
|
localdex/data_loader.py,sha256=hi9aSTto5Ti-OBGOgrQ-XwD5hmivsUwS1uC4rulhwQI,11366
|
5
5
|
localdex/download_data.py,sha256=T4A3OliGe2RsrRV1glyCqRcFhQIRt29KcY1K1-IqTuU,21597
|
6
6
|
localdex/exceptions.py,sha256=Z02-8Kci6jFDk2nnGdVSHZJMDDWE9vuwuASs4VM3To8,2777
|
@@ -4826,8 +4826,9 @@ localdex/models/ability.py,sha256=AQzv3XUHHl4sustMJjPDDjJOjXu2GMLTfcM3-tqQ_1w,30
|
|
4826
4826
|
localdex/models/item.py,sha256=zXao8F-jBPUGq_YLeGeYeK_dZVI7aZMXtWOPwR3qusY,4677
|
4827
4827
|
localdex/models/move.py,sha256=hfgcWI4ziz5MMvc9ddmkotxzYYdrSUqZZQ72IU5tucs,7629
|
4828
4828
|
localdex/models/pokemon.py,sha256=glnOiEhkFc25U54hJHwUkT-okUgtL2prg3269YXI3w0,5422
|
4829
|
-
localdex-0.2.
|
4830
|
-
localdex-0.2.
|
4831
|
-
localdex-0.2.
|
4832
|
-
localdex-0.2.
|
4833
|
-
localdex-0.2.
|
4829
|
+
localdex-0.2.45.dist-info/licenses/LICENSE,sha256=i6DyIs1YqXBAxAIiGBS6vp2iQP9tiMd47S8dvaeFmDQ,1065
|
4830
|
+
localdex-0.2.45.dist-info/METADATA,sha256=lbBlCaUAPBxN35SyxWC_Z9sIk-ScqhQEtGwT4JRJGOI,5886
|
4831
|
+
localdex-0.2.45.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
4832
|
+
localdex-0.2.45.dist-info/entry_points.txt,sha256=n5GxSeQo-MRuvrT2wVk7hOzEFFsWf6tkBjkzmGIYJe4,47
|
4833
|
+
localdex-0.2.45.dist-info/top_level.txt,sha256=vtupDMH-IaxVCoEZrmE0QzdTwhaKzngVJbTA1NkR_MY,9
|
4834
|
+
localdex-0.2.45.dist-info/RECORD,,
|
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2025 LocalDex
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
@@ -1,270 +0,0 @@
|
|
1
|
-
Metadata-Version: 2.4
|
2
|
-
Name: localdex
|
3
|
-
Version: 0.2.40
|
4
|
-
Summary: A local Pokemon data repository/Pokedex with fast offline access
|
5
|
-
Author-email: LocalDex Team <localdex@example.com>
|
6
|
-
License: MIT
|
7
|
-
Project-URL: Homepage, https://github.com/colefoster/localdex
|
8
|
-
Project-URL: Documentation, https://localdex.readthedocs.io/
|
9
|
-
Project-URL: Repository, https://github.com/colefoster/localdex
|
10
|
-
Project-URL: Bug Tracker, https://github.com/colefoster/localdex/issues
|
11
|
-
Classifier: Development Status :: 3 - Alpha
|
12
|
-
Classifier: Intended Audience :: Developers
|
13
|
-
Classifier: Programming Language :: Python :: 3
|
14
|
-
Classifier: Programming Language :: Python :: 3.8
|
15
|
-
Classifier: Programming Language :: Python :: 3.9
|
16
|
-
Classifier: Programming Language :: Python :: 3.10
|
17
|
-
Classifier: Programming Language :: Python :: 3.11
|
18
|
-
Classifier: Programming Language :: Python :: 3.12
|
19
|
-
Classifier: Topic :: Games/Entertainment
|
20
|
-
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
21
|
-
Requires-Python: >=3.8
|
22
|
-
Description-Content-Type: text/markdown
|
23
|
-
Requires-Dist: requests
|
24
|
-
Requires-Dist: typing-extensions
|
25
|
-
Provides-Extra: core
|
26
|
-
Provides-Extra: gen1
|
27
|
-
Provides-Extra: gen2
|
28
|
-
Provides-Extra: gen3
|
29
|
-
Provides-Extra: gen4
|
30
|
-
Provides-Extra: gen5
|
31
|
-
Provides-Extra: gen6
|
32
|
-
Provides-Extra: gen7
|
33
|
-
Provides-Extra: gen8
|
34
|
-
Provides-Extra: gen9
|
35
|
-
Provides-Extra: learnsets
|
36
|
-
Provides-Extra: items
|
37
|
-
Provides-Extra: abilities
|
38
|
-
Provides-Extra: full
|
39
|
-
Requires-Dist: localdex[abilities,gen1,gen2,gen3,gen4,gen5,gen6,gen7,gen8,gen9,items,learnsets]; extra == "full"
|
40
|
-
Provides-Extra: dev
|
41
|
-
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
42
|
-
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
|
43
|
-
Requires-Dist: black>=22.0.0; extra == "dev"
|
44
|
-
Requires-Dist: isort>=5.0.0; extra == "dev"
|
45
|
-
Requires-Dist: mypy>=1.0.0; extra == "dev"
|
46
|
-
Requires-Dist: flake8>=5.0.0; extra == "dev"
|
47
|
-
|
48
|
-
# LocalDex
|
49
|
-
|
50
|
-
A fast, offline-first Python library for Pokemon data access. LocalDex provides comprehensive Pokemon information without requiring network requests, making it perfect for applications that need reliable, fast access to Pokemon data.
|
51
|
-
|
52
|
-
[](https://badge.fury.io/py/localdex)
|
53
|
-
[](https://pypi.org/project/localdex/)
|
54
|
-
[](https://opensource.org/licenses/MIT)
|
55
|
-
[](https://github.com/colefoster/localdex/actions/workflows/release.yml)
|
56
|
-
|
57
|
-
## Features
|
58
|
-
|
59
|
-
- **100% Offline**: All data is stored locally - no network requests required
|
60
|
-
- **Fast Access**: Optimized for quick lookups and searches
|
61
|
-
- **Comprehensive Data**: Pokemon, moves, abilities, items, and more
|
62
|
-
- **Flexible Installation**: Choose which data sets to include
|
63
|
-
- **Type Hints**: Full type support for better development experience
|
64
|
-
- **Multiple Generations**: Support for all Pokemon generations
|
65
|
-
- **Competitive Data**: Includes battle sets and competitive information
|
66
|
-
|
67
|
-
## Installation
|
68
|
-
|
69
|
-
### Basic Installation
|
70
|
-
|
71
|
-
```bash
|
72
|
-
pip install localdex
|
73
|
-
```
|
74
|
-
|
75
|
-
### Selective Data Installation
|
76
|
-
|
77
|
-
Install only the data you need to minimize package size:
|
78
|
-
|
79
|
-
```bash
|
80
|
-
# Core Pokemon data only
|
81
|
-
pip install localdex[core]
|
82
|
-
|
83
|
-
# Specific generation
|
84
|
-
pip install localdex[gen1] # Generation 1 only
|
85
|
-
pip install localdex[gen9] # Generation 9 only
|
86
|
-
|
87
|
-
# Additional data sets
|
88
|
-
pip install localdex[competitive] # Competitive battle data
|
89
|
-
pip install localdex[learnsets] # Detailed move learnsets
|
90
|
-
pip install localdex[items] # Item data
|
91
|
-
pip install localdex[abilities] # Ability data
|
92
|
-
|
93
|
-
# Full installation with everything
|
94
|
-
pip install localdex[full]
|
95
|
-
```
|
96
|
-
|
97
|
-
|
98
|
-
## Quick Start
|
99
|
-
|
100
|
-
```python
|
101
|
-
from localdex import LocalDex
|
102
|
-
|
103
|
-
# Initialize the dex
|
104
|
-
dex = LocalDex()
|
105
|
-
|
106
|
-
# Get Pokemon by name
|
107
|
-
pikachu = dex.get_pokemon("pikachu")
|
108
|
-
print(f"{pikachu.name} - {pikachu.types}")
|
109
|
-
|
110
|
-
# Get Pokemon by ID
|
111
|
-
charizard = dex.get_pokemon_by_id(6)
|
112
|
-
print(f"{charizard.name} - HP: {charizard.base_stats.hp}")
|
113
|
-
|
114
|
-
# Get Pokemon stats
|
115
|
-
bulbasaur = dex.get_pokemon("bulbasaur")
|
116
|
-
print(f"{bulbasaur.name} - Attack: {bulbasaur.base_stats.attack}, Speed: {bulbasaur.base_stats.speed}")
|
117
|
-
|
118
|
-
# Get moves
|
119
|
-
thunderbolt = dex.get_move("thunderbolt")
|
120
|
-
print(f"{thunderbolt.name} - Power: {thunderbolt.base_power}, Type: {thunderbolt.type}")
|
121
|
-
|
122
|
-
# Get abilities (note: use dashes in names like "lightning-rod")
|
123
|
-
lightning_rod = dex.get_ability("lightning-rod")
|
124
|
-
print(f"{lightning_rod.name} - {lightning_rod.description}")
|
125
|
-
|
126
|
-
# Search Pokemon by type (case-insensitive)
|
127
|
-
fire_types = dex.search_pokemon(type="fire")
|
128
|
-
print(f"Fire type Pokemon: {[p.name for p in fire_types[:5]]}")
|
129
|
-
|
130
|
-
# Search Pokemon by stat
|
131
|
-
fast_pokemon = dex.search_pokemon(min_speed=120)
|
132
|
-
print(f"Very fast Pokemon: {[p.name for p in fast_pokemon[:5]]}")
|
133
|
-
|
134
|
-
# Get all moves of a specific type (case-insensitive)
|
135
|
-
all_moves = dex.get_all_moves()
|
136
|
-
electric_moves = [m for m in all_moves if m.type.lower() == "electric"]
|
137
|
-
print(f"Electric moves count: {len(electric_moves)}")
|
138
|
-
print(f"First 5 Electric moves: {[m.name for m in electric_moves[:5]]}")
|
139
|
-
|
140
|
-
## API Reference
|
141
|
-
|
142
|
-
### LocalDex Class
|
143
|
-
|
144
|
-
The main class for accessing Pokemon data.
|
145
|
-
|
146
|
-
#### Methods
|
147
|
-
|
148
|
-
- `get_pokemon(name_or_id: Union[str, int]) -> Pokemon`: Get Pokemon by name or ID
|
149
|
-
- `get_pokemon_by_id(id: int) -> Pokemon`: Get Pokemon by ID
|
150
|
-
- `get_pokemon_by_name(name: str) -> Pokemon`: Get Pokemon by name
|
151
|
-
- `search_pokemon(**filters) -> List[Pokemon]`: Search Pokemon with filters
|
152
|
-
- `get_move(name: str) -> Move`: Get move by name
|
153
|
-
- `get_ability(name: str) -> Ability`: Get ability by name
|
154
|
-
- `get_item(name: str) -> Item`: Get item by name
|
155
|
-
- `get_all_pokemon() -> List[Pokemon]`: Get all Pokemon
|
156
|
-
- `get_all_moves() -> List[Move]`: Get all moves
|
157
|
-
- `get_all_abilities() -> List[Ability]`: Get all abilities
|
158
|
-
- `get_all_items() -> List[Item]`: Get all items
|
159
|
-
|
160
|
-
#### Search Filters
|
161
|
-
|
162
|
-
```python
|
163
|
-
# Search by type
|
164
|
-
fire_pokemon = dex.search_pokemon(type="Fire")
|
165
|
-
|
166
|
-
# Search by generation
|
167
|
-
gen1_pokemon = dex.search_pokemon(generation=1)
|
168
|
-
|
169
|
-
# Search by multiple criteria
|
170
|
-
legendary_fire = dex.search_pokemon(type="Fire", is_legendary=True)
|
171
|
-
|
172
|
-
# Search by base stat range
|
173
|
-
strong_pokemon = dex.search_pokemon(min_attack=100)
|
174
|
-
```
|
175
|
-
|
176
|
-
### Data Models
|
177
|
-
|
178
|
-
#### Pokemon
|
179
|
-
|
180
|
-
```python
|
181
|
-
class Pokemon:
|
182
|
-
id: int
|
183
|
-
name: str
|
184
|
-
types: List[str]
|
185
|
-
base_stats: BaseStats
|
186
|
-
abilities: Dict[str, Ability]
|
187
|
-
moves: List[Move]
|
188
|
-
height: float
|
189
|
-
weight: float
|
190
|
-
description: str
|
191
|
-
# ... and more
|
192
|
-
```
|
193
|
-
|
194
|
-
#### Move
|
195
|
-
|
196
|
-
```python
|
197
|
-
class Move:
|
198
|
-
name: str
|
199
|
-
type: str
|
200
|
-
category: str
|
201
|
-
base_power: int
|
202
|
-
accuracy: int
|
203
|
-
pp: int
|
204
|
-
description: str
|
205
|
-
# ... and more
|
206
|
-
```
|
207
|
-
|
208
|
-
#### Ability
|
209
|
-
|
210
|
-
```python
|
211
|
-
class Ability:
|
212
|
-
name: str
|
213
|
-
description: str
|
214
|
-
short_description: str
|
215
|
-
# ... and more
|
216
|
-
```
|
217
|
-
|
218
|
-
## Data Sets
|
219
|
-
|
220
|
-
LocalDex organizes data into logical sets that can be installed independently:
|
221
|
-
|
222
|
-
### Core Data (`core`)
|
223
|
-
- Basic Pokemon information (name, types, base stats)
|
224
|
-
- Essential for most applications
|
225
|
-
|
226
|
-
### Generation Data (`gen1`-`gen9`)
|
227
|
-
- Pokemon data for specific generations
|
228
|
-
- Useful for generation-specific applications
|
229
|
-
|
230
|
-
### Additional Data Sets
|
231
|
-
- **Competitive** (`competitive`): Battle sets and competitive data
|
232
|
-
- **Learnsets** (`learnsets`): Detailed move learning information
|
233
|
-
- **Items** (`items`): Item data and effects
|
234
|
-
- **Abilities** (`abilities`): Detailed ability information
|
235
|
-
|
236
|
-
## CLI Usage
|
237
|
-
|
238
|
-
LocalDex includes a command-line interface for quick data access:
|
239
|
-
|
240
|
-
```bash
|
241
|
-
# Get Pokemon information
|
242
|
-
localdex pokemon pikachu
|
243
|
-
|
244
|
-
# Search Pokemon
|
245
|
-
localdex search --type Fire --generation 1
|
246
|
-
|
247
|
-
# Get move information
|
248
|
-
localdex move thunderbolt
|
249
|
-
|
250
|
-
# Get ability information
|
251
|
-
localdex ability lightningrod
|
252
|
-
|
253
|
-
# List all Pokemon
|
254
|
-
localdex list-pokemon
|
255
|
-
|
256
|
-
# Export data to JSON
|
257
|
-
localdex export --format json --output pokemon_data.json
|
258
|
-
```
|
259
|
-
|
260
|
-
## License
|
261
|
-
|
262
|
-
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
263
|
-
|
264
|
-
## Data Sources
|
265
|
-
|
266
|
-
LocalDex uses data from:
|
267
|
-
- [Pokemon Showdown](https://github.com/smogon/pokemon-showdown)
|
268
|
-
- [PokeAPI](https://pokeapi.co/) (for initial data collection)
|
269
|
-
|
270
|
-
|
File without changes
|
File without changes
|
File without changes
|