Skip to content

Instantly share code, notes, and snippets.

@Grayfox96
Last active November 21, 2021 13:45
Show Gist options
  • Save Grayfox96/c683678097d6e316a305bea6093b7df8 to your computer and use it in GitHub Desktop.
Save Grayfox96/c683678097d6e316a305bea6093b7df8 to your computer and use it in GitHub Desktop.
from typing import List, Optional
AURON_DAMAGE_VALUES = (
(
260, 261, 262, 263, 264, 266, 267, 268, 269, 270, 271,
272, 273, 274, 275, 276, 278, 279, 280, 281, 282, 283,
284, 285, 286, 287, 288, 289, 291, 292, 293, 294
),
(
520, 522, 524, 526, 528, 532, 534, 536, 538, 540, 542,
544, 546, 548, 550, 552, 556, 558, 560, 562, 564, 566,
568, 570, 572, 574, 576, 578, 582, 584, 586, 588
)
)
TIDUS_DAMAGE_VALUES = (
(
125, 126, 127, 128, 129, 130, 131, 132, 133,
134, 135, 136, 137, 138, 139, 140, 141
),
(
250, 252, 254, 256, 258, 260, 262, 264, 266,
268, 270, 272, 274, 276, 278, 280, 282
)
)
def get_input() -> List[int]:
while True:
input_string = input('Damage values (ATATATAA):')
for symbol in (',', '-', '/', '\\'):
input_string = input_string.replace(symbol, ' ')
damage_values = input_string.split()
try:
damage_values = [int(i) for i in damage_values]
except ValueError as error:
error = str(error).split(':', 1)[1]
print(f'{error} is not a valid damage value.')
continue
damage_values = damage_values[:8]
if len(damage_values) < 8:
print('Need at least 8 damage values.')
continue
damage_values_check = (
('Auron', AURON_DAMAGE_VALUES, damage_values[0]),
('Tidus', TIDUS_DAMAGE_VALUES, damage_values[1]),
('Auron', AURON_DAMAGE_VALUES, damage_values[2]),
('Tidus', TIDUS_DAMAGE_VALUES, damage_values[3]),
('Auron', AURON_DAMAGE_VALUES, damage_values[4]),
('Tidus', TIDUS_DAMAGE_VALUES, damage_values[5]),
('Auron', AURON_DAMAGE_VALUES, damage_values[6]),
('Auron', AURON_DAMAGE_VALUES, damage_values[7]),
)
damage_values_indexes = []
for character, damage_values_list, damage_value in damage_values_check:
try:
damage_values_indexes.append(
damage_values_list[0].index(damage_value))
except ValueError:
try:
damage_values_indexes.append(
damage_values_list[1].index(damage_value))
except ValueError:
print(
f'Invalid damage value for {character}: {damage_value}')
if len(damage_values_indexes) != 8:
continue
print('Damage values:', ', '.join([str(d) for d in damage_values]))
print(damage_values_indexes)
return damage_values_indexes
def find_seed(damage_values_as_str: str) -> Optional[int]:
with open('ffx_ps2_damage_rolls.dat') as file:
damage_values = file.read()
damage_values = damage_values.split('\n')
try:
seed_index = damage_values.index(damage_values_as_str)
except ValueError:
return
with open('ffx_ps2_seeds.dat') as file:
seeds = file.read()
seeds = seeds.split('\n')
return int(seeds[seed_index])
def main():
damage_values_indexes = get_input()
damage_values_as_str = ''.join([f'{n:02}' for n in damage_values_indexes])
if (seed := find_seed(damage_values_as_str)) is not None:
print('Seed:', seed)
else:
print('Seed not found')
if __name__ =='__main__':
main()
input('Press enter to quit...')
from typing import List
TIDUS_DAMAGE_VALUES = (
125, 126, 126, 127, 127, 128, 128, 129, 129, 130, 130,
131, 131, 132, 132, 133, 134, 134, 135, 135, 136, 136,
137, 137, 138, 138, 139, 139, 140, 140, 141, 141
)
TIDUS_DAMAGE_TO_INDEX = (
125, 126, 127, 128, 129, 130, 131, 132, 133,
134, 135, 136, 137, 138, 139, 140, 141
)
RNG_CONSTANTS_1 = (
2100005341, 1700015771, 247163863, 891644838, 1352476256,
1563244181, 1528068162, 511705468, 1739927914, 398147329,
1278224951, 20980264, 1178761637, 802909981, 1130639188,
1599606659, 952700148, -898770777, -1097979074, -2013480859,
-338768120, -625456464, -2049746478, -550389733, -5384772,
-128808769, -1756029551, 1379661854, 904938180, -1209494558,
-1676357703, -1287910319, 1653802906, 393811311, -824919740,
1837641861, 946029195, 1248183957, -1684075875, -2108396259,
-681826312, 1003979812, 1607786269, -585334321, 1285195346,
1997056081, -106688232, 1881479866, 476193932, 307456100,
1290745818, 162507240, -213809065, -1135977230, -1272305475,
1484222417, -1559875058, 1407627502, 1206176750, -1537348094,
638891383, 581678511, 1164589165, -1436620514, 1412081670,
-1538191350, -284976976, 706005400
)
RNG_CONSTANTS_2 = (
10259, 24563, 11177, 56952, 46197, 49826, 27077, 1257, 44164,
56565, 31009, 46618, 64397, 46089, 58119, 13090, 19496, 47700,
21163, 16247, 574, 18658, 60495, 42058, 40532, 13649, 8049,
25369, 9373, 48949, 23157, 32735, 29605, 44013, 16623, 15090,
43767, 51346, 28485, 39192, 40085, 32893, 41400, 1267, 15436,
33645, 37189, 58137, 16264, 59665, 53663, 11528, 37584, 18427,
59827, 49457, 22922, 24212, 62787, 56241, 55318, 9625, 57622,
7580, 56469, 49208, 41671, 36458
)
def s32(integer: int) -> int:
return ((integer & 0xffffffff) ^ 0x80000000) - 0x80000000
def rng_array_generator(rng_value: int) -> List[int]:
rng_value = s32(rng_value)
starting_values = []
for rng_index in range(23):
rng_value = s32(s32(rng_value * 0x5d588b65) + 0x3c35)
rng_value = s32((rng_value >> 0x10) + (rng_value << 0x10))
starting_values.append(rng_value & 0x7fffffff)
return starting_values
def get_rng_array(starting_value: int, rng_index: int, amount: int):
rng_value = s32(starting_value)
rng_constant_1 = RNG_CONSTANTS_1[rng_index]
rng_constant_2 = RNG_CONSTANTS_2[rng_index]
values = []
for _ in range(amount):
rng_value = s32(rng_value * rng_constant_1 ^ rng_constant_2)
rng_value = s32((rng_value >> 0x10) + (rng_value << 0x10))
values.append(rng_value & 0x7fffffff)
return values
def datetime_to_seed(datetime: int, frames: int) -> int:
seed = s32((datetime + 1) * (s32(frames) + 1))
seed = s32(s32(seed * 1108104919) + 11786)
seed = s32(s32(seed * 1566083941) + 15413)
seed = s32(s32(seed >> 16) + s32(seed << 16))
if seed >= 0:
return seed
else:
return 0x100000000 + seed
def main() -> None:
try:
minutes = int(input('Number of minutes (2 as default):'))
except ValueError:
minutes = 2
frames = minutes * 60 * 60
print('Calculating damage rolls for every possible seed'
f' up to frame {frames}.')
damage_rolls = []
seeds = []
for frame in range(frames):
if frame % 60 == 0:
print(f'\r{frame}/{frames}', end='')
for datetime in range(256):
seed = datetime_to_seed(datetime, frame)
starting_values = rng_array_generator(seed)
auron_rolls = get_rng_array(starting_values[22], 22, 37)
tidus_rolls = get_rng_array(starting_values[20], 20, 7)
numbers = []
# first encounter
# get 3 damage rolls from auron
# and 3 damage rolls from tidus
for i in range(1, 6, 2):
numbers.append(auron_rolls[i] & 31)
tidus_damage_roll = TIDUS_DAMAGE_VALUES[tidus_rolls[i] & 31]
numbers.append(TIDUS_DAMAGE_TO_INDEX.index(tidus_damage_roll))
# second encounter after dragon fang
# get 2 damage rolls from auron
for i in range(32, 35, 2):
numbers.append(auron_rolls[i] & 31)
numbers = ''.join([f'{n:02}' for n in numbers])
seeds.append(str(seed))
damage_rolls.append(numbers)
print(f'\r{frames}/{frames}')
with open('ffx_ps2_seeds.dat', 'w') as file:
file.write('\n'.join(seeds))
with open('ffx_ps2_damage_rolls.dat', 'w') as file:
file.write('\n'.join(damage_rolls))
input('Done!')
if __name__ =='__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment