Skip to content

Instantly share code, notes, and snippets.

@EllipticEllipsis
Created March 19, 2022 01:29
Show Gist options
  • Select an option

  • Save EllipticEllipsis/31e4584cf002497f9f7729fbc4fab368 to your computer and use it in GitHub Desktop.

Select an option

Save EllipticEllipsis/31e4584cf002497f9f7729fbc4fab368 to your computer and use it in GitHub Desktop.
Convert a raw number into flag defines
#!/usr/bin/env python3
import argparse
from typing import List
import dataclasses # cursed
@dataclasses.dataclass
class Flag:
mask: int
name: str
@dataclasses.dataclass
class FlagCategory:
size: int
all: str
flags: List[Flag] # Individual flags
flag_combos: List[Flag] # Combinations, must go in order of priority/size
def count_set_bits(n):
return bin(n).count("1")
ACTOR_FLAGS = FlagCategory(
32,
"0xFFFFFFFF",
[
Flag(0x00000001, "ACTOR_FLAG_1"),
Flag(0x00000002, "ACTOR_FLAG_2"),
Flag(0x00000004, "ACTOR_FLAG_4"),
Flag(0x00000008, "ACTOR_FLAG_8"),
Flag(0x00000010, "ACTOR_FLAG_10"),
Flag(0x00000020, "ACTOR_FLAG_20"),
Flag(0x00000040, "ACTOR_FLAG_40"),
Flag(0x00000080, "ACTOR_FLAG_80"),
Flag(0x00000100, "ACTOR_FLAG_100"),
Flag(0x00000200, "ACTOR_FLAG_200"),
Flag(0x00000400, "ACTOR_FLAG_400"),
Flag(0x00000800, "ACTOR_FLAG_800"),
Flag(0x00001000, "ACTOR_FLAG_1000"),
Flag(0x00002000, "ACTOR_FLAG_2000"),
Flag(0x00004000, "ACTOR_FLAG_4000"),
Flag(0x00008000, "ACTOR_FLAG_8000"),
Flag(0x00010000, "ACTOR_FLAG_10000"),
Flag(0x00020000, "ACTOR_FLAG_20000"),
Flag(0x00040000, "ACTOR_FLAG_40000"),
Flag(0x00080000, "ACTOR_FLAG_80000"),
Flag(0x00100000, "ACTOR_FLAG_100000"),
Flag(0x00200000, "ACTOR_FLAG_200000"),
Flag(0x00400000, "ACTOR_FLAG_400000"),
Flag(0x00800000, "ACTOR_FLAG_800000"),
Flag(0x01000000, "ACTOR_FLAG_1000000"),
Flag(0x02000000, "ACTOR_FLAG_2000000"),
Flag(0x04000000, "ACTOR_FLAG_4000000"),
Flag(0x08000000, "ACTOR_FLAG_8000000"),
Flag(0x10000000, "ACTOR_FLAG_10000000"),
Flag(0x20000000, "ACTOR_FLAG_20000000"),
Flag(0x40000000, "ACTOR_FLAG_40000000"),
Flag(0x80000000, "ACTOR_FLAG_80000000"),
],
[
Flag(0x30, "ACTOR_FLAGS_30"),
],
)
PLAYER_STATE_1_FLAGS = FlagCategory(
32,
"0xFFFFFFFF",
[
Flag(0x00000001, "PLAYER_STATE1_1"),
Flag(0x00000002, "PLAYER_STATE1_2"),
Flag(0x00000004, "PLAYER_STATE1_4"),
Flag(0x00000008, "PLAYER_STATE1_8"),
Flag(0x00000010, "PLAYER_STATE1_10"),
Flag(0x00000020, "PLAYER_STATE1_20"),
Flag(0x00000040, "PLAYER_STATE1_40"),
Flag(0x00000080, "PLAYER_STATE1_80"),
Flag(0x00000100, "PLAYER_STATE1_100"),
Flag(0x00000200, "PLAYER_STATE1_200"),
Flag(0x00000400, "PLAYER_STATE1_400"),
Flag(0x00000800, "PLAYER_STATE1_800"),
Flag(0x00001000, "PLAYER_STATE1_1000"),
Flag(0x00002000, "PLAYER_STATE1_2000"),
Flag(0x00004000, "PLAYER_STATE1_4000"),
Flag(0x00008000, "PLAYER_STATE1_8000"),
Flag(0x00010000, "PLAYER_STATE1_10000"),
Flag(0x00020000, "PLAYER_STATE1_20000"),
Flag(0x00040000, "PLAYER_STATE1_40000"),
Flag(0x00080000, "PLAYER_STATE1_80000"),
Flag(0x00100000, "PLAYER_STATE1_100000"),
Flag(0x00200000, "PLAYER_STATE1_200000"),
Flag(0x00400000, "PLAYER_STATE1_400000"),
Flag(0x00800000, "PLAYER_STATE1_800000"),
Flag(0x01000000, "PLAYER_STATE1_1000000"),
Flag(0x02000000, "PLAYER_STATE1_2000000"),
Flag(0x04000000, "PLAYER_STATE1_4000000"),
Flag(0x08000000, "PLAYER_STATE1_8000000"),
Flag(0x10000000, "PLAYER_STATE1_10000000"),
Flag(0x20000000, "PLAYER_STATE1_20000000"),
Flag(0x40000000, "PLAYER_STATE1_40000000"),
Flag(0x80000000, "PLAYER_STATE1_80000000"),
],
[],
)
PLAYER_STATE_2_FLAGS = FlagCategory(
32,
"0xFFFFFFFF",
[
Flag(0x00000001, "PLAYER_STATE2_1"),
Flag(0x00000002, "PLAYER_STATE2_2"),
Flag(0x00000004, "PLAYER_STATE2_4"),
Flag(0x00000008, "PLAYER_STATE2_8"),
Flag(0x00000010, "PLAYER_STATE2_10"),
Flag(0x00000020, "PLAYER_STATE2_20"),
Flag(0x00000040, "PLAYER_STATE2_40"),
Flag(0x00000080, "PLAYER_STATE2_80"),
Flag(0x00000100, "PLAYER_STATE2_100"),
Flag(0x00000200, "PLAYER_STATE2_200"),
Flag(0x00000400, "PLAYER_STATE2_400"),
Flag(0x00000800, "PLAYER_STATE2_800"),
Flag(0x00001000, "PLAYER_STATE2_1000"),
Flag(0x00002000, "PLAYER_STATE2_2000"),
Flag(0x00004000, "PLAYER_STATE2_4000"),
Flag(0x00008000, "PLAYER_STATE2_8000"),
Flag(0x00010000, "PLAYER_STATE2_10000"),
Flag(0x00020000, "PLAYER_STATE2_20000"),
Flag(0x00040000, "PLAYER_STATE2_40000"),
Flag(0x00080000, "PLAYER_STATE2_80000"),
Flag(0x00100000, "PLAYER_STATE2_100000"),
Flag(0x00200000, "PLAYER_STATE2_200000"),
Flag(0x00400000, "PLAYER_STATE2_400000"),
Flag(0x00800000, "PLAYER_STATE2_800000"),
Flag(0x01000000, "PLAYER_STATE2_1000000"),
Flag(0x02000000, "PLAYER_STATE2_2000000"),
Flag(0x04000000, "PLAYER_STATE2_4000000"),
Flag(0x08000000, "PLAYER_STATE2_8000000"),
Flag(0x10000000, "PLAYER_STATE2_10000000"),
Flag(0x20000000, "PLAYER_STATE2_20000000"),
Flag(0x40000000, "PLAYER_STATE2_40000000"),
Flag(0x80000000, "PLAYER_STATE2_80000000"),
],
[],
)
PLAYER_STATE_3_FLAGS = FlagCategory(
32,
"0xFFFFFFFF",
[
Flag(0x00000001, "PLAYER_STATE3_1"),
Flag(0x00000002, "PLAYER_STATE3_2"),
Flag(0x00000004, "PLAYER_STATE3_4"),
Flag(0x00000008, "PLAYER_STATE3_8"),
Flag(0x00000010, "PLAYER_STATE3_10"),
Flag(0x00000020, "PLAYER_STATE3_20"),
Flag(0x00000040, "PLAYER_STATE3_40"),
Flag(0x00000080, "PLAYER_STATE3_80"),
Flag(0x00000100, "PLAYER_STATE3_100"),
Flag(0x00000200, "PLAYER_STATE3_200"),
Flag(0x00000400, "PLAYER_STATE3_400"),
Flag(0x00000800, "PLAYER_STATE3_800"),
Flag(0x00001000, "PLAYER_STATE3_1000"),
Flag(0x00002000, "PLAYER_STATE3_2000"),
Flag(0x00004000, "PLAYER_STATE3_4000"),
Flag(0x00008000, "PLAYER_STATE3_8000"),
Flag(0x00010000, "PLAYER_STATE3_10000"),
Flag(0x00020000, "PLAYER_STATE3_20000"),
Flag(0x00040000, "PLAYER_STATE3_40000"),
Flag(0x00080000, "PLAYER_STATE3_80000"),
Flag(0x00100000, "PLAYER_STATE3_100000"),
Flag(0x00200000, "PLAYER_STATE3_200000"),
Flag(0x00400000, "PLAYER_STATE3_400000"),
Flag(0x00800000, "PLAYER_STATE3_800000"),
Flag(0x01000000, "PLAYER_STATE3_1000000"),
Flag(0x02000000, "PLAYER_STATE3_2000000"),
Flag(0x04000000, "PLAYER_STATE3_4000000"),
Flag(0x08000000, "PLAYER_STATE3_8000000"),
Flag(0x10000000, "PLAYER_STATE3_10000000"),
Flag(0x20000000, "PLAYER_STATE3_20000000"),
Flag(0x40000000, "PLAYER_STATE3_40000000"),
Flag(0x80000000, "PLAYER_STATE3_80000000"),
],
[],
)
OOT_DAMAGE_FLAGS = FlagCategory(
32,
"0xFFFFFFFF",
[
Flag(0x00000001, "DMG_DEKU_NUT"),
Flag(0x00000002, "DMG_DEKU_STICK"),
Flag(0x00000004, "DMG_SLINGSHOT"),
Flag(0x00000008, "DMG_EXPLOSIVE"),
Flag(0x00000010, "DMG_BOOMERANG"),
Flag(0x00000020, "DMG_ARROW_NORMAL"),
Flag(0x00000040, "DMG_HAMMER_SWING"),
Flag(0x00000080, "DMG_HOOKSHOT"),
Flag(0x00000100, "DMG_SLASH_KOKIRI"),
Flag(0x00000200, "DMG_SLASH_MASTER"),
Flag(0x00000400, "DMG_SLASH_GIANT"),
Flag(0x00000800, "DMG_ARROW_FIRE"),
Flag(0x00001000, "DMG_ARROW_ICE"),
Flag(0x00002000, "DMG_ARROW_LIGHT"),
Flag(0x00004000, "DMG_ARROW_UNK1"),
Flag(0x00008000, "DMG_ARROW_UNK2"),
Flag(0x00010000, "DMG_ARROW_UNK3"),
Flag(0x00020000, "DMG_MAGIC_FIRE"),
Flag(0x00040000, "DMG_MAGIC_ICE"),
Flag(0x00080000, "DMG_MAGIC_LIGHT"),
Flag(0x00100000, "DMG_SHIELD"),
Flag(0x00200000, "DMG_MIR_RAY"),
Flag(0x00400000, "DMG_SPIN_KOKIRI"),
Flag(0x00800000, "DMG_SPIN_GIANT"),
Flag(0x01000000, "DMG_SPIN_MASTER"),
Flag(0x02000000, "DMG_JUMP_KOKIRI"),
Flag(0x04000000, "DMG_JUMP_GIANT"),
Flag(0x08000000, "DMG_JUMP_MASTER"),
Flag(0x10000000, "DMG_UNKNOWN_1"),
Flag(0x20000000, "DMG_UNBLOCKABLE"),
Flag(0x40000000, "DMG_HAMMER_JUMP"),
Flag(0x80000000, "DMG_UNKNOWN_2"),
],
[
Flag(0xFFCFFFFF, "DMG_DEFAULT"),
Flag(0x0FC00700, "DMG_SWORD"),
Flag(0x40000040, "DMG_HAMMER"),
Flag(0x0001F8A4, "DMG_RANGED"),
Flag(0x0001F820, "DMG_ARROW"),
Flag(0x00020800, "DMG_FIRE"),
Flag(0x00000700, "DMG_SLASH"),
Flag(0x01C00000, "DMG_SPIN_ATTACK"),
Flag(0x0E000000, "DMG_JUMP_SLASH"),
],
)
def decompose_flags(args, flag_cat: FlagCategory) -> str:
input = int(args.flags, 16)
output = []
# print(f"{input:08X}")
negated = False
if count_set_bits(input) >= 20:
negated = True
input = ~input & ((1 << flag_cat.size) - 1)
# Test combinations
for flag in flag_cat.flag_combos:
if input == 0:
break
# print(f"{flag.name}, {flag.mask & input:X}, {flag.mask:X}")
if flag.mask & input == flag.mask:
output.append(flag.name)
input &= ~flag.mask
# Test for remaining individuals
for flag in flag_cat.flags:
if input == 0:
break
if flag.mask & input == flag.mask:
output.append(flag.name)
input &= ~flag.mask
assert (
input == 0
), f"Is your input correct? It hasn't been completely decomposed: {input:X}"
if negated:
ret = " | ".join(output) if output != [] else flag_cat.all
if len(output) > 1:
ret = "(" + ret + ")"
return "~" + ret
else:
ret = " | ".join(output) if output != [] else "0"
if len(output) > 1:
ret = "(" + ret + ")"
return ret
FLAG_TYPES = {
"actor": ACTOR_FLAGS,
"player_state_1": PLAYER_STATE_1_FLAGS,
"player_state_2": PLAYER_STATE_2_FLAGS,
"player_state_3": PLAYER_STATE_3_FLAGS,
"oot_dmg": OOT_DAMAGE_FLAGS,
}
def main():
description = ""
epilog = ""
parser = argparse.ArgumentParser(
description=description,
epilog=epilog,
formatter_class=argparse.RawTextHelpFormatter,
)
parser.add_argument("flags", help="integer containing packed flags to decompose")
parser.add_argument(
"type", choices=FLAG_TYPES, help="type of flags to use in decomposition"
)
# parser.add_argument("-n", "--negate", help="negate flags instead of printing all of them", action="store_true")
args = parser.parse_args()
# input = int(args.flags, 16)
output = decompose_flags(args, FLAG_TYPES[args.type])
print(output)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment