localdex 0.2.47__py3-none-any.whl → 0.2.49__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 CHANGED
@@ -549,671 +549,9 @@ class LocalDex:
549
549
  "abilities": len(self._ability_cache),
550
550
  "items": len(self._item_cache)
551
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
552
 
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)
1064
-
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)
553
+ @property
554
+ def stats(self):
555
+ """Access to stat calculation functionality."""
556
+ from .stat_calculator import StatCalculator
557
+ return StatCalculator(self)