-
-
Save furrtek/36816e29565e6fd1626392e1f07e5f43 to your computer and use it in GitHub Desktop.
# NGP Horoscope simulator v1.1 | |
# furrtek 2021 | |
# Based on algorithm found in ngp_bios.bin | |
import sys | |
from datetime import datetime | |
if len(sys.argv) == 1: | |
print(sys.argv[0] + " DD/MM/YYYY") | |
exit() | |
dob = datetime.strptime(sys.argv[1], '%d/%m/%Y') | |
current_date = datetime.today() | |
current_day = current_date.day | |
current_month = current_date.month | |
current_year = current_date.year | |
dob_day = dob.day | |
dob_month = dob.month | |
dob_year = dob.year | |
# 0 is Sunday | |
weekday = (datetime(current_year, current_month, current_day).weekday() + 1) % 7 | |
#print("Weekday: %d" % weekday) | |
# January to December | |
zodiac_days = [20, 19, 21, 20, 21, 22, 23, 23, 23, 24, 23, 22] | |
zodiac_signs = [ | |
"Aquarius", | |
"Pisces", | |
"Aries", | |
"Taurus", | |
"Gemini", | |
"Cancer", | |
"Leo", | |
"Virgo", | |
"Libra", | |
"Scorpio", | |
"Sagittarius", | |
"Capricorn"] | |
sign_remap = [11, 12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] | |
lookupA = [1, 7, 6, 5, 4, 3, 2, | |
2, 1, 7, 6, 5, 4, 3, | |
3, 2, 1, 7, 6, 5, 4, | |
4, 3, 2, 1, 7, 6, 5, | |
5, 4, 3, 2, 1, 7, 6, | |
6, 5, 4, 3, 2, 1, 7, | |
7, 6, 5, 4, 3, 2, 1] | |
lookupB = [0, 2, 1, 1, 2, 0, 3, 2, 3, 3, 0, 0, 1, 0, 1, 0] | |
lookupC = [3, 4, 4, 5, 4, 4, 3, 3, 2, 2, 1, 2, 2, 3, 3, 4, 5, 3, 1, 2, 3, 3, 2, 1, 3, 5, 4, 3] | |
e = current_year % 10 # Lowest digit in BCD | |
# ffcc00 | |
dob_month -= 1 | |
zodiac_sign = dob_month | |
if dob_day < zodiac_days[dob_month]: | |
zodiac_sign = dob_month - 1 | |
if zodiac_sign < 0: | |
zodiac_sign = 11 # Warp | |
print("Sign: %s" % zodiac_signs[zodiac_sign]) | |
# ffcde6 | |
zodiac_sign = sign_remap[zodiac_sign] | |
# ffce2c | |
d = current_day % 7 | |
if d == 0: | |
d = 7 | |
if d <= weekday: #ffce4b | |
if dob_month == 0: | |
dob_month = 12 | |
b = 7 - d | |
if dob_month in [4, 6, 9, 11]: | |
a = 30 | |
if dob_month != 2: | |
a = 31 | |
else: | |
if leap_year: #ffce7a - TODO | |
a = 28 | |
else: | |
a = 29 | |
d = (a - b) % 7 #ffce86 | |
b = zodiac_sign | |
if b < 8: | |
b -= 1 | |
else: | |
b -= 8 | |
a = d - 1 | |
xsp6 = a | |
a += b | |
h = a if (a < 7) else (d + b) - 8 | |
wa = lookupA[h * 7 + weekday] | |
h = (wa * wa) & 255 | |
b = (zodiac_sign + e + current_month + h) & 3 | |
var40c2 = b | |
d = (zodiac_sign * 2 + e + current_month + h) & 3 | |
var40c4 = d | |
a = (zodiac_sign * 3 + e + current_month + h) & 3 | |
var40c6 = a | |
if (b == d) and (b == a): | |
if b == 2: | |
var40c4 = 3 | |
var40c6 = 0 | |
elif a == 1: | |
var40c4 = 2 | |
var40c6 = 3 | |
elif a != 0: | |
var40c4 = 0 | |
var40c6 = 1 | |
else: | |
var40c4 = 1 | |
var40c6 = 2 | |
else: | |
# ffcf6a | |
hl = b * 4 | |
if b == d: | |
var40c4 = lookupB[hl + a] | |
else: | |
if b == a: | |
var40c6 = lookupB[hl + d] | |
else: | |
if d == a: | |
var40c2 = lookupB[hl + d * 4] | |
# ffcfb7 | |
d = lookupA[(xsp6 * 7) + weekday] | |
if current_day >= d + 7: | |
b = (current_day - d) // 7 | |
var40c2 += b | |
if var40c2 >= 4: | |
var40c2 -= 4 | |
var40c4 += b | |
if var40c4 >= 4: | |
var40c4 -= 4 | |
var40c6 += b | |
if var40c6 >= 4: | |
var40c6 -= 4 | |
# ffd049 | |
zodiac_sign += weekday | |
level_money = lookupC[var40c2 * 7 + (zodiac_sign - 1 + b) % 7] | |
level_health = lookupC[var40c4 * 7 + (zodiac_sign + b * 2) % 7] | |
level_romance = lookupC[var40c6 * 7 + (zodiac_sign + 1 + b * 3) % 7] | |
sum = level_money + level_health + level_romance | |
level_general = sum // 3 | |
if sum % 3 == 2: | |
level_general += 1 | |
print("MONEY: %d" % level_money) | |
print("HEALTH: %d" % level_health) | |
print("ROMANCE: %d" % level_romance) | |
print("GENERAL: %d" % level_general) |
TurfMasta's bot uses an automated emulator actually running the original code, so the results should be correct.
This script is based on the bios disassembly but it was proven buggy several times, indeed.
Let me know if you want the IDA project and my notes.
yeah anything you got I'd love to have. And I didn't know that about turfmasta's bot, that's good to know.
His bot is giving different answers than MAME. But my MAME setup is using the b&w ngp, possibly SNK adjusted the algorithm? I'll see if I can get a ngpc setup going too.
All I was able to find from that time is a partially commented disassembly of the NGPC bios: https://file.io/07BvQGXxmt5n
The horoscope stuff starts around FFCC00.
This is great, thanks! If I succeed in fully figuring it out I'll post a link to the repo here.
This script doesn't match what the NGP does (testing with mame). I'm now taking a stab at reverse engineering the bios algorithm now. I appreciate the script though, it's been a good starting point.