diff --git a/example.py b/example.py new file mode 100644 index 0000000..2404e74 --- /dev/null +++ b/example.py @@ -0,0 +1,45 @@ +__author__ = "Lukas Mahler" +__version__ = "0.0.0" +__date__ = "26.06.2023" +__email__ = "m@hler.eu" +__status__ = "Development" + + +from src.FadeCalculator import FadeCalculator +from src.AmberFadeCalculator import AmberFadeCalculator +from src.AcidFadeCalculator import AcidFadeCalculator + + +def main(): + """ + Showcasing example usage + """ + + # Create an instances of the calculators + fade_calc = FadeCalculator() + amber_calc = AmberFadeCalculator() + acid_calc = AcidFadeCalculator() + + # Get list of supported weapons + print("Supported weapons in fade calculator: ", fade_calc.get_supported_weapons()) + print("Supported weapons in amber fade calculator:", amber_calc.get_supported_weapons()) + print("Supported weapons in acid fade calculator: ", acid_calc.get_supported_weapons()) + + # Get the fade percentages for a specific weapon and seed + fade = fade_calc.get_fade_percentage(weapon := "AWP", 42) + print(f"Base fade percentage for [{weapon:>10s}] " + f"with seed: {fade.seed:4d} is {fade.percentage:6.2f}% / ranked: {fade.ranking:4d}") + + # Get the amber fade percentages for a specific weapon and seed + fade = amber_calc.get_fade_percentage(weapon := "AUG", 42) + print(f"Amber fade percentage for [{weapon:>10s}] " + f"with seed: {fade.seed:4d} is {fade.percentage:6.2f}% / ranked: {fade.ranking:4d}") + + # Get the acid fade percentages for a specific weapon and seed + fade = acid_calc.get_fade_percentage(weapon := "SSG 08", 42) + print(f"Acid fade percentage for [{weapon:>10s}] " + f"with seed: {fade.seed:4d} is {fade.percentage:6.2f}% / ranked: {fade.ranking:4d}") + + +if __name__ == '__main__': + main() diff --git a/src/AcidFadeCalculator.py b/src/AcidFadeCalculator.py new file mode 100644 index 0000000..1ed5b3c --- /dev/null +++ b/src/AcidFadeCalculator.py @@ -0,0 +1,40 @@ +__author__ = "Lukas Mahler" +__version__ = "0.0.0" +__date__ = "26.06.2023" +__email__ = "m@hler.eu" +__status__ = "Development" + + +from src.BaseCalculator import BaseCalculator + + +class AcidFadeCalculator(BaseCalculator): + + def __init__(self): + + super().__init__() + + self.weapons = [ + 'SSG 08', + ] + + self.reversed_weapons = [] + + self.trade_up_weapons = [ + 'SSG 08', + ] + + self.configs = { + 'default': { + 'pattern_offset_x_start': -2.4, + 'pattern_offset_x_end': -2.1, + 'pattern_offset_y_start': 0.0, + 'pattern_offset_y_end': 0.0, + 'pattern_rotate_start': -55, + 'pattern_rotate_end': -65, + } + } + + +if __name__ == '__main__': + exit(1) diff --git a/src/AmberFadeCalculator.py b/src/AmberFadeCalculator.py new file mode 100644 index 0000000..ac7d702 --- /dev/null +++ b/src/AmberFadeCalculator.py @@ -0,0 +1,50 @@ +__author__ = "Lukas Mahler" +__version__ = "0.0.0" +__date__ = "26.06.2023" +__email__ = "m@hler.eu" +__status__ = "Development" + + +from src.BaseCalculator import BaseCalculator + + +class AmberFadeCalculator(BaseCalculator): + + def __init__(self): + + super().__init__() + + self.weapons = [ + 'AUG', + 'Galil AR', + 'MAC-10', + 'P2000', + 'R8 Revolver', + 'Sawed-Off', + ] + + self.reversed_weapons = [] + + self.trade_up_weapons = [ + 'AUG', + 'Galil AR', + 'MAC-10', + 'P2000', + 'R8 Revolver', + 'Sawed-Off', + ] + + self.configs = { + 'default': { + 'pattern_offset_x_start': -0.7, + 'pattern_offset_x_end': -0.7, + 'pattern_offset_y_start': -0.7, + 'pattern_offset_y_end': -0.7, + 'pattern_rotate_start': -55, + 'pattern_rotate_end': -65, + } + } + + +if __name__ == '__main__': + exit(1) diff --git a/src/BaseCalculator.py b/src/BaseCalculator.py new file mode 100644 index 0000000..065f3d9 --- /dev/null +++ b/src/BaseCalculator.py @@ -0,0 +1,105 @@ +__author__ = "Lukas Mahler" +__version__ = "0.0.0" +__date__ = "26.06.2023" +__email__ = "m@hler.eu" +__status__ = "Development" + + +from src.RandomNumberGenerator import RandomNumberGenerator + + +class FadePercentage: + def __init__(self, seed, percentage, ranking): + self.seed = seed + self.percentage = percentage + self.ranking = ranking + + +class WeaponFadePercentage: + def __init__(self, weapon, percentages): + self.weapon = weapon + self.percentages = percentages + + +class BaseCalculator: + def __init__(self): + self.weapons = [] + self.reversed_weapons = [] + self.trade_up_weapons = [] + self.configs = {} + self.min_percentage = 80 + + def get_supported_weapons(self): + return self.weapons + + def get_fade_percentage(self, weapon, seed): + percentages = self.get_fade_percentages(weapon) + return percentages[seed] + + def get_all_fade_percentages(self): + return [ + WeaponFadePercentage(weapon, self.get_fade_percentages(weapon)) + for weapon in self.weapons + ] + + def get_fade_percentages(self, weapon): + if weapon not in self.weapons: + raise ValueError(f'The weapon "{weapon}" is currently not supported.') + + config = self.configs.get(weapon, self.configs['default']) + + raw_results = [] + + max_seed = 1000 if weapon in self.trade_up_weapons else 999 + + for i in range(max_seed + 1): + random_number_generator = RandomNumberGenerator() + random_number_generator.set_seed(i) + + x_offset = random_number_generator.random_float( + config['pattern_offset_x_start'], config['pattern_offset_x_end'] + ) + + random_number_generator.random_float( + config['pattern_offset_y_start'], config['pattern_offset_y_end'] + ) + + rotation = random_number_generator.random_float( + config['pattern_rotate_start'], config['pattern_rotate_end'] + ) + + if config['pattern_offset_x_start'] != config['pattern_offset_x_end']: + raw_result = rotation * x_offset + else: + raw_result = rotation + + raw_results.append(abs(raw_result)) + + is_reversed = weapon in self.reversed_weapons + + if is_reversed: + best_result = max(raw_results) + worst_result = min(raw_results) + else: + best_result = min(raw_results) + worst_result = max(raw_results) + + result_range = worst_result - best_result + + percentage_results = [ + (worst_result - raw_result) / result_range + for raw_result in raw_results + ] + + sorted_percentage_results = sorted(percentage_results) + + return [ + FadePercentage(i, self.min_percentage + (percentage_result * (100 - self.min_percentage)), + min(sorted_percentage_results.index(percentage_result) + 1, + len(sorted_percentage_results) - sorted_percentage_results.index(percentage_result))) + for i, percentage_result in enumerate(percentage_results) + ] + + +if __name__ == '__main__': + exit(1) diff --git a/src/FadeCalculator.py b/src/FadeCalculator.py new file mode 100644 index 0000000..6c527ca --- /dev/null +++ b/src/FadeCalculator.py @@ -0,0 +1,81 @@ +__author__ = "Lukas Mahler" +__version__ = "0.0.0" +__date__ = "26.06.2023" +__email__ = "m@hler.eu" +__status__ = "Development" + + +from src.BaseCalculator import BaseCalculator + + +class FadeCalculator(BaseCalculator): + + def __init__(self): + + super().__init__() + + self.weapons = [ + 'AWP', + 'Bayonet', + 'Bowie Knife', + 'Butterfly Knife', + 'Classic Knife', + 'Falchion Knife', + 'Flip Knife', + 'Glock-18', + 'Gut Knife', + 'Huntsman Knife', + 'Karambit', + 'M9 Bayonet', + 'MAC-10', + 'MP7', + 'Navaja Knife', + 'Nomad Knife', + 'Paracord Knife', + 'R8 Revolver', + 'Shadow Daggers', + 'Skeleton Knife', + 'Stiletto Knife', + 'Survival Knife', + 'Talon Knife', + 'UMP-45', + 'Ursus Knife' + ] + + self.reversed_weapons = [ + 'AWP', + 'Karambit', + 'Talon Knife' + ] + + self.trade_up_weapons = [ + 'AWP', + 'Glock-18', + 'MAC-10', + 'MP7', + 'R8 Revolver', + 'UMP-45' + ] + + self.configs = { + 'default': { + 'pattern_offset_x_start': -0.7, + 'pattern_offset_x_end': -0.7, + 'pattern_offset_y_start': -0.7, + 'pattern_offset_y_end': -0.7, + 'pattern_rotate_start': -55, + 'pattern_rotate_end': -65 + }, + 'MP7': { + 'pattern_offset_x_start': -0.9, + 'pattern_offset_x_end': -0.3, + 'pattern_offset_y_start': -0.7, + 'pattern_offset_y_end': -0.5, + 'pattern_rotate_start': -55, + 'pattern_rotate_end': -65 + } + } + + +if __name__ == '__main__': + exit(1) diff --git a/src/RandomNumberGenerator.py b/src/RandomNumberGenerator.py new file mode 100644 index 0000000..6310088 --- /dev/null +++ b/src/RandomNumberGenerator.py @@ -0,0 +1,108 @@ +__author__ = "Lukas Mahler" +__version__ = "0.0.0" +__date__ = "26.06.2023" +__email__ = "m@hler.eu" +__status__ = "Development" + + +import math + + +class RandomNumberGenerator: + """ + Initializes a RandomNumberGenerator object. + + The RandomNumberGenerator uses the parameters IA, IM, IQ, IR, NTAB, AM, and RNMX + to generate random numbers based on a seed value. + """ + + def __init__(self): + self.mIdum = 0 + self.mIy = 0 + + self.NTAB = 32 + self.mIv = [0] * self.NTAB # Initialize mIv with zeros + + self.IA = 16807 + self.IM = 2147483647 + self.IQ = 127773 + self.IR = 2836 + self.NDIV = 1 + (self.IM - 1) // self.NTAB + self.AM = 1.0 / self.IM + self.RNMX = 1.0 - 1.2e-7 + + def set_seed(self, seed): + """ + Sets the seed value for the random number generator. + + :param seed: The seed value to initialize the random number generator. + :type seed: int + """ + + self.mIdum = seed + + if seed >= 0: + self.mIdum = -seed + + self.mIy = 0 + + def random_number(self): + """ + Generates a random integer using the current seed value. + + :return: A random integer value. + :rtype: int + """ + + if self.mIdum <= 0 or self.mIy == 0: + if -self.mIdum < 1: + self.mIdum = 1 + else: + self.mIdum = -self.mIdum + + for j in range(self.NTAB + 7, -1, -1): + k = self.mIdum // self.IQ + self.mIdum = self.IA * (self.mIdum - k * self.IQ) - self.IR * k + + if self.mIdum < 0: + self.mIdum += self.IM + + if j < self.NTAB: + self.mIv[j] = self.mIdum + + self.mIy = self.mIv[0] + + k = self.mIdum // self.IQ + self.mIdum = self.IA * (self.mIdum - k * self.IQ) - self.IR * k + + if self.mIdum < 0: + self.mIdum += self.IM + + j = self.mIy // self.NDIV + self.mIy = self.mIv[j] + self.mIv[j] = self.mIdum + + return self.mIy + + def random_float(self, low, high): + """ + Generates a random float between the given low and high values. + + :param low: The lower bound of the random float. + :type low: float + :param high: The upper bound of the random float. + :type high: float + :return: A random float value between low and high (inclusive). + :rtype: float + """ + + float_val = self.AM * self.random_number() + + if float_val > self.RNMX: + float_val = self.RNMX + + return (float_val * (high - low)) + low + + +if __name__ == '__main__': + exit(1)