diff --git a/Makefile b/Makefile index f608b4b9f..9cec59d86 100644 --- a/Makefile +++ b/Makefile @@ -168,7 +168,7 @@ clean: mostlyclean clean-fs clean-tools clean-fs: $(RM) $(filter %.narc %.arc,$(HOSTFS_FILES)) $(RM) $(patsubst %.narc,%.naix,$(patsubst %.arc,%.naix,$(filter %.narc %.arc,$(HOSTFS_FILES)))) - $(RM) $(NCGR_CLEAN_LIST) $(NCLR_CLEAN_LIST) $(NCER_CLEAN_LIST) $(FS_CLEAN_LIST) + $(RM) $(NCGR_CLEAN_LIST) $(NCLR_CLEAN_LIST) $(NCER_CLEAN_LIST) $(NANR_CLEAN_LIST) $(FS_CLEAN_LIST) find . \( -iname '*.1bpp' -o -iname '*.4bpp' -o -iname '*.8bpp' -o -iname '*.gbapal' -o -iname '*.lz' \) -exec $(RM) {} + $(RM) files/msgdata/msg/narc_*.bin @@ -283,6 +283,9 @@ $(NCPR_NCLR_FILES): GFX_FLAGS = -ncpr %.NCER: %.json $(GFX) $< $@ +%.NANR: %.json + $(GFX) $< $@ + %.NSCR: %_map.json $(GFX) $< $@ $(GFX_FLAGS) diff --git a/arm9/asm/unk_02035068.s b/arm9/asm/unk_02035068.s index 2a2fe0b54..000524413 100644 --- a/arm9/asm/unk_02035068.s +++ b/arm9/asm/unk_02035068.s @@ -2096,7 +2096,7 @@ _020360EA: ldr r1, _0203627C ; =UNK_020F2A90 add r0, r7, #0x0 mov r2, #0xb - bl CreateBagView + bl Bag_CreateView mov r1, #0x7e lsl r1, r1, #0x2 add r3, r5, #0x0 @@ -3141,7 +3141,7 @@ _020369C6: mov r1, #0x4 add r2, sp, #0x8 add r3, #0x1 - bl sub_0206F17C + bl BagCursor_Field_PocketGetPosition mov r0, #0x7e add r2, sp, #0x8 lsl r0, r0, #0x2 @@ -3188,7 +3188,7 @@ sub_02036A14: ; 0x02036A14 ldrb r3, [r3, #0x1] ldr r0, [r0, #0x0] mov r1, #0x4 - bl sub_0206F190 + bl BagCursor_Field_PocketSetPosition mov r1, #0x7e lsl r1, r1, #0x2 ldr r1, [r4, r1] diff --git a/arm9/asm/unk_020372D4.s b/arm9/asm/unk_020372D4.s index d3ff64a6e..ed764e0bb 100644 --- a/arm9/asm/unk_020372D4.s +++ b/arm9/asm/unk_020372D4.s @@ -233,7 +233,7 @@ sub_02037400: ; 0x02037400 mov r1, #0xb bl sub_02034A28 mov r0, #0xb - bl sub_0206F164 + bl BagCursor_New add r1, r4, #0x0 add r1, #0x94 str r0, [r1, #0x0] diff --git a/arm9/asm/unk_020377F0.s b/arm9/asm/unk_020377F0.s index a78031735..26daef33f 100644 --- a/arm9/asm/unk_020377F0.s +++ b/arm9/asm/unk_020377F0.s @@ -267,7 +267,7 @@ sub_02037844: ; 0x02037844 bl Save_Bag_Get ldr r1, _02037898 ; =UNK_020F2BDC mov r2, #0xb - bl CreateBagView + bl Bag_CreateView add r3, r5, #0x0 add r3, #0x94 ldr r1, [r5, #0xc] @@ -328,7 +328,7 @@ _020378C8: add r0, r6, #0x0 ldr r1, [r1, #0x0] mov r2, #0x20 - bl CreateBagView + bl Bag_CreateView add r3, r5, #0x0 add r3, #0x94 ldr r1, [r5, #0xc] diff --git a/arm9/asm/unk_0208898C.s b/arm9/asm/unk_0208898C.s index 0eaad6d4d..36cc02742 100644 --- a/arm9/asm/unk_0208898C.s +++ b/arm9/asm/unk_0208898C.s @@ -46,7 +46,7 @@ sub_020889B0: ; 0x020889B0 str r0, [r4, #0x0] str r5, [r4, #0x10] ldr r0, [r4, #0x0] - bl sub_0206F164 + bl BagCursor_New str r0, [r4, #0xc] ldr r0, [r5, #0x4] cmp r0, #0x1 diff --git a/arm9/global.inc b/arm9/global.inc index bd0d23e73..47f9053dd 100644 --- a/arm9/global.inc +++ b/arm9/global.inc @@ -5024,22 +5024,22 @@ .extern Bag_PocketNotEmpty .extern Bag_GetQuantity .extern Pocket_GetQuantity -.extern CreateBagView +.extern Bag_CreateView .extern Bag_GetPocketSlotN .extern Save_Bag_Get -.extern sub_0206F164 -.extern sub_0206F17C -.extern sub_0206F18C -.extern sub_0206F190 -.extern sub_0206F19C -.extern sub_0206F1A0 -.extern sub_0206F1AC -.extern sub_0206F1B0 -.extern sub_0206F1B4 -.extern sub_0206F1B8 -.extern sub_0206F1C0 -.extern sub_0206F1E4 -.extern sub_0206F1EC +.extern BagCursor_New +.extern BagCursor_Field_PocketGetPosition +.extern BagCursor_Field_GetPocket +.extern BagCursor_Field_PocketSetPosition +.extern BagCursor_Field_SetPocket +.extern BagCursor_Battle_PocketGetPosition +.extern BagCursor_Battle_GetLastUsedItem +.extern BagCursor_Battle_GetLastUsedPocket +.extern BagCursor_Battle_GetPocket +.extern BagCursor_Battle_PocketSetPosition +.extern BagCursor_Battle_Init +.extern BagCursor_Battle_SetLastUsedItem +.extern BagCursor_Battle_SetPocket .extern sub_0206F3B8 .extern sub_0206F3D8 .extern sub_0207008C diff --git a/arm9/overlays/06/asm/overlay_06.s b/arm9/overlays/06/asm/overlay_06.s index 94e6d0571..6e1de3f0b 100644 --- a/arm9/overlays/06/asm/overlay_06.s +++ b/arm9/overlays/06/asm/overlay_06.s @@ -11163,7 +11163,7 @@ ov06_0223ECF0: ; 0x0223ECF0 bl Save_Bag_Get ldr r1, _0223ED48 ; =0x0224F47C mov r2, #0xb - bl CreateBagView + bl Bag_CreateView add r3, r5, #0 str r0, [r4, #4] add r3, #0x94 diff --git a/arm9/overlays/09/asm/overlay_09.s b/arm9/overlays/09/asm/overlay_09.s index 2ba98d978..81d8118d3 100644 --- a/arm9/overlays/09/asm/overlay_09.s +++ b/arm9/overlays/09/asm/overlay_09.s @@ -3808,7 +3808,7 @@ _02213CA8: bl ov11_02230218 add r1, r4, #0 add r2, r6, #0 - bl sub_0206F1E4 + bl BagCursor_Battle_SetLastUsedItem pop {r3, r4, r5, r6, r7, pc} thumb_func_start ov09_02213CB8 @@ -12685,18 +12685,18 @@ _02218730: add r1, r5, #0 add r2, r2, r5 add r3, r3, r5 - bl sub_0206F1A0 + bl BagCursor_Battle_PocketGetPosition add r0, r5, #1 lsl r0, r0, #0x18 lsr r5, r0, #0x18 cmp r5, #5 blo _02218730 add r0, r6, #0 - bl sub_0206F1AC + bl BagCursor_Battle_GetLastUsedItem ldr r1, [r4] strh r0, [r1, #0x20] add r0, r6, #0 - bl sub_0206F1B0 + bl BagCursor_Battle_GetLastUsedPocket ldr r1, [r4] strb r0, [r1, #0x1f] add r0, r4, #0 @@ -12873,7 +12873,7 @@ ov09_02218888: ; 0x02218888 ldr r0, [r4] ldr r0, [r0] bl ov11_02230218 - bl sub_0206F1B4 + bl BagCursor_Battle_GetPocket ldr r1, _02218950 ; =0x0000114D strb r0, [r4, r1] add r0, r4, #0 @@ -13687,7 +13687,7 @@ _02218F4E: ldrb r2, [r2] ldrb r3, [r3] add r1, r4, #0 - bl sub_0206F1B8 + bl BagCursor_Battle_PocketSetPosition add r0, r4, #1 lsl r0, r0, #0x18 lsr r4, r0, #0x18 @@ -13696,7 +13696,7 @@ _02218F4E: ldr r1, _02218F8C ; =0x0000114D add r0, r6, #0 ldrb r1, [r5, r1] - bl sub_0206F1EC + bl BagCursor_Battle_SetPocket _02218F78: ldr r0, [r5] mov r1, #1 @@ -14300,7 +14300,7 @@ ov09_0221944C: ; 0x0221944C bl ov11_02230218 add r1, r4, #0 add r2, r6, #0 - bl sub_0206F1E4 + bl BagCursor_Battle_SetLastUsedItem pop {r3, r4, r5, r6, r7, pc} thumb_func_start ov09_02219474 diff --git a/arm9/overlays/11/asm/ov11_0222D5C0_1.s b/arm9/overlays/11/asm/ov11_0222D5C0_1.s index 74e089285..041ca5000 100644 --- a/arm9/overlays/11/asm/ov11_0222D5C0_1.s +++ b/arm9/overlays/11/asm/ov11_0222D5C0_1.s @@ -1039,7 +1039,7 @@ _0222DC42: bl ov11_0222FE94 add r0, r4, #0 bl ov11_02230218 - bl sub_0206F1C0 + bl BagCursor_Battle_Init mov r0, #5 mov r1, #4 mov r2, #0 diff --git a/arm9/overlays/11/asm/ov11_0223D1DC.s b/arm9/overlays/11/asm/ov11_0223D1DC.s index 823f5f431..27afedb3c 100644 --- a/arm9/overlays/11/asm/ov11_0223D1DC.s +++ b/arm9/overlays/11/asm/ov11_0223D1DC.s @@ -4708,7 +4708,7 @@ _0223F598: bl ov11_02230218 ldrh r1, [r6] ldrb r2, [r6, #2] - bl sub_0206F1E4 + bl BagCursor_Battle_SetLastUsedItem _0223F5D2: ldrh r1, [r6] mov r0, #0x4a diff --git a/arm9/overlays/14/asm/overlay_14.s b/arm9/overlays/14/asm/overlay_14.s index cd2c1a8d7..893f3541d 100644 --- a/arm9/overlays/14/asm/overlay_14.s +++ b/arm9/overlays/14/asm/overlay_14.s @@ -5810,7 +5810,7 @@ _021DA41E: bl Save_Bag_Get ldr r1, _021DA5D8 ; =ov14_021E6264 mov r2, #9 - bl CreateBagView + bl Bag_CreateView mov r1, #0x85 lsl r1, r1, #2 str r0, [r4, r1] diff --git a/arm9/overlays/75/asm/overlay_75.s b/arm9/overlays/75/asm/overlay_75.s index df462e664..ca5b0f189 100644 --- a/arm9/overlays/75/asm/overlay_75.s +++ b/arm9/overlays/75/asm/overlay_75.s @@ -1114,7 +1114,7 @@ _021E74AE: ldr r0, [r0, #0x6c] add r2, #1 add r3, sp, #0 - bl sub_0206F17C + bl BagCursor_Field_PocketGetPosition add r0, sp, #0 ldrb r0, [r0, #1] cmp r0, #0 @@ -1139,7 +1139,7 @@ _021E74F2: add r0, #0xc4 ldr r0, [r0] ldr r0, [r0, #0x6c] - bl sub_0206F18C + bl BagCursor_Field_GetPocket mov r1, #0 mov r3, #0xc _021E7502: @@ -1195,7 +1195,7 @@ _021E7540: ldr r0, [r0, #0x6c] lsr r2, r2, #0x18 lsr r3, r3, #0x18 - bl sub_0206F190 + bl BagCursor_Field_PocketSetPosition add r4, r4, #1 add r5, #0xc cmp r4, #8 @@ -1210,7 +1210,7 @@ _021E7568: mul r1, r2 add r1, r7, r1 ldrb r1, [r1, #8] - bl sub_0206F19C + bl BagCursor_Field_SetPocket _021E757E: pop {r3, r4, r5, r6, r7, pc} thumb_func_end ov75_021E752C diff --git a/arm9/src/bag.c b/arm9/src/bag.c index 4a29e8232..4c5b40d8b 100644 --- a/arm9/src/bag.c +++ b/arm9/src/bag.c @@ -1,458 +1,420 @@ #include "global.h" +#include "constants/items.h" #include "MI_memory.h" #include "bag.h" #include "itemtool.h" #include "heap.h" -u32 Save_Bag_sizeof(void) -{ - return sizeof(struct Bag); +static u32 Bag_GetItemPocket(Bag *bag, u16 itemId, ItemSlot **itemSlots, u32 *countPtr, HeapID heapId); +static ItemSlot *Pocket_GetItemSlotForAdd(ItemSlot *slots, u32 count, u16 itemId, u16 quantity, u16 maxQuantity); +static ItemSlot *Bag_GetItemSlotForAdd(Bag *bag, u16 itemId, u16 quantity, HeapID heapId); +static ItemSlot *Pocket_GetItemSlotForRemove(ItemSlot *slots, u32 count, u16 itemId, u16 quantity); +static ItemSlot *Bag_GetItemSlotForRemove(Bag *bag, u16 itemId, u16 quantity, HeapID heapId); +static void SwapItemSlots(ItemSlot *a, ItemSlot *b); +static void PocketCompaction(ItemSlot *slots, u32 count); +static void SortPocket(ItemSlot *slots, u32 count); + +u32 Save_Bag_sizeof(void) { + return sizeof(Bag); } -struct Bag * Save_Bag_New(HeapID heapId) -{ - struct Bag * ret = (struct Bag *)AllocFromHeap(heapId, sizeof(struct Bag)); - Save_Bag_Init(ret); - return ret; +Bag *Save_Bag_New(HeapID heapId) { + Bag *bag = (Bag *) AllocFromHeap(heapId, sizeof(Bag)); + Save_Bag_Init(bag); + return bag; } -void Save_Bag_Init(struct Bag * bag) -{ - MI_CpuClear16(bag, sizeof(struct Bag)); +void Save_Bag_Init(Bag *bag) { + MI_CpuClear16(bag, sizeof(Bag)); } -void Save_Bag_Copy(const struct Bag * src, struct Bag * dest) -{ - MI_CpuCopy8(src, dest, sizeof(struct Bag)); +void Save_Bag_Copy(const Bag *src, Bag *dest) { + MI_CpuCopy8(src, dest, sizeof(Bag)); } -u32 Bag_GetRegisteredItem(struct Bag * bag) -{ +u32 Bag_GetRegisteredItem(Bag *bag) { return bag->registeredItem; } -void Bag_SetRegisteredItem(struct Bag * bag, u32 item) -{ +void Bag_SetRegisteredItem(Bag *bag, u32 item) { bag->registeredItem = item; } -u32 Bag_GetItemPocket(struct Bag * bag, u16 item_id, struct ItemSlot ** slot_p, u32 * count_p, HeapID heapId) -{ - u32 pocket = GetItemAttr(item_id, 5, heapId); - switch (pocket) - { - case POCKET_KEY_ITEMS: - *slot_p = bag->keyItems; - *count_p = NUM_BAG_KEY_ITEMS; - break; - case POCKET_ITEMS: - *slot_p = bag->items; - *count_p = NUM_BAG_ITEMS; - break; - case POCKET_BERRIES: - *slot_p = bag->berries; - *count_p = NUM_BAG_BERRIES; - break; - case POCKET_MEDICINE: - *slot_p = bag->medicine; - *count_p = NUM_BAG_MEDICINE; - break; - case POCKET_BALLS: - *slot_p = bag->balls; - *count_p = NUM_BAG_BALLS; - break; - case POCKET_BATTLE_ITEMS: - *slot_p = bag->battleItems; - *count_p = NUM_BAG_BATTLE_ITEMS; - break; - case POCKET_MAIL: - *slot_p = bag->mail; - *count_p = NUM_BAG_MAIL; - break; - case POCKET_TMHMS: - *slot_p = bag->TMsHMs; - *count_p = NUM_BAG_TMS_HMS; - break; +static u32 Bag_GetItemPocket(Bag *bag, u16 itemId, ItemSlot **itemSlots, u32 *countPtr, HeapID heapId) { + u32 pocket = GetItemAttr(itemId, ITEMATTR_POCKET, heapId); + switch (pocket) { + case POCKET_KEY_ITEMS: + *itemSlots = bag->keyItems; + *countPtr = NUM_BAG_KEY_ITEMS; + break; + case POCKET_ITEMS: + *itemSlots = bag->items; + *countPtr = NUM_BAG_ITEMS; + break; + case POCKET_BERRIES: + *itemSlots = bag->berries; + *countPtr = NUM_BAG_BERRIES; + break; + case POCKET_MEDICINE: + *itemSlots = bag->medicine; + *countPtr = NUM_BAG_MEDICINE; + break; + case POCKET_BALLS: + *itemSlots = bag->balls; + *countPtr = NUM_BAG_BALLS; + break; + case POCKET_BATTLE_ITEMS: + *itemSlots = bag->battleItems; + *countPtr = NUM_BAG_BATTLE_ITEMS; + break; + case POCKET_MAIL: + *itemSlots = bag->mail; + *countPtr = NUM_BAG_MAIL; + break; + case POCKET_TMHMS: + *itemSlots = bag->TMsHMs; + *countPtr = NUM_BAG_TMS_HMS; + break; } return pocket; } -struct ItemSlot * Pocket_GetItemSlotForAdd(struct ItemSlot * slots, u32 count, u16 item_id, u16 quantity, u16 maxquantity) -{ - int i; - int found = -1; - for (i = 0; i < count; i++) - { - if (slots[i].id == item_id) - { - if (quantity + slots[i].quantity > maxquantity) +static ItemSlot *Pocket_GetItemSlotForAdd(ItemSlot *slots, u32 count, u16 itemId, u16 quantity, u16 maxQuantity) { + s32 i; + s32 found = -1; + for (i = 0; i < count; i++) { + if (slots[i].id == itemId) { + // Only one stack allowed per item. + // If the resulting stack would be too large, + // pretend there's no room for it. + if (quantity + slots[i].quantity > maxQuantity) { return NULL; + } return &slots[i]; } - if (found == -1 && slots[i].id == ITEM_NONE && slots[i].quantity == 0) - { + if (found == -1 && slots[i].id == ITEM_NONE && slots[i].quantity == 0) { found = i; } } - if (found == -1) + if (found == -1) { return NULL; + } return &slots[found]; } -struct ItemSlot * Bag_GetItemSlotForAdd(struct Bag * bag, u16 item_id, u16 quantity, HeapID heapId) -{ - struct ItemSlot * slots; +static ItemSlot *Bag_GetItemSlotForAdd(Bag *bag, u16 itemId, u16 quantity, HeapID heapId) { + ItemSlot *slots; u32 count; - u32 pocket = Bag_GetItemPocket(bag, item_id, &slots, &count, heapId); - if (pocket == POCKET_TMHMS) - { - return Pocket_GetItemSlotForAdd(slots, count, item_id, quantity, 99); - } - else - { - return Pocket_GetItemSlotForAdd(slots, count, item_id, quantity, 999); + u32 pocket = Bag_GetItemPocket(bag, itemId, &slots, &count, heapId); + if (pocket == POCKET_TMHMS) { + return Pocket_GetItemSlotForAdd(slots, count, itemId, quantity, BAG_TMHM_QUANTITY_MAX); + } else { + return Pocket_GetItemSlotForAdd(slots, count, itemId, quantity, BAG_SLOT_QUANTITY_MAX); } } -BOOL Bag_HasSpaceForItem(struct Bag * bag, u16 item_id, u16 quantity, HeapID heapId) -{ - return Bag_GetItemSlotForAdd(bag, item_id, quantity, heapId) != NULL; +BOOL Bag_HasSpaceForItem(Bag *bag, u16 itemId, u16 quantity, HeapID heapId) { + return Bag_GetItemSlotForAdd(bag, itemId, quantity, heapId) != NULL; } -BOOL Bag_AddItem(struct Bag * bag, u16 item_id, u16 quantity, HeapID heapId) -{ - struct ItemSlot * slots = Bag_GetItemSlotForAdd(bag, item_id, quantity, heapId); - if (slots == NULL) +BOOL Bag_AddItem(Bag *bag, u16 itemId, u16 quantity, HeapID heapId) { + ItemSlot *slot = Bag_GetItemSlotForAdd(bag, itemId, quantity, heapId); + if (slot == NULL) { return FALSE; - slots->id = item_id; - slots->quantity += quantity; + } + slot->id = itemId; + slot->quantity += quantity; u32 count; - u32 pocket = Bag_GetItemPocket(bag, item_id, &slots, &count, heapId); - if (pocket == POCKET_TMHMS || pocket == POCKET_BERRIES) - { - SortPocket(slots, count); + u32 pocket = Bag_GetItemPocket(bag, itemId, &slot, &count, heapId); + if (pocket == POCKET_TMHMS || pocket == POCKET_BERRIES) { + SortPocket(slot, count); } return TRUE; } -struct ItemSlot * Pocket_GetItemSlotForRemove(struct ItemSlot * slots, u32 count, u16 item_id, u16 quantity) -{ - int i; - for (i = 0; i < count; i++) - { - if (slots[i].id == item_id) - { - if (slots[i].quantity >= quantity) - return &slots[i]; - return NULL; +static ItemSlot *Pocket_GetItemSlotForRemove(ItemSlot *slots, u32 count, u16 itemId, u16 quantity) { + for (s32 i = 0; i < count; i++) { + if (slots[i].id == itemId) { + if (slots[i].quantity < quantity) { + return NULL; + } + return &slots[i]; } } return NULL; } -struct ItemSlot * Bag_GetItemSlotForRemove(struct Bag * bag, u16 item_id, u16 quantity, HeapID heapId) -{ - struct ItemSlot * slots; +static ItemSlot *Bag_GetItemSlotForRemove(Bag *bag, u16 itemId, u16 quantity, HeapID heapId) { + ItemSlot *slots; u32 count; - (void)Bag_GetItemPocket(bag, item_id, &slots, &count, heapId); - return Pocket_GetItemSlotForRemove(slots, count, item_id, quantity); + Bag_GetItemPocket(bag, itemId, &slots, &count, heapId); + return Pocket_GetItemSlotForRemove(slots, count, itemId, quantity); } -BOOL Bag_TakeItem(struct Bag * bag, u16 item_id, u16 quantity, HeapID heapId) -{ - struct ItemSlot * slots = Bag_GetItemSlotForRemove(bag, item_id, quantity, heapId); - if (slots == NULL) - return FALSE; - slots->quantity -= quantity; - if (slots->quantity == 0) - slots->id = ITEM_NONE; - u32 count; - (void)Bag_GetItemPocket(bag, item_id, &slots, &count, heapId); - PocketCompaction(slots, count); - return TRUE; -} - -BOOL Pocket_TakeItem(struct ItemSlot * slots, u32 count, u16 item_id, u16 quantity) -{ - struct ItemSlot * slot = Pocket_GetItemSlotForRemove(slots, count, item_id, quantity); - if (slot == NULL) - return FALSE; - slot->quantity -= quantity; - if (slot->quantity == 0) - slot->id = ITEM_NONE; - PocketCompaction(slots, count); - return TRUE; -} - -BOOL Bag_HasItem(struct Bag * bag, u16 item_id, u16 quantity, HeapID heapId) -{ - return Bag_GetItemSlotForRemove(bag, item_id, quantity, heapId) != NULL; -} - -BOOL Bag_PocketNotEmpty(struct Bag * bag, u32 pocket) -{ - struct ItemSlot * slots; - u32 count; - switch (pocket) - { - case POCKET_KEY_ITEMS: - slots = bag->keyItems; - count = NUM_BAG_KEY_ITEMS; - break; - case POCKET_ITEMS: - slots = bag->items; - count = NUM_BAG_ITEMS; - break; - case POCKET_BERRIES: - slots = bag->berries; - count = NUM_BAG_BERRIES; - break; - case POCKET_MEDICINE: - slots = bag->medicine; - count = NUM_BAG_MEDICINE; - break; - case POCKET_BALLS: - slots = bag->balls; - count = NUM_BAG_BALLS; - break; - case POCKET_BATTLE_ITEMS: - slots = bag->battleItems; - count = NUM_BAG_BATTLE_ITEMS; - break; - case POCKET_MAIL: - slots = bag->mail; - count = NUM_BAG_MAIL; - break; - case POCKET_TMHMS: - slots = bag->TMsHMs; - count = NUM_BAG_TMS_HMS; - break; - default: +BOOL Bag_TakeItem(Bag *bag, u16 itemId, u16 quantity, HeapID heapId) { + ItemSlot *slot = Bag_GetItemSlotForRemove(bag, itemId, quantity, heapId); + if (slot == NULL) { return FALSE; } - int i; - for (i = 0; i < count; i++) - { - if (slots[i].id != ITEM_NONE) + slot->quantity -= quantity; + if (slot->quantity == 0) { + slot->id = ITEM_NONE; + } + u32 count; + Bag_GetItemPocket(bag, itemId, &slot, &count, heapId); + PocketCompaction(slot, count); + return TRUE; +} + +BOOL Pocket_TakeItem(ItemSlot *slots, u32 count, u16 itemId, u16 quantity) { + ItemSlot *slot = Pocket_GetItemSlotForRemove(slots, count, itemId, quantity); + if (slot == NULL) { + return FALSE; + } + slot->quantity -= quantity; + if (slot->quantity == 0) { + slot->id = ITEM_NONE; + } + PocketCompaction(slots, count); + return TRUE; +} + +BOOL Bag_HasItem(Bag *bag, u16 itemId, u16 quantity, HeapID heapId) { + return Bag_GetItemSlotForRemove(bag, itemId, quantity, heapId) != NULL; +} + +BOOL Bag_PocketNotEmpty(Bag *bag, u32 pocket) { + ItemSlot * slots; + u32 count; + switch (pocket) { + case POCKET_KEY_ITEMS: + slots = bag->keyItems; + count = NUM_BAG_KEY_ITEMS; + break; + case POCKET_ITEMS: + slots = bag->items; + count = NUM_BAG_ITEMS; + break; + case POCKET_BERRIES: + slots = bag->berries; + count = NUM_BAG_BERRIES; + break; + case POCKET_MEDICINE: + slots = bag->medicine; + count = NUM_BAG_MEDICINE; + break; + case POCKET_BALLS: + slots = bag->balls; + count = NUM_BAG_BALLS; + break; + case POCKET_BATTLE_ITEMS: + slots = bag->battleItems; + count = NUM_BAG_BATTLE_ITEMS; + break; + case POCKET_MAIL: + slots = bag->mail; + count = NUM_BAG_MAIL; + break; + case POCKET_TMHMS: + slots = bag->TMsHMs; + count = NUM_BAG_TMS_HMS; + break; + default: + return FALSE; + } + + for (s32 i = 0; i < count; i++) { + if (slots[i].id != ITEM_NONE) { return TRUE; + } } return FALSE; } -u16 Bag_GetQuantity(struct Bag * bag, u16 item_id, HeapID heapId) -{ - struct ItemSlot * slot = Bag_GetItemSlotForRemove(bag, item_id, 1, heapId); - if (slot == NULL) +u16 Bag_GetQuantity(Bag *bag, u16 itemId, HeapID heapId) { + ItemSlot *slot = Bag_GetItemSlotForRemove(bag, itemId, 1, heapId); + if (slot == NULL) { return 0; + } return slot->quantity; } -u16 Pocket_GetQuantity(struct ItemSlot * slots, u32 count, u16 item_id) -{ - struct ItemSlot * slot = Pocket_GetItemSlotForRemove(slots, count, item_id, 1); - if (slot == NULL) +u16 Pocket_GetQuantity(ItemSlot *slots, u32 count, u16 itemId) { + ItemSlot *slot = Pocket_GetItemSlotForRemove(slots, count, itemId, 1); + if (slot == NULL) { return 0; + } return slot->quantity; } -void SwapItemSlots(struct ItemSlot * a, struct ItemSlot * b) -{ - struct ItemSlot tmp; - - tmp = *a; +static void SwapItemSlots(ItemSlot *a, ItemSlot *b) { + ItemSlot c = *a; *a = *b; - *b = tmp; + *b = c; } -void PocketCompaction(struct ItemSlot * slots, u32 count) -{ - int i, j; - for (i = 0; i < count - 1; i++) - { - for (j = i + 1; j < count; j++) - { - if (slots[i].quantity == 0) - { +static void PocketCompaction(ItemSlot *slots, u32 count) { + for (s32 i = 0; i < count - 1; i++) { + for (s32 j = i + 1; j < count; j++) { + if (slots[i].quantity == 0) { SwapItemSlots(&slots[i], &slots[j]); } } } } -void SortPocket(struct ItemSlot * slots, u32 count) -{ - int i, j; - for (i = 0; i < count - 1; i++) - { - for (j = i + 1; j < count; j++) - { - if (slots[i].quantity == 0 || (slots[j].quantity != 0 && slots[i].id > slots[j].id)) - { +static void SortPocket(ItemSlot *slots, u32 count) { + for (s32 i = 0; i < count - 1; i++) { + for (s32 j = i + 1; j < count; j++) { + if (slots[i].quantity == 0 || (slots[j].quantity != 0 && slots[i].id > slots[j].id)) { SwapItemSlots(&slots[i], &slots[j]); } } } } -struct BagView * CreateBagView(struct Bag * bag, const u8 * pockets, HeapID heapId) +BagView *Bag_CreateView(Bag *bag, const u8 *pockets, HeapID heapId) { - struct BagView * view = BagView_New((u8)heapId); + BagView *ret = BagView_New(heapId); - for (u32 i = 0; pockets[i] != 0xFF; i++) - { - switch (pockets[i]) - { - case POCKET_KEY_ITEMS: - BagView_SetItem(view, bag->keyItems, POCKET_KEY_ITEMS, (u8)i); - break; - case POCKET_ITEMS: - BagView_SetItem(view, bag->items, POCKET_ITEMS, (u8)i); - break; - case POCKET_BERRIES: - BagView_SetItem(view, bag->berries, POCKET_BERRIES, (u8)i); - break; - case POCKET_MEDICINE: - BagView_SetItem(view, bag->medicine, POCKET_MEDICINE, (u8)i); - break; - case POCKET_BALLS: - BagView_SetItem(view, bag->balls, POCKET_BALLS, (u8)i); - break; - case POCKET_BATTLE_ITEMS: - BagView_SetItem(view, bag->battleItems, POCKET_BATTLE_ITEMS, (u8)i); - break; - case POCKET_MAIL: - BagView_SetItem(view, bag->mail, POCKET_MAIL, (u8)i); - break; - case POCKET_TMHMS: - BagView_SetItem(view, bag->TMsHMs, POCKET_TMHMS, (u8)i); - break; + for (u32 i = 0; pockets[i] != POCKET_BAG_VIEW_END; i++) { + switch (pockets[i]) { + case POCKET_KEY_ITEMS: + BagView_SetItem(ret, bag->keyItems, POCKET_KEY_ITEMS, i); + break; + case POCKET_ITEMS: + BagView_SetItem(ret, bag->items, POCKET_ITEMS, i); + break; + case POCKET_BERRIES: + BagView_SetItem(ret, bag->berries, POCKET_BERRIES, i); + break; + case POCKET_MEDICINE: + BagView_SetItem(ret, bag->medicine, POCKET_MEDICINE, i); + break; + case POCKET_BALLS: + BagView_SetItem(ret, bag->balls, POCKET_BALLS, i); + break; + case POCKET_BATTLE_ITEMS: + BagView_SetItem(ret, bag->battleItems, POCKET_BATTLE_ITEMS, i); + break; + case POCKET_MAIL: + BagView_SetItem(ret, bag->mail, POCKET_MAIL, i); + break; + case POCKET_TMHMS: + BagView_SetItem(ret, bag->TMsHMs, POCKET_TMHMS, i); + break; } } - return view; -} - -struct ItemSlot * Bag_GetPocketSlotN(struct Bag * bag, u32 pocket, u32 slot) -{ - struct ItemSlot * slots; - u32 count; - switch (pocket) - { - case POCKET_KEY_ITEMS: - slots = bag->keyItems; - count = NUM_BAG_KEY_ITEMS; - break; - case POCKET_ITEMS: - slots = bag->items; - count = NUM_BAG_ITEMS; - break; - case POCKET_BERRIES: - slots = bag->berries; - count = NUM_BAG_BERRIES; - break; - case POCKET_MEDICINE: - slots = bag->medicine; - count = NUM_BAG_MEDICINE; - break; - case POCKET_BALLS: - slots = bag->balls; - count = NUM_BAG_BALLS; - break; - case POCKET_BATTLE_ITEMS: - slots = bag->battleItems; - count = NUM_BAG_BATTLE_ITEMS; - break; - case POCKET_MAIL: - slots = bag->mail; - count = NUM_BAG_MAIL; - break; - case POCKET_TMHMS: - slots = bag->TMsHMs; - count = NUM_BAG_TMS_HMS; - break; - } - if (slot >= count) - return NULL; - return &slots[slot]; -} - -struct Bag * Save_Bag_Get(struct SaveData * save) -{ - return (struct Bag *)SaveArray_Get(save, 3); -} - -struct BagCursor * sub_0206F164(HeapID heapId) -{ - struct BagCursor * ret = (struct BagCursor *)AllocFromHeap(heapId, sizeof(struct BagCursor)); - MI_CpuClear16(ret, sizeof(struct BagCursor)); return ret; } -void sub_0206F17C(struct BagCursor * a0, u32 a1, u8 * a2, u8 * a3) -{ - *a2 = a0->field.position[a1]; - *a3 = a0->field.scroll[a1]; -} +ItemSlot *Bag_GetPocketSlotN(Bag *bag, u8 pocket, u32 slot) { + ItemSlot *slots; + u32 count; -u16 sub_0206F18C(struct BagCursor * a0) -{ - return a0->field.pocket; -} - -void sub_0206F190(struct BagCursor * a0, u32 a1, u8 a2, u8 a3) -{ - a0->field.position[a1] = a2; - a0->field.scroll[a1] = a3; -} - -void sub_0206F19C(struct BagCursor * a0, u16 a1) -{ - a0->field.pocket = a1; -} - -void sub_0206F1A0(struct BagCursor * a0, u32 a1, u8 * a2, u8 * a3) -{ - *a2 = a0->battle.position[a1]; - *a3 = a0->battle.scroll[a1]; -} - -u16 sub_0206F1AC(struct BagCursor * a0) -{ - return a0->battle.lastUsedItem; -} - -u16 sub_0206F1B0(struct BagCursor * a0) -{ - return a0->battle.lastUsedPocket; -} - -u16 sub_0206F1B4(struct BagCursor * a0) -{ - return a0->battle.pocket; -} - -void sub_0206F1B8(struct BagCursor * a0, u32 a1, u8 a2, u8 a3) -{ - a0->battle.position[a1] = a2; - a0->battle.scroll[a1] = a3; -} - -void sub_0206F1C0(struct BagCursor * a0) -{ - u32 i; - for (i = 0; i < 5; i++) - { - sub_0206F1B8(a0, i, 0, 0); + switch (pocket) { + case POCKET_KEY_ITEMS: + slots = bag->keyItems; + count = NUM_BAG_KEY_ITEMS; + break; + case POCKET_ITEMS: + slots = bag->items; + count = NUM_BAG_ITEMS; + break; + case POCKET_BERRIES: + slots = bag->berries; + count = NUM_BAG_BERRIES; + break; + case POCKET_MEDICINE: + slots = bag->medicine; + count = NUM_BAG_MEDICINE; + break; + case POCKET_BALLS: + slots = bag->balls; + count = NUM_BAG_BALLS; + break; + case POCKET_BATTLE_ITEMS: + slots = bag->battleItems; + count = NUM_BAG_BATTLE_ITEMS; + break; + case POCKET_MAIL: + slots = bag->mail; + count = NUM_BAG_MAIL; + break; + case POCKET_TMHMS: + slots = bag->TMsHMs; + count = NUM_BAG_TMS_HMS; + break; } - sub_0206F1EC(a0, 0); + // UB: If pocket invalid, count and slot are uninitialized + if (slot >= count) { + return NULL; + } + return &slots[slot]; } -void sub_0206F1E4(struct BagCursor * a0, u16 a1, u16 a2) -{ - a0->battle.lastUsedItem = a1; - a0->battle.lastUsedPocket = a2; +Bag *Save_Bag_Get(SaveData *saveData) { + return SaveArray_Get(saveData, SAVE_BAG); } -void sub_0206F1EC(struct BagCursor * a0, u16 a1) -{ - a0->battle.pocket = a1; +BagCursor *BagCursor_New(HeapID heapId) { + BagCursor *ret = AllocFromHeap(heapId, sizeof(BagCursor)); + MI_CpuClear16(ret, sizeof(BagCursor)); + return ret; +} + +void BagCursor_Field_PocketGetPosition(BagCursor *cursor, u32 pocket, u8 *position, u8 *scroll) { + *position = cursor->field.position[pocket]; + *scroll = cursor->field.scroll[pocket]; +} + +u16 BagCursor_Field_GetPocket(BagCursor *cursor) { + return cursor->field.pocket; +} + +void BagCursor_Field_PocketSetPosition(BagCursor *cursor, u32 pocket, u8 position, u8 scroll) { + cursor->field.position[pocket] = position; + cursor->field.scroll[pocket] = scroll; +} + +void BagCursor_Field_SetPocket(BagCursor *cursor, u16 pocket) { + cursor->field.pocket = pocket; +} + +void BagCursor_Battle_PocketGetPosition(BagCursor *cursor, u32 pocket, u8 *position, u8 *scroll) { + *position = cursor->battle.position[pocket]; + *scroll = cursor->battle.scroll[pocket]; +} + +u16 BagCursor_Battle_GetLastUsedItem(BagCursor *cursor) { + return cursor->battle.lastUsedItem; +} + +u16 BagCursor_Battle_GetLastUsedPocket(BagCursor *cursor) { + return cursor->battle.lastUsedPocket; +} + +u16 BagCursor_Battle_GetPocket(BagCursor *cursor) { + return cursor->battle.pocket; +} + +void BagCursor_Battle_PocketSetPosition(BagCursor *cursor, u32 pocket, u8 position, u8 scroll) { + cursor->battle.position[pocket] = position; + cursor->battle.scroll[pocket] = scroll; +} + +void BagCursor_Battle_Init(BagCursor *cursor) { + for (u32 i = 0; i < 5; i++) { + BagCursor_Battle_PocketSetPosition(cursor, i, 0, 0); + } + BagCursor_Battle_SetPocket(cursor, 0); +} + +void BagCursor_Battle_SetLastUsedItem(BagCursor *cursor, u16 itemId, u16 pocket) { + cursor->battle.lastUsedItem = itemId; + cursor->battle.lastUsedPocket = pocket; +} + +void BagCursor_Battle_SetPocket(BagCursor *cursor, u16 pocket) { + cursor->battle.pocket = pocket; } diff --git a/arm9/src/bg_window.c b/arm9/src/bg_window.c index 9e30b4117..91bafa246 100644 --- a/arm9/src/bg_window.c +++ b/arm9/src/bg_window.c @@ -5,7 +5,7 @@ #include "gx.h" #include "heap.h" -const u8 sTilemapWidthByBufferSize[] = { +static const u8 sTilemapWidthByBufferSize[] = { [GF_BG_SCR_SIZE_128x128] = 0x10, [GF_BG_SCR_SIZE_256x256] = 0x20, [GF_BG_SCR_SIZE_256x512] = 0x20, diff --git a/arm9/src/unk_02088AAC.c b/arm9/src/unk_02088AAC.c index f0116df71..dbe1199a3 100644 --- a/arm9/src/unk_02088AAC.c +++ b/arm9/src/unk_02088AAC.c @@ -89,7 +89,7 @@ u32 sub_02088B4C(struct UnkStruct_02088AAC *r0) .exitFunc = ov75_021E6F00, .ovly = FS_OVERLAY_ID(OVERLAY_75) }; - struct BagView *bag_view = CreateBagView(r0->poffinCaseAppData->bag, UNK_020FD6F4, r0->heapId); + struct BagView *bag_view = Bag_CreateView(r0->poffinCaseAppData->bag, UNK_020FD6F4, r0->heapId); sub_0206E314(bag_view, r0->poffinCaseAppData->save, (u8)((u8)r0->unk06 == 1 ? 5 : 4), r0->unk0C); @@ -166,7 +166,7 @@ u32 sub_02088C3C(struct UnkStruct_02088AAC *r0) u8 sp5; u8 sp6; - sub_0206F17C(r0->unk0C, 4, &sp6, &sp5); + BagCursor_Field_PocketGetPosition(r0->unk0C, 4, &sp6, &sp5); sub_020851F8(r0->ovly_param, sp5, sp6, (u8)(berry_count + 2)); r0->ovly_data = OverlayManager_New(&OVERLAY_68_MANAGER, (s32 *)r0->ovly_param, r0->heapId); @@ -185,7 +185,7 @@ u32 sub_02088CDC(struct UnkStruct_02088AAC *r0) u8 sp1; sub_0208524C(r0->ovly_param, &sp0, &sp1); - sub_0206F190(r0->unk0C, 4, sp1, sp0); + BagCursor_Field_PocketSetPosition(r0->unk0C, 4, sp1, sp0); FreeToHeap(r0->ovly_param); r0->ovly_param = NULL; diff --git a/files/poketool/icongra/poke_icon/.gitignore b/files/poketool/icongra/poke_icon/.gitignore index fccab7c87..cb2e2b3d2 100644 --- a/files/poketool/icongra/poke_icon/.gitignore +++ b/files/poketool/icongra/poke_icon/.gitignore @@ -1,4 +1,6 @@ narc_0000.NCLR +narc_0001.NANR +narc_0003.NANR *.NCER narc_0007.NCGR narc_0008.NCGR diff --git a/files/poketool/icongra/poke_icon/narc_0001.NANR b/files/poketool/icongra/poke_icon/narc_0001.NANR deleted file mode 100644 index 033b8ba3c..000000000 Binary files a/files/poketool/icongra/poke_icon/narc_0001.NANR and /dev/null differ diff --git a/files/poketool/icongra/poke_icon/narc_0001.json b/files/poketool/icongra/poke_icon/narc_0001.json new file mode 100644 index 000000000..41655f5f8 --- /dev/null +++ b/files/poketool/icongra/poke_icon/narc_0001.json @@ -0,0 +1,46 @@ +{ + "labelEnabled": true, + "sequenceCount": 2, + "frameCount": 2, + "sequences": [ + { + "frameCount": 1, + "loopStartFrame": 0, + "animationElement": 0, + "animationType": 1, + "playbackMode": 1, + "frameData": [ + { + "frameDelay": 1, + "resultId": 0 + } + ] + }, + { + "frameCount": 1, + "loopStartFrame": 0, + "animationElement": 0, + "animationType": 1, + "playbackMode": 1, + "frameData": [ + { + "frameDelay": 1, + "resultId": 1 + } + ] + } + ], + "animationResults": [ + { + "resultType": 0, + "index": 0 + }, + { + "resultType": 0, + "index": 1 + } + ], + "resultCount": 2, + "labels": ["CellAnime0", "CellAnime1"], + "labelCount": 2 +} diff --git a/files/poketool/icongra/poke_icon/narc_0003.NANR b/files/poketool/icongra/poke_icon/narc_0003.NANR deleted file mode 100644 index 199eb5aad..000000000 Binary files a/files/poketool/icongra/poke_icon/narc_0003.NANR and /dev/null differ diff --git a/files/poketool/icongra/poke_icon/narc_0003.json b/files/poketool/icongra/poke_icon/narc_0003.json new file mode 100644 index 000000000..f6dab439a --- /dev/null +++ b/files/poketool/icongra/poke_icon/narc_0003.json @@ -0,0 +1,140 @@ +{ + "labelEnabled": true, + "sequenceCount": 6, + "frameCount": 12, + "sequences": [ + { + "frameCount": 1, + "loopStartFrame": 0, + "animationElement": 0, + "animationType": 1, + "playbackMode": 1, + "frameData": [ + { + "frameDelay": 1, + "resultId": 0 + } + ] + }, + { + "frameCount": 2, + "loopStartFrame": 0, + "animationElement": 0, + "animationType": 1, + "playbackMode": 2, + "frameData": [ + { + "frameDelay": 4, + "resultId": 0 + }, + { + "frameDelay": 4, + "resultId": 1 + } + ] + }, + { + "frameCount": 2, + "loopStartFrame": 0, + "animationElement": 0, + "animationType": 1, + "playbackMode": 2, + "frameData": [ + { + "frameDelay": 6, + "resultId": 0 + }, + { + "frameDelay": 6, + "resultId": 1 + } + ] + }, + { + "frameCount": 2, + "loopStartFrame": 0, + "animationElement": 0, + "animationType": 1, + "playbackMode": 2, + "frameData": [ + { + "frameDelay": 12, + "resultId": 0 + }, + { + "frameDelay": 12, + "resultId": 1 + } + ] + }, + { + "frameCount": 2, + "loopStartFrame": 0, + "animationElement": 0, + "animationType": 1, + "playbackMode": 2, + "frameData": [ + { + "frameDelay": 20, + "resultId": 0 + }, + { + "frameDelay": 20, + "resultId": 1 + } + ] + }, + { + "frameCount": 3, + "loopStartFrame": 0, + "animationElement": 2, + "animationType": 1, + "playbackMode": 2, + "frameData": [ + { + "frameDelay": 32, + "resultId": 2 + }, + { + "frameDelay": 2, + "resultId": 3 + }, + { + "frameDelay": 2, + "resultId": 4 + } + ] + } + ], + "animationResults": [ + { + "resultType": 0, + "index": 0 + }, + { + "resultType": 0, + "index": 1 + }, + { + "resultType": 2, + "index": 0, + "positionX": 0, + "positionY": 0 + }, + { + "resultType": 2, + "index": 0, + "positionX": 1, + "positionY": 0 + }, + { + "resultType": 2, + "index": 0, + "positionX": -1, + "positionY": 0 + } + ], + "resultCount": 5, + "labels": ["CellAnime0", "CellAnime1", "CellAnime2", "CellAnime3", "CellAnime4", "CellAnime5"], + "labelCount": 6 +} \ No newline at end of file diff --git a/filesystem.mk b/filesystem.mk index d2320effe..a417b170d 100644 --- a/filesystem.mk +++ b/filesystem.mk @@ -2671,7 +2671,9 @@ files/poketool/pokegra/pokegra.narc: \ files/poketool/icongra/poke_icon.narc: \ files/poketool/icongra/poke_icon/narc_0000.NCLR \ + files/poketool/icongra/poke_icon/narc_0001.NANR \ files/poketool/icongra/poke_icon/narc_0002.NCER \ + files/poketool/icongra/poke_icon/narc_0003.NANR \ files/poketool/icongra/poke_icon/narc_0004.NCER \ files/poketool/icongra/poke_icon/narc_0006.NCER \ files/poketool/icongra/poke_icon/narc_0007.NCGR \ diff --git a/graphics_rules.mk b/graphics_rules.mk index 2cb321d5d..e6fc2ff89 100644 --- a/graphics_rules.mk +++ b/graphics_rules.mk @@ -1211,3 +1211,6 @@ NCLR_CLEAN_LIST := files/application/wifi_earth/wifi_earth/narc_0006.NCLR \ NCER_CLEAN_LIST := files/poketool/icongra/poke_icon/narc_0002.NCER \ files/poketool/icongra/poke_icon/narc_0004.NCER \ files/poketool/icongra/poke_icon/narc_0006.NCER + +NANR_CLEAN_LIST := files/poketool/icongra/poke_icon/narc_0001.NANR \ + files/poketool/icongra/poke_icon/narc_0003.NANR diff --git a/include/bag.h b/include/bag.h index 0964c94bb..6115792da 100644 --- a/include/bag.h +++ b/include/bag.h @@ -7,54 +7,34 @@ #include "save.h" typedef struct Bag { - struct ItemSlot items[NUM_BAG_ITEMS]; - struct ItemSlot keyItems[NUM_BAG_KEY_ITEMS]; - struct ItemSlot TMsHMs[NUM_BAG_TMS_HMS]; - struct ItemSlot mail[NUM_BAG_MAIL]; - struct ItemSlot medicine[NUM_BAG_MEDICINE]; - struct ItemSlot berries[NUM_BAG_BERRIES]; - struct ItemSlot balls[NUM_BAG_BALLS]; - struct ItemSlot battleItems[NUM_BAG_BATTLE_ITEMS]; + ItemSlot items[NUM_BAG_ITEMS]; + ItemSlot keyItems[NUM_BAG_KEY_ITEMS]; + ItemSlot TMsHMs[NUM_BAG_TMS_HMS]; + ItemSlot mail[NUM_BAG_MAIL]; + ItemSlot medicine[NUM_BAG_MEDICINE]; + ItemSlot berries[NUM_BAG_BERRIES]; + ItemSlot balls[NUM_BAG_BALLS]; + ItemSlot battleItems[NUM_BAG_BATTLE_ITEMS]; u32 registeredItem; } Bag; u32 Save_Bag_sizeof(void); -struct Bag * Save_Bag_New(HeapID heapId); -void Save_Bag_Init(struct Bag * bag); -void Save_Bag_Copy(const struct Bag * src, struct Bag * dest); -u32 Bag_GetRegisteredItem(struct Bag * bag); -void Bag_SetRegisteredItem(struct Bag * bag, u32 item); -u32 Bag_GetItemPocket(struct Bag * bag, u16 item_id, struct ItemSlot ** slot_p, u32 * count_p, HeapID heapId); -struct ItemSlot * Pocket_GetItemSlotForAdd(struct ItemSlot * slots, u32 count, u16 item_id, u16 quantity, u16 maxquantity); -struct ItemSlot * Bag_GetItemSlotForAdd(struct Bag * bag, u16 item_id, u16 quantity, HeapID heapId); -BOOL Bag_HasSpaceForItem(struct Bag * bag, u16 item_id, u16 quantity, HeapID heapId); -BOOL Bag_AddItem(struct Bag * bag, u16 item_id, u16 quantity, HeapID heapId); -struct ItemSlot * Pocket_GetItemSlotForRemove(struct ItemSlot * slots, u32 count, u16 item_id, u16 quantity); -struct ItemSlot * Bag_GetItemSlotForRemove(struct Bag * bag, u16 item_id, u16 quantity, HeapID heapId); -BOOL Bag_TakeItem(struct Bag * bag, u16 item_id, u16 quantity, HeapID heapId); -BOOL Pocket_TakeItem(struct ItemSlot * slots, u32 count, u16 item_id, u16 quantity); -BOOL Bag_HasItem(struct Bag * bag, u16 item_id, u16 quantity, HeapID heapId); -BOOL Bag_PocketNotEmpty(struct Bag * bag, u32 pocket); -u16 Bag_GetQuantity(struct Bag * bag, u16 item_id, HeapID heapId); -u16 Pocket_GetQuantity(struct ItemSlot * slots, u32 count, u16 item_id); -void SwapItemSlots(struct ItemSlot * a, struct ItemSlot * b); -void PocketCompaction(struct ItemSlot * slots, u32 count); -void SortPocket(struct ItemSlot * slots, u32 count); -struct BagView * CreateBagView(struct Bag * bag, const u8 * pockets, HeapID heapId); -struct ItemSlot * Bag_GetPocketSlotN(struct Bag * bag, u32 pocket, u32 slot); -struct Bag * Save_Bag_Get(struct SaveData * save); -struct BagCursor * sub_0206F164(HeapID heapId); -void sub_0206F17C(struct BagCursor * a0, u32 a1, u8 * a2, u8 * a3); -u16 sub_0206F18C(struct BagCursor * a0); -void sub_0206F190(struct BagCursor * a0, u32 a1, u8 a2, u8 a3); -void sub_0206F19C(struct BagCursor * a0, u16 a1); -void sub_0206F1A0(struct BagCursor * a0, u32 a1, u8 * a2, u8 * a3); -u16 sub_0206F1AC(struct BagCursor * a0); -u16 sub_0206F1B0(struct BagCursor * a0); -u16 sub_0206F1B4(struct BagCursor * a0); -void sub_0206F1B8(struct BagCursor * a0, u32 a1, u8 a2, u8 a3); -void sub_0206F1C0(struct BagCursor * a0); -void sub_0206F1E4(struct BagCursor * a0, u16 a1, u16 a2); -void sub_0206F1EC(struct BagCursor * a0, u16 a1); +Bag *Save_Bag_New(HeapID heapId); +void Save_Bag_Init(Bag *bag); +void Save_Bag_Copy(const Bag *src, Bag *dest); +u32 Bag_GetRegisteredItem(Bag *bag); +void Bag_SetRegisteredItem(Bag *bag, u32 item); +BOOL Bag_HasSpaceForItem(Bag *bag, u16 itemId, u16 quantity, HeapID heapId); +BOOL Bag_AddItem(Bag *bag, u16 itemId, u16 quantity, HeapID heapId); +BOOL Bag_TakeItem(Bag *bag, u16 itemId, u16 quantity, HeapID heapId); +BOOL Pocket_TakeItem(ItemSlot *slots, u32 count, u16 itemId, u16 quantity); +BOOL Bag_HasItem(Bag *bag, u16 itemId, u16 quantity, HeapID heapId); +BOOL Bag_PocketNotEmpty(Bag *bag, u32 pocket); +u16 Bag_GetQuantity(Bag *bag, u16 itemId, HeapID heapId); +u16 Pocket_GetQuantity(ItemSlot *slots, u32 count, u16 itemId); +void SortPocket(ItemSlot *slots, u32 count); +BagView * Bag_CreateView(Bag *bag, const u8 *pockets, HeapID heapId); +ItemSlot *Bag_GetPocketSlotN(Bag *bag, u8 pocket, u32 slot); +Bag *Save_Bag_Get(SaveData *saveData); #endif //POKEDIAMOND_BAG_H diff --git a/include/bag_cursor.h b/include/bag_cursor.h index b4acfa092..a754ef9ec 100644 --- a/include/bag_cursor.h +++ b/include/bag_cursor.h @@ -2,6 +2,7 @@ #define POKEDIAMOND_BAG_CURSOR_H #include "global.h" +#include "heap.h" typedef struct BagCursorField { u8 scroll[8]; @@ -23,4 +24,18 @@ typedef struct BagCursor { BagCursorBattle battle; } BagCursor; +BagCursor *BagCursor_New(HeapID heapId); +void BagCursor_Field_PocketGetPosition(BagCursor *cursor, u32 pocket, u8 *position, u8 *scroll); +u16 BagCursor_Field_GetPocket(BagCursor *cursor); +void BagCursor_Field_PocketSetPosition(BagCursor *cursor, u32 pocket, u8 position, u8 scroll); +void BagCursor_Field_SetPocket(BagCursor *cursor, u16 pocket); +void BagCursor_Battle_PocketGetPosition(BagCursor *cursor, u32 pocket, u8 *position, u8 *scroll); +u16 BagCursor_Battle_GetLastUsedItem(BagCursor *cursor); +u16 BagCursor_Battle_GetLastUsedPocket(BagCursor *cursor); +u16 BagCursor_Battle_GetPocket(BagCursor *cursor); +void BagCursor_Battle_PocketSetPosition(BagCursor *cursor, u32 pocket, u8 position, u8 scroll); +void BagCursor_Battle_Init(BagCursor *cursor); +void BagCursor_Battle_SetLastUsedItem(BagCursor *cursor, u16 itemId, u16 pocket); +void BagCursor_Battle_SetPocket(BagCursor *cursor, u16 pocket); + #endif // POKEDIAMOND_BAG_CURSOR_H diff --git a/include/constants/items.h b/include/constants/items.h index 34b71487c..84c37fe92 100644 --- a/include/constants/items.h +++ b/include/constants/items.h @@ -10,6 +10,8 @@ #define POCKET_BATTLE_ITEMS 6 #define POCKET_KEY_ITEMS 7 +#define POCKET_BAG_VIEW_END 0xFF + #define NUM_BAG_ITEMS 165 #define NUM_BAG_KEY_ITEMS 50 #define NUM_BAG_TMS_HMS 100 @@ -19,6 +21,9 @@ #define NUM_BAG_BALLS 15 #define NUM_BAG_BATTLE_ITEMS 30 +#define BAG_SLOT_QUANTITY_MAX 999 +#define BAG_TMHM_QUANTITY_MAX 99 + #define ITEMATTR_PRICE 0 #define ITEMATTR_HOLD_EFFECT 1 #define ITEMATTR_HOLD_EFFECT_PARAM 2 diff --git a/include/constants/save_arrays.h b/include/constants/save_arrays.h index 4086911b7..15374baef 100644 --- a/include/constants/save_arrays.h +++ b/include/constants/save_arrays.h @@ -1,6 +1,7 @@ #ifndef POKEDIAMOND_CONSTANTS_SAVE_ARRAYS_H #define POKEDIAMOND_CONSTANTS_SAVE_ARRAYS_H +#define SAVE_BAG 3 #define SAVE_SAFARI_ZONE 27 #define SAVE_BLOCK_NUM 36 diff --git a/tools/nitrogfx/LICENSE b/tools/nitrogfx/LICENSE index b66bf81c0..1575ad654 100644 --- a/tools/nitrogfx/LICENSE +++ b/tools/nitrogfx/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2015 YamaArashi +Copyright (c) 2015 YamaArashi, 2021-2023 red031000 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/tools/nitrogfx/Makefile b/tools/nitrogfx/Makefile index 940d6eda2..f4c67d07a 100644 --- a/tools/nitrogfx/Makefile +++ b/tools/nitrogfx/Makefile @@ -19,7 +19,7 @@ all: nitrogfx @: nitrogfx-debug: $(SRCS) convert_png.h gfx.h global.h jasc_pal.h lz.h rl.h util.h font.h json.h cJSON.h - $(CC) $(CFLAGS) -DDEBUG $(SRCS) -o $@ $(LDFLAGS) $(LIBS) + $(CC) $(CFLAGS) -g -DDEBUG $(SRCS) -o $@ $(LDFLAGS) $(LIBS) nitrogfx: $(SRCS) convert_png.h gfx.h global.h jasc_pal.h lz.h rl.h util.h font.h json.h cJSON.h $(CC) $(CFLAGS) $(SRCS) -o $@ $(LDFLAGS) $(LIBS) diff --git a/tools/nitrogfx/cJSON.c b/tools/nitrogfx/cJSON.c index b0c12115d..3063f74e9 100644 --- a/tools/nitrogfx/cJSON.c +++ b/tools/nitrogfx/cJSON.c @@ -96,9 +96,9 @@ CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void) return (const char*) (global_error.json + global_error.position); } -CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item) +CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item) { - if (!cJSON_IsString(item)) + if (!cJSON_IsString(item)) { return NULL; } @@ -106,9 +106,9 @@ CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item) return item->valuestring; } -CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item) +CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item) { - if (!cJSON_IsNumber(item)) + if (!cJSON_IsNumber(item)) { return (double) NAN; } @@ -117,8 +117,8 @@ CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item) } /* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ -#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 14) -#error cJSON.h and cJSON.c have different versions. Make sure that both have the same. +#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 15) + #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. #endif CJSON_PUBLIC(const char*) cJSON_Version(void) @@ -347,7 +347,7 @@ static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_bu goto loop_end; } } - loop_end: +loop_end: number_c_string[i] = '\0'; number = strtod((const char*)number_c_string, (char**)&after_end); @@ -511,7 +511,7 @@ static unsigned char* ensure(printbuffer * const p, size_t needed) return NULL; } - + memcpy(newbuffer, p->buffer, p->offset + 1); p->hooks.deallocate(p->buffer); } @@ -761,7 +761,7 @@ static unsigned char utf16_literal_to_utf8(const unsigned char * const input_poi return sequence_length; - fail: +fail: return 0; } @@ -820,7 +820,7 @@ static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_bu { *output_pointer++ = *input_pointer++; } - /* escape sequence */ + /* escape sequence */ else { unsigned char sequence_length = 2; @@ -852,7 +852,7 @@ static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_bu *output_pointer++ = input_pointer[1]; break; - /* UTF-16 literal */ + /* UTF-16 literal */ case 'u': sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer); if (sequence_length == 0) @@ -880,7 +880,7 @@ static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_bu return true; - fail: +fail: if (output != NULL) { input_buffer->hooks.deallocate(output); @@ -1045,7 +1045,7 @@ static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer) while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32)) { - buffer->offset++; + buffer->offset++; } if (buffer->offset == buffer->length) @@ -1103,7 +1103,7 @@ CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer } buffer.content = (const unsigned char*)value; - buffer.length = buffer_length; + buffer.length = buffer_length; buffer.offset = 0; buffer.hooks = global_hooks; @@ -1135,7 +1135,7 @@ CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer return item; - fail: +fail: if (item != NULL) { cJSON_Delete(item); @@ -1230,7 +1230,7 @@ static unsigned char *print(const cJSON * const item, cJSON_bool format, const i return printed; - fail: +fail: if (buffer->buffer != NULL) { hooks->deallocate(buffer->buffer); @@ -1508,7 +1508,7 @@ static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buf goto fail; /* expected end of array */ } - success: +success: input_buffer->depth--; if (head != NULL) { @@ -1522,7 +1522,7 @@ static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buf return true; - fail: +fail: if (head != NULL) { cJSON_Delete(head); @@ -1684,7 +1684,7 @@ static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_bu goto fail; /* expected end of object */ } - success: +success: input_buffer->depth--; if (head != NULL) { @@ -1697,7 +1697,7 @@ static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_bu input_buffer->offset++; return true; - fail: +fail: if (head != NULL) { cJSON_Delete(head); @@ -1989,7 +1989,7 @@ CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item) } #if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) -#pragma GCC diagnostic push + #pragma GCC diagnostic push #endif #ifdef __GNUC__ #pragma GCC diagnostic ignored "-Wcast-qual" @@ -2000,7 +2000,7 @@ static void* cast_away_const(const void* string) return (void*)string; } #if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) -#pragma GCC diagnostic pop + #pragma GCC diagnostic pop #endif @@ -2689,7 +2689,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int co if (a && a->child) { a->child->prev = n; } - + return a; } @@ -2768,7 +2768,7 @@ CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse) return newitem; - fail: +fail: if (newitem != NULL) { cJSON_Delete(newitem); @@ -2976,7 +2976,7 @@ CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item) CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive) { - if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)) || cJSON_IsInvalid(a)) + if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF))) { return false; } diff --git a/tools/nitrogfx/cJSON.h b/tools/nitrogfx/cJSON.h index 94b2efe09..92907a2cd 100644 --- a/tools/nitrogfx/cJSON.h +++ b/tools/nitrogfx/cJSON.h @@ -81,7 +81,7 @@ then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJ /* project version */ #define CJSON_VERSION_MAJOR 1 #define CJSON_VERSION_MINOR 7 -#define CJSON_VERSION_PATCH 14 +#define CJSON_VERSION_PATCH 15 #include @@ -124,9 +124,9 @@ typedef struct cJSON typedef struct cJSON_Hooks { - /* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */ - void *(CJSON_CDECL *malloc_fn)(size_t sz); - void (CJSON_CDECL *free_fn)(void *ptr); + /* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */ + void *(CJSON_CDECL *malloc_fn)(size_t sz); + void (CJSON_CDECL *free_fn)(void *ptr); } cJSON_Hooks; typedef int cJSON_bool; @@ -255,8 +255,8 @@ CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse); CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive); /* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from strings. - * The input pointer json cannot point to a read-only address area, such as a string constant, - * but should point to a readable and writable adress area. */ + * The input pointer json cannot point to a read-only address area, such as a string constant, + * but should point to a readable and writable address area. */ CJSON_PUBLIC(void) cJSON_Minify(char *json); /* Helper functions for creating and adding items to an object at the same time. diff --git a/tools/nitrogfx/gfx.c b/tools/nitrogfx/gfx.c index 43e8f83c5..a87dae45d 100644 --- a/tools/nitrogfx/gfx.c +++ b/tools/nitrogfx/gfx.c @@ -1,4 +1,4 @@ -// Copyright (c) 2015 YamaArashi +// Copyright (c) 2015 YamaArashi, 2021-2023 red031000 #include #include @@ -21,89 +21,103 @@ static void AdvanceMetatilePosition(int *subTileX, int *subTileY, int *metatileX, int *metatileY, int metatilesWide, int metatileWidth, int metatileHeight) { - (*subTileX)++; - if (*subTileX == metatileWidth) { - *subTileX = 0; - (*subTileY)++; - if (*subTileY == metatileHeight) { - *subTileY = 0; - (*metatileX)++; - if (*metatileX == metatilesWide) { - *metatileX = 0; - (*metatileY)++; - } - } - } + (*subTileX)++; + if (*subTileX == metatileWidth) { + *subTileX = 0; + (*subTileY)++; + if (*subTileY == metatileHeight) { + *subTileY = 0; + (*metatileX)++; + if (*metatileX == metatilesWide) { + *metatileX = 0; + (*metatileY)++; + } + } + } } static void ConvertFromTiles1Bpp(unsigned char *src, unsigned char *dest, int numTiles, int metatilesWide, int metatileWidth, int metatileHeight, bool invertColors) { - int subTileX = 0; - int subTileY = 0; - int metatileX = 0; - int metatileY = 0; - int pitch = metatilesWide * metatileWidth; + int subTileX = 0; + int subTileY = 0; + int metatileX = 0; + int metatileY = 0; + int pitch = metatilesWide * metatileWidth; - for (int i = 0; i < numTiles; i++) { - for (int j = 0; j < 8; j++) { - int destY = (metatileY * metatileHeight + subTileY) * 8 + j; - int destX = metatileX * metatileWidth + subTileX; - unsigned char srcPixelOctet = *src++; - unsigned char *destPixelOctet = &dest[destY * pitch + destX]; + for (int i = 0; i < numTiles; i++) { + for (int j = 0; j < 8; j++) { + int destY = (metatileY * metatileHeight + subTileY) * 8 + j; + int destX = metatileX * metatileWidth + subTileX; + unsigned char srcPixelOctet = *src++; + unsigned char *destPixelOctet = &dest[destY * pitch + destX]; - for (int k = 0; k < 8; k++) { - *destPixelOctet <<= 1; - *destPixelOctet |= (srcPixelOctet & 1) ^ invertColors; - srcPixelOctet >>= 1; - } - } + for (int k = 0; k < 8; k++) { + *destPixelOctet <<= 1; + *destPixelOctet |= (srcPixelOctet & 1) ^ invertColors; + srcPixelOctet >>= 1; + } + } - AdvanceMetatilePosition(&subTileX, &subTileY, &metatileX, &metatileY, metatilesWide, metatileWidth, metatileHeight); - } + AdvanceMetatilePosition(&subTileX, &subTileY, &metatileX, &metatileY, metatilesWide, metatileWidth, metatileHeight); + } } static void ConvertFromTiles4Bpp(unsigned char *src, unsigned char *dest, int numTiles, int metatilesWide, int metatileWidth, int metatileHeight, bool invertColors) { - int subTileX = 0; - int subTileY = 0; - int metatileX = 0; - int metatileY = 0; - int pitch = (metatilesWide * metatileWidth) * 4; + int subTileX = 0; + int subTileY = 0; + int metatileX = 0; + int metatileY = 0; + int pitch = (metatilesWide * metatileWidth) * 4; - for (int i = 0; i < numTiles; i++) { - for (int j = 0; j < 8; j++) { - int destY = (metatileY * metatileHeight + subTileY) * 8 + j; + for (int i = 0; i < numTiles; i++) { + for (int j = 0; j < 8; j++) { + int destY = (metatileY * metatileHeight + subTileY) * 8 + j; - for (int k = 0; k < 4; k++) { - int destX = (metatileX * metatileWidth + subTileX) * 4 + k; - unsigned char srcPixelPair = *src++; - unsigned char leftPixel = srcPixelPair & 0xF; - unsigned char rightPixel = srcPixelPair >> 4; + for (int k = 0; k < 4; k++) { + int destX = (metatileX * metatileWidth + subTileX) * 4 + k; + unsigned char srcPixelPair = *src++; + unsigned char leftPixel = srcPixelPair & 0xF; + unsigned char rightPixel = srcPixelPair >> 4; - if (invertColors) { - leftPixel = 15 - leftPixel; - rightPixel = 15 - rightPixel; - } + if (invertColors) { + leftPixel = 15 - leftPixel; + rightPixel = 15 - rightPixel; + } - dest[destY * pitch + destX] = (leftPixel << 4) | rightPixel; - } - } + dest[destY * pitch + destX] = (leftPixel << 4) | rightPixel; + } + } - AdvanceMetatilePosition(&subTileX, &subTileY, &metatileX, &metatileY, metatilesWide, metatileWidth, metatileHeight); - } + AdvanceMetatilePosition(&subTileX, &subTileY, &metatileX, &metatileY, metatilesWide, metatileWidth, metatileHeight); + } } -static uint32_t ConvertFromScanned4Bpp(unsigned char *src, unsigned char *dest, int fileSize, bool invertColours) +static uint32_t ConvertFromScanned4Bpp(unsigned char *src, unsigned char *dest, int fileSize, bool invertColours, bool scanFrontToBack) { - uint32_t encValue = (src[fileSize - 1] << 8) | src[fileSize - 2]; - for (int i = fileSize; i > 0; i -= 2) - { - uint16_t val = (src[i - 1] << 8) | src[i - 2]; - val ^= (encValue & 0xFFFF); - src[i - 1] = (val >> 8); - src[i - 2] = (unsigned char)val; - encValue = encValue * 1103515245; - encValue = encValue + 24691; + uint32_t encValue = 0; + if (scanFrontToBack) { + encValue = (src[1] << 8) | src[0]; + for (int i = 0; i < fileSize; i += 2) + { + uint16_t val = src[i] | (src[i + 1] << 8); + val ^= (encValue & 0xFFFF); + src[i] = val; + src[i + 1] = val >> 8; + encValue = encValue * 1103515245; + encValue = encValue + 24691; + } + } else { + encValue = (src[fileSize - 1] << 8) | src[fileSize - 2]; + for (int i = fileSize; i > 0; i -= 2) + { + uint16_t val = (src[i - 1] << 8) | src[i - 2]; + val ^= (encValue & 0xFFFF); + src[i - 1] = (val >> 8); + src[i - 2] = val; + encValue = encValue * 1103515245; + encValue = encValue + 24691; + } } for (int i = 0; i < fileSize; i++) { @@ -123,89 +137,89 @@ static uint32_t ConvertFromScanned4Bpp(unsigned char *src, unsigned char *dest, static void ConvertFromTiles8Bpp(unsigned char *src, unsigned char *dest, int numTiles, int metatilesWide, int metatileWidth, int metatileHeight, bool invertColors) { - int subTileX = 0; - int subTileY = 0; - int metatileX = 0; - int metatileY = 0; - int pitch = (metatilesWide * metatileWidth) * 8; + int subTileX = 0; + int subTileY = 0; + int metatileX = 0; + int metatileY = 0; + int pitch = (metatilesWide * metatileWidth) * 8; - for (int i = 0; i < numTiles; i++) { - for (int j = 0; j < 8; j++) { - int destY = (metatileY * metatileHeight + subTileY) * 8 + j; + for (int i = 0; i < numTiles; i++) { + for (int j = 0; j < 8; j++) { + int destY = (metatileY * metatileHeight + subTileY) * 8 + j; - for (int k = 0; k < 8; k++) { - int destX = (metatileX * metatileWidth + subTileX) * 8 + k; - unsigned char srcPixel = *src++; + for (int k = 0; k < 8; k++) { + int destX = (metatileX * metatileWidth + subTileX) * 8 + k; + unsigned char srcPixel = *src++; - if (invertColors) - srcPixel = 255 - srcPixel; + if (invertColors) + srcPixel = 255 - srcPixel; - dest[destY * pitch + destX] = srcPixel; - } - } + dest[destY * pitch + destX] = srcPixel; + } + } - AdvanceMetatilePosition(&subTileX, &subTileY, &metatileX, &metatileY, metatilesWide, metatileWidth, metatileHeight); - } + AdvanceMetatilePosition(&subTileX, &subTileY, &metatileX, &metatileY, metatilesWide, metatileWidth, metatileHeight); + } } static void ConvertToTiles1Bpp(unsigned char *src, unsigned char *dest, int numTiles, int metatilesWide, int metatileWidth, int metatileHeight, bool invertColors) { - int subTileX = 0; - int subTileY = 0; - int metatileX = 0; - int metatileY = 0; - int pitch = metatilesWide * metatileWidth; + int subTileX = 0; + int subTileY = 0; + int metatileX = 0; + int metatileY = 0; + int pitch = metatilesWide * metatileWidth; - for (int i = 0; i < numTiles; i++) { - for (int j = 0; j < 8; j++) { - int srcY = (metatileY * metatileHeight + subTileY) * 8 + j; - int srcX = metatileX * metatileWidth + subTileX; - unsigned char srcPixelOctet = src[srcY * pitch + srcX]; - unsigned char *destPixelOctet = dest++; + for (int i = 0; i < numTiles; i++) { + for (int j = 0; j < 8; j++) { + int srcY = (metatileY * metatileHeight + subTileY) * 8 + j; + int srcX = metatileX * metatileWidth + subTileX; + unsigned char srcPixelOctet = src[srcY * pitch + srcX]; + unsigned char *destPixelOctet = dest++; - for (int k = 0; k < 8; k++) { - *destPixelOctet <<= 1; - *destPixelOctet |= (srcPixelOctet & 1) ^ invertColors; - srcPixelOctet >>= 1; - } - } + for (int k = 0; k < 8; k++) { + *destPixelOctet <<= 1; + *destPixelOctet |= (srcPixelOctet & 1) ^ invertColors; + srcPixelOctet >>= 1; + } + } - AdvanceMetatilePosition(&subTileX, &subTileY, &metatileX, &metatileY, metatilesWide, metatileWidth, metatileHeight); - } + AdvanceMetatilePosition(&subTileX, &subTileY, &metatileX, &metatileY, metatilesWide, metatileWidth, metatileHeight); + } } static void ConvertToTiles4Bpp(unsigned char *src, unsigned char *dest, int numTiles, int metatilesWide, int metatileWidth, int metatileHeight, bool invertColors) { - int subTileX = 0; - int subTileY = 0; - int metatileX = 0; - int metatileY = 0; - int pitch = (metatilesWide * metatileWidth) * 4; + int subTileX = 0; + int subTileY = 0; + int metatileX = 0; + int metatileY = 0; + int pitch = (metatilesWide * metatileWidth) * 4; - for (int i = 0; i < numTiles; i++) { - for (int j = 0; j < 8; j++) { - int srcY = (metatileY * metatileHeight + subTileY) * 8 + j; + for (int i = 0; i < numTiles; i++) { + for (int j = 0; j < 8; j++) { + int srcY = (metatileY * metatileHeight + subTileY) * 8 + j; - for (int k = 0; k < 4; k++) { - int srcX = (metatileX * metatileWidth + subTileX) * 4 + k; - unsigned char srcPixelPair = src[srcY * pitch + srcX]; - unsigned char leftPixel = srcPixelPair >> 4; - unsigned char rightPixel = srcPixelPair & 0xF; + for (int k = 0; k < 4; k++) { + int srcX = (metatileX * metatileWidth + subTileX) * 4 + k; + unsigned char srcPixelPair = src[srcY * pitch + srcX]; + unsigned char leftPixel = srcPixelPair >> 4; + unsigned char rightPixel = srcPixelPair & 0xF; - if (invertColors) { - leftPixel = 15 - leftPixel; - rightPixel = 15 - rightPixel; - } + if (invertColors) { + leftPixel = 15 - leftPixel; + rightPixel = 15 - rightPixel; + } - *dest++ = (rightPixel << 4) | leftPixel; - } - } + *dest++ = (rightPixel << 4) | leftPixel; + } + } - AdvanceMetatilePosition(&subTileX, &subTileY, &metatileX, &metatileY, metatilesWide, metatileWidth, metatileHeight); - } + AdvanceMetatilePosition(&subTileX, &subTileY, &metatileX, &metatileY, metatilesWide, metatileWidth, metatileHeight); + } } -static void ConvertToScanned4Bpp(unsigned char *src, unsigned char *dest, int fileSize, bool invertColours, uint32_t encValue) +static void ConvertToScanned4Bpp(unsigned char *src, unsigned char *dest, int fileSize, bool invertColours, uint32_t encValue, uint32_t scanMode) { for (int i = 0; i < fileSize; i++) { @@ -219,86 +233,98 @@ static void ConvertToScanned4Bpp(unsigned char *src, unsigned char *dest, int fi dest[i] = (leftPixel << 4) | rightPixel; } - for (int i = 1; i < fileSize; i += 2) - { - uint16_t val = (dest[i] << 8) | dest[i - 1]; - encValue = (encValue - 24691) * 4005161829; - val ^= (encValue & 0xFFFF); - dest[i] = (val >> 8); - dest[i - 1] = (unsigned char)val; + if (scanMode == 2) { // front to back + for (int i = fileSize - 1; i > 0; i -= 2) + { + uint16_t val = dest[i - 1] | (dest[i] << 8); + encValue = (encValue - 24691) * 4005161829; + val ^= (encValue & 0xFFFF); + dest[i] = (val >> 8); + dest[i - 1] = val; + } + } + else if (scanMode == 1) { + for (int i = 1; i < fileSize; i += 2) + { + uint16_t val = (dest[i] << 8) | dest[i - 1]; + encValue = (encValue - 24691) * 4005161829; + val ^= (encValue & 0xFFFF); + dest[i] = (val >> 8); + dest[i - 1] = val; + } } } static void ConvertToTiles8Bpp(unsigned char *src, unsigned char *dest, int numTiles, int metatilesWide, int metatileWidth, int metatileHeight, bool invertColors) { - int subTileX = 0; - int subTileY = 0; - int metatileX = 0; - int metatileY = 0; - int pitch = (metatilesWide * metatileWidth) * 8; + int subTileX = 0; + int subTileY = 0; + int metatileX = 0; + int metatileY = 0; + int pitch = (metatilesWide * metatileWidth) * 8; - for (int i = 0; i < numTiles; i++) { - for (int j = 0; j < 8; j++) { - int srcY = (metatileY * metatileHeight + subTileY) * 8 + j; + for (int i = 0; i < numTiles; i++) { + for (int j = 0; j < 8; j++) { + int srcY = (metatileY * metatileHeight + subTileY) * 8 + j; - for (int k = 0; k < 8; k++) { - int srcX = (metatileX * metatileWidth + subTileX) * 8 + k; - unsigned char srcPixel = src[srcY * pitch + srcX]; + for (int k = 0; k < 8; k++) { + int srcX = (metatileX * metatileWidth + subTileX) * 8 + k; + unsigned char srcPixel = src[srcY * pitch + srcX]; - if (invertColors) - srcPixel = 255 - srcPixel; + if (invertColors) + srcPixel = 255 - srcPixel; - *dest++ = srcPixel; - } - } + *dest++ = srcPixel; + } + } - AdvanceMetatilePosition(&subTileX, &subTileY, &metatileX, &metatileY, metatilesWide, metatileWidth, metatileHeight); - } + AdvanceMetatilePosition(&subTileX, &subTileY, &metatileX, &metatileY, metatilesWide, metatileWidth, metatileHeight); + } } void ReadImage(char *path, int tilesWidth, int bitDepth, int metatileWidth, int metatileHeight, struct Image *image, bool invertColors) { - int tileSize = bitDepth * 8; + int tileSize = bitDepth * 8; - int fileSize; - unsigned char *buffer = ReadWholeFile(path, &fileSize); + int fileSize; + unsigned char *buffer = ReadWholeFile(path, &fileSize); - int numTiles = fileSize / tileSize; + int numTiles = fileSize / tileSize; - int tilesHeight = (numTiles + tilesWidth - 1) / tilesWidth; + int tilesHeight = (numTiles + tilesWidth - 1) / tilesWidth; - if (tilesWidth % metatileWidth != 0) - FATAL_ERROR("The width in tiles (%d) isn't a multiple of the specified metatile width (%d)", tilesWidth, metatileWidth); + if (tilesWidth % metatileWidth != 0) + FATAL_ERROR("The width in tiles (%d) isn't a multiple of the specified metatile width (%d)", tilesWidth, metatileWidth); - if (tilesHeight % metatileHeight != 0) - FATAL_ERROR("The height in tiles (%d) isn't a multiple of the specified metatile height (%d)", tilesHeight, metatileHeight); + if (tilesHeight % metatileHeight != 0) + FATAL_ERROR("The height in tiles (%d) isn't a multiple of the specified metatile height (%d)", tilesHeight, metatileHeight); - image->width = tilesWidth * 8; - image->height = tilesHeight * 8; - image->bitDepth = bitDepth; - image->pixels = calloc(tilesWidth * tilesHeight, tileSize); + image->width = tilesWidth * 8; + image->height = tilesHeight * 8; + image->bitDepth = bitDepth; + image->pixels = calloc(tilesWidth * tilesHeight, tileSize); - if (image->pixels == NULL) - FATAL_ERROR("Failed to allocate memory for pixels.\n"); + if (image->pixels == NULL) + FATAL_ERROR("Failed to allocate memory for pixels.\n"); - int metatilesWide = tilesWidth / metatileWidth; + int metatilesWide = tilesWidth / metatileWidth; - switch (bitDepth) { - case 1: - ConvertFromTiles1Bpp(buffer, image->pixels, numTiles, metatilesWide, metatileWidth, metatileHeight, invertColors); - break; - case 4: - ConvertFromTiles4Bpp(buffer, image->pixels, numTiles, metatilesWide, metatileWidth, metatileHeight, invertColors); - break; - case 8: - ConvertFromTiles8Bpp(buffer, image->pixels, numTiles, metatilesWide, metatileWidth, metatileHeight, invertColors); - break; - } + switch (bitDepth) { + case 1: + ConvertFromTiles1Bpp(buffer, image->pixels, numTiles, metatilesWide, metatileWidth, metatileHeight, invertColors); + break; + case 4: + ConvertFromTiles4Bpp(buffer, image->pixels, numTiles, metatilesWide, metatileWidth, metatileHeight, invertColors); + break; + case 8: + ConvertFromTiles8Bpp(buffer, image->pixels, numTiles, metatilesWide, metatileWidth, metatileHeight, invertColors); + break; + } - free(buffer); + free(buffer); } -uint32_t ReadNtrImage(char *path, int tilesWidth, int bitDepth, int metatileWidth, int metatileHeight, struct Image *image, bool invertColors) +uint32_t ReadNtrImage(char *path, int tilesWidth, int bitDepth, int metatileWidth, int metatileHeight, struct Image *image, bool invertColors, bool scanFrontToBack) { int fileSize; unsigned char *buffer = ReadWholeFile(path, &fileSize); @@ -328,10 +354,18 @@ uint32_t ReadNtrImage(char *path, int tilesWidth, int bitDepth, int metatileWidt int tileSize = bitDepth * 8; - int numTiles = (charHeader[0x18] + (charHeader[0x19] << 8) + (charHeader[0x1A] << 16) + (charHeader[0x1B] << 24)) - / (64 / (8 / bitDepth)); + if (tilesWidth == 0) { + tilesWidth = ReadS16(charHeader, 0xA); + if (tilesWidth < 0) { + tilesWidth = 1; + } + } - int tilesHeight = (numTiles + tilesWidth - 1) / tilesWidth; + int numTiles = ReadS32(charHeader, 0x18) / (64 / (8 / bitDepth)); + + int tilesHeight = ReadS16(charHeader, 0x8); + if (tilesHeight < 0) + tilesHeight = (numTiles + tilesWidth - 1) / tilesWidth; if (tilesWidth % metatileWidth != 0) FATAL_ERROR("The width in tiles (%d) isn't a multiple of the specified metatile width (%d)", tilesWidth, metatileWidth); @@ -347,7 +381,7 @@ uint32_t ReadNtrImage(char *path, int tilesWidth, int bitDepth, int metatileWidt if (image->pixels == NULL) FATAL_ERROR("Failed to allocate memory for pixels.\n"); - + int metatilesWide = tilesWidth / metatileWidth; uint32_t key = 0; @@ -356,7 +390,7 @@ uint32_t ReadNtrImage(char *path, int tilesWidth, int bitDepth, int metatileWidt switch (bitDepth) { case 4: - key = ConvertFromScanned4Bpp(imageData, image->pixels, fileSize - 0x30, invertColors); + key = ConvertFromScanned4Bpp(imageData, image->pixels, fileSize - 0x30, invertColors, scanFrontToBack); break; case 8: FATAL_ERROR("8bpp is not implemented yet\n"); @@ -384,57 +418,57 @@ uint32_t ReadNtrImage(char *path, int tilesWidth, int bitDepth, int metatileWidt void WriteImage(char *path, int numTiles, int bitDepth, int metatileWidth, int metatileHeight, struct Image *image, bool invertColors) { - int tileSize = bitDepth * 8; + int tileSize = bitDepth * 8; - if (image->width % 8 != 0) - FATAL_ERROR("The width in pixels (%d) isn't a multiple of 8.\n", image->width); + if (image->width % 8 != 0) + FATAL_ERROR("The width in pixels (%d) isn't a multiple of 8.\n", image->width); - if (image->height % 8 != 0) - FATAL_ERROR("The height in pixels (%d) isn't a multiple of 8.\n", image->height); + if (image->height % 8 != 0) + FATAL_ERROR("The height in pixels (%d) isn't a multiple of 8.\n", image->height); - int tilesWidth = image->width / 8; - int tilesHeight = image->height / 8; + int tilesWidth = image->width / 8; + int tilesHeight = image->height / 8; - if (tilesWidth % metatileWidth != 0) - FATAL_ERROR("The width in tiles (%d) isn't a multiple of the specified metatile width (%d)", tilesWidth, metatileWidth); + if (tilesWidth % metatileWidth != 0) + FATAL_ERROR("The width in tiles (%d) isn't a multiple of the specified metatile width (%d)", tilesWidth, metatileWidth); - if (tilesHeight % metatileHeight != 0) - FATAL_ERROR("The height in tiles (%d) isn't a multiple of the specified metatile height (%d)", tilesHeight, metatileHeight); + if (tilesHeight % metatileHeight != 0) + FATAL_ERROR("The height in tiles (%d) isn't a multiple of the specified metatile height (%d)", tilesHeight, metatileHeight); - int maxNumTiles = tilesWidth * tilesHeight; + int maxNumTiles = tilesWidth * tilesHeight; - if (numTiles == 0) - numTiles = maxNumTiles; - else if (numTiles > maxNumTiles) - FATAL_ERROR("The specified number of tiles (%d) is greater than the maximum possible value (%d).\n", numTiles, maxNumTiles); + if (numTiles == 0) + numTiles = maxNumTiles; + else if (numTiles > maxNumTiles) + FATAL_ERROR("The specified number of tiles (%d) is greater than the maximum possible value (%d).\n", numTiles, maxNumTiles); - int bufferSize = numTiles * tileSize; - unsigned char *buffer = malloc(bufferSize); + int bufferSize = numTiles * tileSize; + unsigned char *buffer = malloc(bufferSize); - if (buffer == NULL) - FATAL_ERROR("Failed to allocate memory for pixels.\n"); + if (buffer == NULL) + FATAL_ERROR("Failed to allocate memory for pixels.\n"); - int metatilesWide = tilesWidth / metatileWidth; + int metatilesWide = tilesWidth / metatileWidth; - switch (bitDepth) { - case 1: - ConvertToTiles1Bpp(image->pixels, buffer, numTiles, metatilesWide, metatileWidth, metatileHeight, invertColors); - break; - case 4: - ConvertToTiles4Bpp(image->pixels, buffer, numTiles, metatilesWide, metatileWidth, metatileHeight, invertColors); - break; - case 8: - ConvertToTiles8Bpp(image->pixels, buffer, numTiles, metatilesWide, metatileWidth, metatileHeight, invertColors); - break; - } + switch (bitDepth) { + case 1: + ConvertToTiles1Bpp(image->pixels, buffer, numTiles, metatilesWide, metatileWidth, metatileHeight, invertColors); + break; + case 4: + ConvertToTiles4Bpp(image->pixels, buffer, numTiles, metatilesWide, metatileWidth, metatileHeight, invertColors); + break; + case 8: + ConvertToTiles8Bpp(image->pixels, buffer, numTiles, metatilesWide, metatileWidth, metatileHeight, invertColors); + break; + } - WriteWholeFile(path, buffer, bufferSize); + WriteWholeFile(path, buffer, bufferSize); - free(buffer); + free(buffer); } void WriteNtrImage(char *path, int numTiles, int bitDepth, int metatileWidth, int metatileHeight, struct Image *image, - bool invertColors, bool clobberSize, bool byteOrder, bool version101, bool sopc, bool scanned, + bool invertColors, bool clobberSize, bool byteOrder, bool version101, bool sopc, uint32_t scanMode, uint32_t key, bool wrongSize) { FILE *fp = fopen(path, "wb"); @@ -474,12 +508,12 @@ void WriteNtrImage(char *path, int numTiles, int bitDepth, int metatileWidth, in int metatilesWide = tilesWidth / metatileWidth; - if (scanned) + if (scanMode) { switch (bitDepth) { case 4: - ConvertToScanned4Bpp(image->pixels, pixelBuffer, bufferSize, invertColors, key); + ConvertToScanned4Bpp(image->pixels, pixelBuffer, bufferSize, invertColors, key, scanMode); break; case 8: FATAL_ERROR("8Bpp not supported yet.\n"); @@ -531,7 +565,7 @@ void WriteNtrImage(char *path, int numTiles, int bitDepth, int metatileWidth, in charHeader[12] = bitDepth == 4 ? 3 : 4; - if (scanned) + if (scanMode) { charHeader[20] = 1; } @@ -546,8 +580,8 @@ void WriteNtrImage(char *path, int numTiles, int bitDepth, int metatileWidth, in fwrite(pixelBuffer, 1, bufferSize, fp); if (sopc) - { - unsigned char sopcBuffer[0x10] = { 0x53, 0x4F, 0x50, 0x43, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + { + unsigned char sopcBuffer[0x10] = { 0x53, 0x4F, 0x50, 0x43, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; sopcBuffer[12] = tilesWidth & 0xFF; sopcBuffer[13] = (tilesWidth >> 8) & 0xFF; @@ -556,7 +590,7 @@ void WriteNtrImage(char *path, int numTiles, int bitDepth, int metatileWidth, in sopcBuffer[15] = (tilesHeight >> 8) & 0xFF; fwrite(sopcBuffer, 1, 0x10, fp); - } + } free(pixelBuffer); fclose(fp); @@ -564,28 +598,28 @@ void WriteNtrImage(char *path, int numTiles, int bitDepth, int metatileWidth, in void FreeImage(struct Image *image) { - free(image->pixels); - image->pixels = NULL; + free(image->pixels); + image->pixels = NULL; } void ReadGbaPalette(char *path, struct Palette *palette) { - int fileSize; - unsigned char *data = ReadWholeFile(path, &fileSize); + int fileSize; + unsigned char *data = ReadWholeFile(path, &fileSize); - if (fileSize % 2 != 0) - FATAL_ERROR("The file size (%d) is not a multiple of 2.\n", fileSize); + if (fileSize % 2 != 0) + FATAL_ERROR("The file size (%d) is not a multiple of 2.\n", fileSize); - palette->numColors = fileSize / 2; + palette->numColors = fileSize / 2; - for (int i = 0; i < palette->numColors; i++) { - uint16_t paletteEntry = (data[i * 2 + 1] << 8) | data[i * 2]; - palette->colors[i].red = UPCONVERT_BIT_DEPTH(GET_GBA_PAL_RED(paletteEntry)); - palette->colors[i].green = UPCONVERT_BIT_DEPTH(GET_GBA_PAL_GREEN(paletteEntry)); - palette->colors[i].blue = UPCONVERT_BIT_DEPTH(GET_GBA_PAL_BLUE(paletteEntry)); - } + for (int i = 0; i < palette->numColors; i++) { + uint16_t paletteEntry = (data[i * 2 + 1] << 8) | data[i * 2]; + palette->colors[i].red = UPCONVERT_BIT_DEPTH(GET_GBA_PAL_RED(paletteEntry)); + palette->colors[i].green = UPCONVERT_BIT_DEPTH(GET_GBA_PAL_GREEN(paletteEntry)); + palette->colors[i].blue = UPCONVERT_BIT_DEPTH(GET_GBA_PAL_BLUE(paletteEntry)); + } - free(data); + free(data); } void ReadNtrPalette(char *path, struct Palette *palette, int bitdepth, int palIndex) @@ -619,19 +653,19 @@ void ReadNtrPalette(char *path, struct Palette *palette, int bitdepth, int palIn for (int i = 0; i < 256; i++) { - if (i < palette->numColors) - { - uint16_t paletteEntry = (paletteData[(32 * palIndex) + i * 2 + 1] << 8) | paletteData[(32 * palIndex) + i * 2]; - palette->colors[i].red = UPCONVERT_BIT_DEPTH(GET_GBA_PAL_RED(paletteEntry)); - palette->colors[i].green = UPCONVERT_BIT_DEPTH(GET_GBA_PAL_GREEN(paletteEntry)); - palette->colors[i].blue = UPCONVERT_BIT_DEPTH(GET_GBA_PAL_BLUE(paletteEntry)); - } - else - { - palette->colors[i].red = 0; - palette->colors[i].green = 0; - palette->colors[i].blue = 0; - } + if (i < palette->numColors) + { + uint16_t paletteEntry = (paletteData[(32 * palIndex) + i * 2 + 1] << 8) | paletteData[(32 * palIndex) + i * 2]; + palette->colors[i].red = UPCONVERT_BIT_DEPTH(GET_GBA_PAL_RED(paletteEntry)); + palette->colors[i].green = UPCONVERT_BIT_DEPTH(GET_GBA_PAL_GREEN(paletteEntry)); + palette->colors[i].blue = UPCONVERT_BIT_DEPTH(GET_GBA_PAL_BLUE(paletteEntry)); + } + else + { + palette->colors[i].red = 0; + palette->colors[i].green = 0; + palette->colors[i].blue = 0; + } } free(data); @@ -639,23 +673,23 @@ void ReadNtrPalette(char *path, struct Palette *palette, int bitdepth, int palIn void WriteGbaPalette(char *path, struct Palette *palette) { - FILE *fp = fopen(path, "wb"); + FILE *fp = fopen(path, "wb"); - if (fp == NULL) - FATAL_ERROR("Failed to open \"%s\" for writing.\n", path); + if (fp == NULL) + FATAL_ERROR("Failed to open \"%s\" for writing.\n", path); - for (int i = 0; i < palette->numColors; i++) { - unsigned char red = DOWNCONVERT_BIT_DEPTH(palette->colors[i].red); - unsigned char green = DOWNCONVERT_BIT_DEPTH(palette->colors[i].green); - unsigned char blue = DOWNCONVERT_BIT_DEPTH(palette->colors[i].blue); + for (int i = 0; i < palette->numColors; i++) { + unsigned char red = DOWNCONVERT_BIT_DEPTH(palette->colors[i].red); + unsigned char green = DOWNCONVERT_BIT_DEPTH(palette->colors[i].green); + unsigned char blue = DOWNCONVERT_BIT_DEPTH(palette->colors[i].blue); - uint16_t paletteEntry = SET_GBA_PAL(red, green, blue); + uint16_t paletteEntry = SET_GBA_PAL(red, green, blue); - fputc(paletteEntry & 0xFF, fp); - fputc(paletteEntry >> 8, fp); - } + fputc(paletteEntry & 0xFF, fp); + fputc(paletteEntry >> 8, fp); + } - fclose(fp); + fclose(fp); } void WriteNtrPalette(char *path, struct Palette *palette, bool ncpr, bool ir, int bitdepth, bool pad, int compNum) @@ -742,10 +776,10 @@ void WriteNtrPalette(char *path, struct Palette *palette, bool ncpr, bool ir, in void WriteNtrCell(char *path, struct JsonToCellOptions *options) { - FILE *fp = fopen(path, "wb"); + FILE *fp = fopen(path, "wb"); - if (fp == NULL) - FATAL_ERROR("Failed to open \"%s\" for writing.\n", path); + if (fp == NULL) + FATAL_ERROR("Failed to open \"%s\" for writing.\n", path); unsigned int totalSize = (options->labelEnabled > 0 ? 0x34 : 0x20) + options->cellCount * (options->extended ? 0x16 : 0xe); @@ -757,44 +791,44 @@ void WriteNtrCell(char *path, struct JsonToCellOptions *options) } } - WriteGenericNtrHeader(fp, "RECN", totalSize, true, false, options->labelEnabled ? 3 : 1); + WriteGenericNtrHeader(fp, "RECN", totalSize, true, false, options->labelEnabled ? 3 : 1); - unsigned char KBECHeader[0x20] = + unsigned char KBECHeader[0x20] = { - 0x4B, 0x42, 0x45, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + 0x4B, 0x42, 0x45, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - KBECHeader[8] = options->cellCount; //cell count + KBECHeader[8] = options->cellCount; //cell count - if (options->extended) + if (options->extended) { - KBECHeader[10] = 1; //extended + KBECHeader[10] = 1; //extended } - unsigned int size = options->cellCount * (options->extended ? 0x16 : 0xe); + unsigned int size = options->cellCount * (options->extended ? 0x16 : 0xe); - KBECHeader[4] = (size + 0x20) & 0xFF; //size - KBECHeader[5] = (size + 0x20) >> 8; //unlikely to be more than 16 bits, but there are 32 allocated, change if necessary + KBECHeader[4] = (size + 0x20) & 0xFF; //size + KBECHeader[5] = (size + 0x20) >> 8; //unlikely to be more than 16 bits, but there are 32 allocated, change if necessary - KBECHeader[16] = (options->mappingType & 0xFF); //not possible to be more than 8 bits, though 32 are allocated + KBECHeader[16] = (options->mappingType & 0xFF); //not possible to be more than 8 bits, though 32 are allocated - fwrite(KBECHeader, 1, 0x20, fp); + fwrite(KBECHeader, 1, 0x20, fp); - unsigned char *KBECContents = malloc(size); + unsigned char *KBECContents = malloc(size); - memset(KBECContents, 0, size); + memset(KBECContents, 0, size); - if (!options->extended) + if (!options->extended) { - FATAL_ERROR("Don't know how to deal with not extended yet, bug red031000.\n"); + FATAL_ERROR("Don't know how to deal with not extended yet, bug red031000.\n"); } - int i; - for (i = 0; i < options->cellCount * 0x10; i += 0x10) + int i; + for (i = 0; i < options->cellCount * 0x10; i += 0x10) { - KBECContents[i] = 0x01; //number of images - KBECContents[i + 2] = options->cells[i / 0x10]->readOnly & 0xff; //unknown + KBECContents[i] = 0x01; //number of images + KBECContents[i + 2] = options->cells[i / 0x10]->readOnly & 0xff; //unknown KBECContents[i + 3] = options->cells[i / 0x10]->readOnly >> 8; KBECContents[i + 4] = (i / 0x10 * 6) & 0xff; //pointer to OAM data KBECContents[i + 5] = (i / 0x10 * 6) >> 8; //unlikely to be more than 16 bits, but there are 32 allocated, change if necessary @@ -808,21 +842,21 @@ void WriteNtrCell(char *path, struct JsonToCellOptions *options) KBECContents[i + 15] = options->cells[i / 0x10]->minY >> 8; } - //OAM data - for (int j = i; j < options->cellCount * 6 + i; j += 6) + //OAM data + for (int j = i; j < options->cellCount * 6 + i; j += 6) { - //Attr0 + //Attr0 - //bits 0-7 Y coordinate - KBECContents[j] = options->cells[(j - i) / 6]->oam.attr0.YCoordinate & 0xff; + //bits 0-7 Y coordinate + KBECContents[j] = options->cells[(j - i) / 6]->oam.attr0.YCoordinate & 0xff; - //bit 8 rotation - KBECContents[j + 1] = options->cells[(j - i) / 6]->oam.attr0.Rotation; + //bit 8 rotation + KBECContents[j + 1] = options->cells[(j - i) / 6]->oam.attr0.Rotation; - //bit 9 Obj Size (if rotation) or Obj Disable (if not rotation) - KBECContents[j + 1] |= options->cells[(j - i) / 6]->oam.attr0.SizeDisable << 1; + //bit 9 Obj Size (if rotation) or Obj Disable (if not rotation) + KBECContents[j + 1] |= options->cells[(j - i) / 6]->oam.attr0.SizeDisable << 1; - //bits 10-11 Obj Mode + //bits 10-11 Obj Mode KBECContents[j + 1] |= options->cells[(j - i) / 6]->oam.attr0.Mode << 2; //bit 12 Obj Mosaic @@ -859,12 +893,12 @@ void WriteNtrCell(char *path, struct JsonToCellOptions *options) KBECContents[j + 5] |= options->cells[(j - i) / 6]->oam.attr2.Palette << 4; } - fwrite(KBECContents, 1, size, fp); + fwrite(KBECContents, 1, size, fp); - free(KBECContents); + free(KBECContents); - if (options->labelEnabled) - { + if (options->labelEnabled) + { unsigned int lablSize = 8; for (int j = 0; j < options->labelCount; j++) { @@ -901,20 +935,20 @@ void WriteNtrCell(char *path, struct JsonToCellOptions *options) free(labl); - unsigned char texu[0xc] = {0x54, 0x58, 0x45, 0x55, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + unsigned char txeu[0xc] = {0x54, 0x58, 0x45, 0x55, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - fwrite(texu, 1, 0xc, fp); + fwrite(txeu, 1, 0xc, fp); } - fclose(fp); + fclose(fp); } -void WriteNtrScreen(char *outputPath, struct JsonToScreenOptions *options) +void WriteNtrScreen(char *path, struct JsonToScreenOptions *options) { - FILE *fp = fopen(outputPath, "wb"); + FILE *fp = fopen(path, "wb"); if (fp == NULL) - FATAL_ERROR("Failed to open \"%s\" for writing.\n", outputPath); + FATAL_ERROR("Failed to open \"%s\" for writing.\n", path); int totalSize = options->width * options->height * 2 + 0x14; @@ -947,3 +981,224 @@ void WriteNtrScreen(char *outputPath, struct JsonToScreenOptions *options) fclose(fp); } + +void WriteNtrAnimation(char *path, struct JsonToAnimationOptions *options) +{ + FILE *fp = fopen(path, "wb"); + + if (fp == NULL) + FATAL_ERROR("Failed to open \"%s\" for writing.\n", path); + + unsigned int totalSize = 0x20 + options->sequenceCount * 0x10 + options->frameCount * 0x8; + + //todo: check these + for (int i = 0; i < options->resultCount; i++) + { + if (options->animationResults[i]->resultType == 0) + totalSize += 0x4; + else if (options->animationResults[i]->resultType == 1) + totalSize += 0x10; + else if (options->animationResults[i]->resultType == 2) + totalSize += 0x8; + } + + unsigned int KNBASize = totalSize; + + if (options->labelEnabled) + { + totalSize += options->multiCell ? 0x8 : 0x14; + for (int j = 0; j < options->labelCount; j++) + { + totalSize += (unsigned)strlen(options->labels[j]) + 5; //strlen + terminator + pointer + } + } + + WriteGenericNtrHeader(fp, options->multiCell ? "RAMN" : "RNAN", totalSize, true, false, options->labelEnabled ? (options->multiCell ? 2 : 3) : 1); + + unsigned char KBNAHeader[0x20] = + { + 0x4B, 0x4E, 0x42, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + KBNAHeader[4] = KNBASize & 0xff; + KBNAHeader[5] = (KNBASize >> 8) & 0xff; + KBNAHeader[6] = (KNBASize >> 16) & 0xff; + KBNAHeader[7] = KNBASize >> 24; + + KBNAHeader[8] = options->sequenceCount & 0xff; + KBNAHeader[9] = options->sequenceCount >> 8; + + KBNAHeader[10] = options->frameCount & 0xff; + KBNAHeader[11] = options->frameCount >> 8; + + unsigned int frameOffset = 0x18 + options->sequenceCount * 0x10; + + KBNAHeader[16] = frameOffset & 0xff; + KBNAHeader[17] = (frameOffset >> 8) & 0xff; + KBNAHeader[18] = (frameOffset >> 16) & 0xff; + KBNAHeader[19] = frameOffset >> 24; + + unsigned int resultsOffset = frameOffset + options->frameCount * 0x8; + + KBNAHeader[20] = resultsOffset & 0xff; + KBNAHeader[21] = (resultsOffset >> 8) & 0xff; + KBNAHeader[22] = (resultsOffset >> 16) & 0xff; + KBNAHeader[23] = resultsOffset >> 24; + + fwrite(KBNAHeader, 1, 0x20, fp); + + int contentsSize = KNBASize - 0x20; + unsigned char *KBNAContents = malloc(contentsSize); + + int i; + int framePtrCounter = 0; + for (i = 0; i < options->sequenceCount * 0x10; i += 0x10) + { + KBNAContents[i] = options->sequenceData[i / 0x10]->frameCount & 0xff; + KBNAContents[i + 1] = options->sequenceData[i / 0x10]->frameCount >> 8; + KBNAContents[i + 2] = options->sequenceData[i / 0x10]->loopStartFrame & 0xff; + KBNAContents[i + 3] = options->sequenceData[i / 0x10]->loopStartFrame >> 8; + KBNAContents[i + 4] = options->sequenceData[i / 0x10]->animationElement & 0xff; + KBNAContents[i + 5] = options->sequenceData[i / 0x10]->animationElement >> 8; + KBNAContents[i + 6] = options->sequenceData[i / 0x10]->animationType & 0xff; + KBNAContents[i + 7] = options->sequenceData[i / 0x10]->animationType >> 8; + KBNAContents[i + 8] = options->sequenceData[i / 0x10]->playbackMode & 0xff; + KBNAContents[i + 9] = (options->sequenceData[i / 0x10]->playbackMode >> 8) & 0xff; + KBNAContents[i + 10] = (options->sequenceData[i / 0x10]->playbackMode >> 16) & 0xff; + KBNAContents[i + 11] = options->sequenceData[i / 0x10]->playbackMode >> 24; + KBNAContents[i + 12] = framePtrCounter & 0xff; + KBNAContents[i + 13] = (framePtrCounter >> 8) & 0xff; + KBNAContents[i + 14] = (framePtrCounter >> 16) & 0xff; + KBNAContents[i + 15] = framePtrCounter >> 24; + framePtrCounter += options->sequenceData[i / 0x10]->frameCount * 8; + } + + int j; + int m; + for (j = i, m = 0; m < options->sequenceCount; m++) + { + for (int k = 0; k < options->sequenceData[m]->frameCount; k++) { + int resPtr = 0; + for (int l = 0; l < options->sequenceData[m]->frameData[k]->resultId; l++) { + if (options->animationResults[l]->resultType == 0) + resPtr += 0x4; + else if (options->animationResults[l]->resultType == 1) + resPtr += 0x10; + else if (options->animationResults[l]->resultType == 2) + resPtr += 0x8; + } + KBNAContents[j + (k * 8)] = resPtr & 0xff; + KBNAContents[j + (k * 8) + 1] = (resPtr >> 8) & 0xff; + KBNAContents[j + (k * 8) + 2] = (resPtr >> 16) & 0xff; + KBNAContents[j + (k * 8) + 3] = resPtr >> 24; + KBNAContents[j + (k * 8) + 4] = options->sequenceData[m]->frameData[k]->frameDelay & 0xff; + KBNAContents[j + (k * 8) + 5] = options->sequenceData[m]->frameData[k]->frameDelay >> 8; + KBNAContents[j + (k * 8) + 6] = 0xEF; + KBNAContents[j + (k * 8) + 7] = 0xBE; + } + j += options->sequenceData[m]->frameCount * 8; + } + + //todo: these are extrapolated, need confirming + int resPtrCounter = j; + for (int k = 0; k < options->resultCount; k++) + { + switch (options->animationResults[k]->resultType) + { + case 0: + KBNAContents[resPtrCounter] = options->animationResults[k]->index & 0xff; + KBNAContents[resPtrCounter + 1] = options->animationResults[k]->index >> 8; + KBNAContents[resPtrCounter + 2] = 0xCC; + KBNAContents[resPtrCounter + 3] = 0xCC; + resPtrCounter += 0x4; + break; + + case 1: + KBNAContents[resPtrCounter] = options->animationResults[k]->dataSrt.index & 0xff; + KBNAContents[resPtrCounter + 1] = options->animationResults[k]->dataSrt.index >> 8; + KBNAContents[resPtrCounter + 2] = options->animationResults[k]->dataSrt.rotation & 0xff; + KBNAContents[resPtrCounter + 3] = options->animationResults[k]->dataSrt.rotation >> 8; + KBNAContents[resPtrCounter + 4] = options->animationResults[k]->dataSrt.scaleX & 0xff; + KBNAContents[resPtrCounter + 5] = (options->animationResults[k]->dataSrt.scaleX >> 8) & 0xff; + KBNAContents[resPtrCounter + 6] = (options->animationResults[k]->dataSrt.scaleX >> 16) & 0xff; + KBNAContents[resPtrCounter + 7] = options->animationResults[k]->dataSrt.scaleX >> 24; + KBNAContents[resPtrCounter + 8] = options->animationResults[k]->dataSrt.scaleY & 0xff; + KBNAContents[resPtrCounter + 9] = (options->animationResults[k]->dataSrt.scaleY >> 8) & 0xff; + KBNAContents[resPtrCounter + 10] = (options->animationResults[k]->dataSrt.scaleY >> 16) & 0xff; + KBNAContents[resPtrCounter + 11] = options->animationResults[k]->dataSrt.scaleY >> 24; + KBNAContents[resPtrCounter + 12] = options->animationResults[k]->dataSrt.positionX & 0xff; + KBNAContents[resPtrCounter + 13] = options->animationResults[k]->dataSrt.positionX >> 8; + KBNAContents[resPtrCounter + 14] = options->animationResults[k]->dataSrt.positionY & 0xff; + KBNAContents[resPtrCounter + 15] = options->animationResults[k]->dataSrt.positionY >> 8; + resPtrCounter += 0x10; + break; + + case 2: + KBNAContents[resPtrCounter] = options->animationResults[k]->dataT.index & 0xff; + KBNAContents[resPtrCounter + 1] = options->animationResults[k]->dataT.index >> 8; + //KBNAContents[resPtrCounter + 2] = options->animationResults[k]->dataT.rotation & 0xff; + //KBNAContents[resPtrCounter + 3] = options->animationResults[k]->dataT.rotation >> 8; + KBNAContents[resPtrCounter + 2] = 0xEF; + KBNAContents[resPtrCounter + 3] = 0xBE; + KBNAContents[resPtrCounter + 4] = options->animationResults[k]->dataT.positionX & 0xff; + KBNAContents[resPtrCounter + 5] = options->animationResults[k]->dataT.positionX >> 8; + KBNAContents[resPtrCounter + 6] = options->animationResults[k]->dataT.positionY & 0xff; + KBNAContents[resPtrCounter + 7] = options->animationResults[k]->dataT.positionY >> 8; + resPtrCounter += 0x8; + break; + } + } + + fwrite(KBNAContents, 1, contentsSize, fp); + + free(KBNAContents); + + if (options->labelEnabled) + { + unsigned int lablSize = 8; + for (int j = 0; j < options->labelCount; j++) + { + lablSize += (unsigned)strlen(options->labels[j]) + 5; + } + + unsigned char *labl = malloc(lablSize); + + memset(labl, 0, lablSize); + + strcpy((char *) labl, "LBAL"); + labl[4] = lablSize & 0xff; + labl[5] = lablSize >> 8; + + unsigned int position = 0; + + i = 0; + for (int j = 0; j < options->labelCount; j++) + { + labl[i + 8] = position & 0xff; + labl[i + 9] = position >> 8; + + position += (unsigned)strlen(options->labels[j]) + 1; + i += 4; + } + + for (int j = 0; j < options->labelCount; j++) + { + strcpy((char *) (labl + (i + 8)), options->labels[j]); + i += (int)strlen(options->labels[j]) + 1; + } + + fwrite(labl, 1, lablSize, fp); + + free(labl); + + if(!options->multiCell) + { + unsigned char txeu[0xc] = {0x54, 0x58, 0x45, 0x55, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + + fwrite(txeu, 1, 0xc, fp); + } + } + + fclose(fp); +} diff --git a/tools/nitrogfx/gfx.h b/tools/nitrogfx/gfx.h index 389aec413..cab792bba 100644 --- a/tools/nitrogfx/gfx.h +++ b/tools/nitrogfx/gfx.h @@ -1,4 +1,4 @@ -// Copyright (c) 2015 YamaArashi +// Copyright (c) 2015 YamaArashi, 2021-2023 red031000 #ifndef GFX_H #define GFX_H @@ -30,10 +30,10 @@ struct Image { }; void ReadImage(char *path, int tilesWidth, int bitDepth, int metatileWidth, int metatileHeight, struct Image *image, bool invertColors); -uint32_t ReadNtrImage(char *path, int tilesWidth, int bitDepth, int metatileWidth, int metatileHeight, struct Image *image, bool invertColors); +uint32_t ReadNtrImage(char *path, int tilesWidth, int bitDepth, int metatileWidth, int metatileHeight, struct Image *image, bool invertColors, bool scanFrontToBack); void WriteImage(char *path, int numTiles, int bitDepth, int metatileWidth, int metatileHeight, struct Image *image, bool invertColors); void WriteNtrImage(char *path, int numTiles, int bitDepth, int metatileWidth, int metatileHeight, struct Image *image, - bool invertColors, bool clobberSize, bool byteOrder, bool version101, bool sopc, bool scanned, + bool invertColors, bool clobberSize, bool byteOrder, bool version101, bool sopc, uint32_t scanMode, uint32_t key, bool wrongSize); void FreeImage(struct Image *image); void ReadGbaPalette(char *path, struct Palette *palette); @@ -41,6 +41,7 @@ void ReadNtrPalette(char *path, struct Palette *palette, int bitdepth, int palIn void WriteGbaPalette(char *path, struct Palette *palette); void WriteNtrPalette(char *path, struct Palette *palette, bool ncpr, bool ir, int bitdepth, bool pad, int compNum); void WriteNtrCell(char *path, struct JsonToCellOptions *options); -void WriteNtrScreen(char *outputPath, struct JsonToScreenOptions *options); +void WriteNtrScreen(char *path, struct JsonToScreenOptions *options); +void WriteNtrAnimation(char *path, struct JsonToAnimationOptions *options); #endif // GFX_H diff --git a/tools/nitrogfx/json.c b/tools/nitrogfx/json.c index b825c363d..bcef5c0f0 100644 --- a/tools/nitrogfx/json.c +++ b/tools/nitrogfx/json.c @@ -1,4 +1,4 @@ -// Copyright (c) 2021 red031000 +// Copyright (c) 2021-2023 red031000 #include "global.h" #include "cJSON.h" @@ -230,6 +230,176 @@ struct JsonToScreenOptions *ParseNSCRJson(char *path) return options; } +struct JsonToAnimationOptions *ParseNANRJson(char *path) +{ + int filelength; + unsigned char *jsonString = ReadWholeFile(path, &filelength); + + cJSON *json = cJSON_Parse((const char *)jsonString); + + struct JsonToAnimationOptions *options = malloc(sizeof(struct JsonToAnimationOptions)); + + if (json == NULL) + { + const char *errorPtr = cJSON_GetErrorPtr(); + FATAL_ERROR("Error in line \"%s\"\n", errorPtr); + } + + cJSON *sequenceCount = cJSON_GetObjectItemCaseSensitive(json, "sequenceCount"); + cJSON *frameCount = cJSON_GetObjectItemCaseSensitive(json, "frameCount"); + + options->sequenceCount = GetInt(sequenceCount); + options->frameCount = GetInt(frameCount); + + options->sequenceData = malloc(sizeof(struct SequenceData *) * options->sequenceCount); + + int i; + for (i = 0; i < options->sequenceCount; i++) + { + options->sequenceData[i] = malloc(sizeof(struct SequenceData)); + } + + cJSON *sequence = NULL; + cJSON *sequences = cJSON_GetObjectItemCaseSensitive(json, "sequences"); + + i = 0; + cJSON_ArrayForEach(sequence, sequences) + { + if (i > options->sequenceCount - 1) + FATAL_ERROR("Sequence count is incorrect.\n"); + + cJSON *frameCount = cJSON_GetObjectItemCaseSensitive(sequence, "frameCount"); + cJSON *loopStartFrame = cJSON_GetObjectItemCaseSensitive(sequence, "loopStartFrame"); + cJSON *animationElement = cJSON_GetObjectItemCaseSensitive(sequence, "animationElement"); + cJSON *animationType = cJSON_GetObjectItemCaseSensitive(sequence, "animationType"); + cJSON *playbackMode = cJSON_GetObjectItemCaseSensitive(sequence, "playbackMode"); + + options->sequenceData[i]->frameCount = GetInt(frameCount); + options->sequenceData[i]->loopStartFrame = GetInt(loopStartFrame); + options->sequenceData[i]->animationElement = GetInt(animationElement); + options->sequenceData[i]->animationType = GetInt(animationType); + options->sequenceData[i]->playbackMode = GetInt(playbackMode); + + options->sequenceData[i]->frameData = malloc(sizeof(struct FrameData *) * options->sequenceData[i]->frameCount); + int j; + for (j = 0; j < options->sequenceData[i]->frameCount; j++) + { + options->sequenceData[i]->frameData[j] = malloc(sizeof(struct FrameData)); + } + + j = 0; + cJSON *frame = NULL; + cJSON *frameData = cJSON_GetObjectItemCaseSensitive(sequence, "frameData"); + + cJSON_ArrayForEach(frame, frameData) + { + if (j > options->sequenceData[i]->frameCount - 1) + FATAL_ERROR("Sequence frame count is incorrect.\n"); + + cJSON *frameDelay = cJSON_GetObjectItemCaseSensitive(frame, "frameDelay"); + cJSON *resultId = cJSON_GetObjectItemCaseSensitive(frame, "resultId"); + + options->sequenceData[i]->frameData[j]->frameDelay = GetInt(frameDelay); + options->sequenceData[i]->frameData[j]->resultId = GetInt(resultId); + + j++; + } + + i++; + } + + //todo implement extended attributes + + cJSON *resultCount = cJSON_GetObjectItemCaseSensitive(json, "resultCount"); + + options->resultCount = GetInt(resultCount); + + options->animationResults = malloc(sizeof(struct AnimationResults *) * options->resultCount); + + for (i = 0; i < options->resultCount; i++) + { + options->animationResults[i] = malloc(sizeof(struct AnimationResults)); + } + + i = 0; + + cJSON *animationResult = NULL; + cJSON *animationResults = cJSON_GetObjectItemCaseSensitive(json, "animationResults"); + cJSON_ArrayForEach(animationResult, animationResults) + { + if (i > options->resultCount - 1) + FATAL_ERROR("Frame count is incorrect.\n"); + + cJSON *resultType = cJSON_GetObjectItemCaseSensitive(animationResult, "resultType"); + options->animationResults[i]->resultType = GetInt(resultType); + switch (options->animationResults[i]->resultType) { + case 0: { //index + cJSON *index = cJSON_GetObjectItemCaseSensitive(animationResult, "index"); + options->animationResults[i]->index = GetInt(index); + break; + } + + case 1: { //SRT + cJSON *index = cJSON_GetObjectItemCaseSensitive(animationResult, "index"); + cJSON *rotation = cJSON_GetObjectItemCaseSensitive(animationResult, "rotation"); + cJSON *scaleX = cJSON_GetObjectItemCaseSensitive(animationResult, "scaleX"); + cJSON *scaleY = cJSON_GetObjectItemCaseSensitive(animationResult, "scaleY"); + cJSON *positionX = cJSON_GetObjectItemCaseSensitive(animationResult, "positionX"); + cJSON *positionY = cJSON_GetObjectItemCaseSensitive(animationResult, "positionY"); + + options->animationResults[i]->dataSrt.index = GetInt(index); + options->animationResults[i]->dataSrt.rotation = GetInt(rotation); + options->animationResults[i]->dataSrt.scaleX = GetInt(scaleX); + options->animationResults[i]->dataSrt.scaleY = GetInt(scaleY); + options->animationResults[i]->dataSrt.positionX = GetInt(positionX); + options->animationResults[i]->dataSrt.positionY = GetInt(positionY); + break; + } + + case 2: { //T + cJSON *index = cJSON_GetObjectItemCaseSensitive(animationResult, "index"); + //cJSON *rotation = cJSON_GetObjectItemCaseSensitive(animationResult, "rotation"); + cJSON *positionX = cJSON_GetObjectItemCaseSensitive(animationResult, "positionX"); + cJSON *positionY = cJSON_GetObjectItemCaseSensitive(animationResult, "positionY"); + + options->animationResults[i]->dataT.index = GetInt(index); + //options->animationResults[i]->dataSrt.rotation = GetInt(rotation); + options->animationResults[i]->dataT.positionX = GetInt(positionX); + options->animationResults[i]->dataT.positionY = GetInt(positionY); + break; + } + } + + i++; + } + + cJSON *labelBool = cJSON_GetObjectItemCaseSensitive(json, "labelEnabled"); + options->labelEnabled = GetBool(labelBool); + + if (options->labelEnabled) + { + cJSON *labelCount = cJSON_GetObjectItemCaseSensitive(json, "labelCount"); + options->labelCount = GetInt(labelCount); + options->labels = malloc(sizeof(char *) * options->labelCount); + + cJSON *labels = cJSON_GetObjectItemCaseSensitive(json, "labels"); + cJSON *label = NULL; + + int j = 0; + cJSON_ArrayForEach(label, labels) + { + char *labelString = GetString(label); + options->labels[j] = malloc(strlen(labelString) + 1); + strcpy(options->labels[j], labelString); + j++; + } + } + + cJSON_Delete(json); + free(jsonString); + return options; +} + void FreeNCERCell(struct JsonToCellOptions *options) { for (int i = 0; i < options->cellCount; i++) @@ -244,6 +414,7 @@ void FreeNCERCell(struct JsonToCellOptions *options) } free(options->labels); } + free(options->cells); free(options); } @@ -253,3 +424,31 @@ void FreeNSCRScreen(struct JsonToScreenOptions *options) free(options); } + +void FreeNANRAnimation(struct JsonToAnimationOptions *options) +{ + for (int i = 0; i < options->sequenceCount; i++) + { + for (int j = 0; j < options->sequenceData[i]->frameCount; j++) + { + free(options->sequenceData[i]->frameData[j]); + } + free(options->sequenceData[i]->frameData); + free(options->sequenceData[i]); + } + for (int i = 0; i < options->resultCount; i++) + { + free(options->animationResults[i]); + } + if (options->labelEnabled) + { + for (int j = 0; j < options->labelCount; j++) + { + free(options->labels[j]); + } + free(options->labels); + } + free(options->sequenceData); + free(options->animationResults); + free(options); +} diff --git a/tools/nitrogfx/json.h b/tools/nitrogfx/json.h index f297cf08a..aebe4b5e3 100644 --- a/tools/nitrogfx/json.h +++ b/tools/nitrogfx/json.h @@ -1,4 +1,4 @@ -// Copyright (c) 2021 red031000 +// Copyright (c) 2021-2023 red031000 #ifndef JSON_H #define JSON_H @@ -7,7 +7,9 @@ struct JsonToCellOptions *ParseNCERJson(char *path); struct JsonToScreenOptions *ParseNSCRJson(char *path); +struct JsonToAnimationOptions *ParseNANRJson(char *path); void FreeNCERCell(struct JsonToCellOptions *options); void FreeNSCRScreen(struct JsonToScreenOptions *options); +void FreeNANRAnimation(struct JsonToAnimationOptions *options); #endif //JSON_H diff --git a/tools/nitrogfx/main.c b/tools/nitrogfx/main.c index 5561e44ef..adc93b8fe 100644 --- a/tools/nitrogfx/main.c +++ b/tools/nitrogfx/main.c @@ -1,5 +1,6 @@ -// Copyright (c) 2015 YamaArashi +// Copyright (c) 2015 YamaArashi, 2021-2023 red031000 +#include #include #include #include @@ -45,8 +46,30 @@ void ConvertGbaToPng(char *inputPath, char *outputPath, struct GbaToPngOptions * FreeImage(&image); } -void ConvertNtrToPng(char *inputPath, char *outputPath, struct GbaToPngOptions *options) +void ConvertNtrToPng(char *inputPath, char *outputPath, struct NtrToPngOptions *options) { + // handle empty files if possible + FILE *fp = fopen(inputPath, "rb"); + + if (options->handleEmpty) + { + if (fp != NULL) + { + fseek(fp, 0, SEEK_END); + uint32_t size = ftell(fp); + rewind(fp); + if (size == 0) + { + FILE *out = fopen(outputPath, "wb+"); + fclose(out); + fclose(fp); + return; + } + } + } + + fclose(fp); + struct Image image; if (options->paletteFilePath != NULL) @@ -58,8 +81,8 @@ void ConvertNtrToPng(char *inputPath, char *outputPath, struct GbaToPngOptions * { image.hasPalette = false; } - - uint32_t key = ReadNtrImage(inputPath, options->width, 0, options->metatileWidth, options->metatileHeight, &image, !image.hasPalette); + + uint32_t key = ReadNtrImage(inputPath, options->width, 0, options->metatileWidth, options->metatileHeight, &image, !image.hasPalette, options->scanFrontToBack); if (key) { @@ -95,6 +118,27 @@ void ConvertPngToGba(char *inputPath, char *outputPath, struct PngToGbaOptions * void ConvertPngToNtr(char *inputPath, char *outputPath, struct PngToNtrOptions *options) { + // handle empty files if possible + FILE *fp = fopen(inputPath, "rb"); + + if (options->handleEmpty) + { + if (fp != NULL) + { + fseek(fp, 0, SEEK_END); + uint32_t size = ftell(fp); + rewind(fp); + if (size == 0) + { + FILE *out = fopen(outputPath, "wb+"); + fclose(out); + fclose(fp); + return; + } + } + } + + fclose(fp); struct Image image; image.bitDepth = options->bitDepth; @@ -102,7 +146,7 @@ void ConvertPngToNtr(char *inputPath, char *outputPath, struct PngToNtrOptions * ReadPng(inputPath, &image); uint32_t key = 0; - if (options->scanned) + if (options->scanMode) { char* string = malloc(strlen(inputPath) + 5); sprintf(string, "%s.key", inputPath); @@ -118,7 +162,7 @@ void ConvertPngToNtr(char *inputPath, char *outputPath, struct PngToNtrOptions * WriteNtrImage(outputPath, options->numTiles, image.bitDepth, options->metatileWidth, options->metatileHeight, &image, !image.hasPalette, options->clobberSize, options->byteOrder, options->version101, - options->sopc, options->scanned, key, options->wrongSize); + options->sopc, options->scanMode, key, options->wrongSize); FreeImage(&image); } @@ -128,7 +172,10 @@ void HandleGbaToPngCommand(char *inputPath, char *outputPath, int argc, char **a char *inputFileExtension = GetFileExtension(inputPath); struct GbaToPngOptions options; options.paletteFilePath = NULL; - options.bitDepth = inputFileExtension[0] - '0'; + if (isdigit(inputFileExtension[0])) + options.bitDepth = inputFileExtension[0] - '0'; + else + options.bitDepth = 4; options.hasTransparency = false; options.width = 1; options.metatileWidth = 1; @@ -204,13 +251,15 @@ void HandleGbaToPngCommand(char *inputPath, char *outputPath, int argc, char **a void HandleNtrToPngCommand(char *inputPath, char *outputPath, int argc, char **argv) { - struct GbaToPngOptions options; + struct NtrToPngOptions options; options.paletteFilePath = NULL; options.hasTransparency = false; - options.width = 1; + options.width = 0; options.metatileWidth = 1; options.metatileHeight = 1; options.palIndex = 1; + options.scanFrontToBack = false; + options.handleEmpty = false; for (int i = 3; i < argc; i++) { @@ -281,13 +330,21 @@ void HandleNtrToPngCommand(char *inputPath, char *outputPath, int argc, char **a if (options.metatileHeight < 1) FATAL_ERROR("metatile height must be positive.\n"); } + else if (strcmp(option, "-scanfronttoback") == 0) + { + options.scanFrontToBack = true; + } + else if (strcmp(option, "-handleempty") == 0) + { + options.handleEmpty = true; + } else { FATAL_ERROR("Unrecognized option \"%s\".\n", option); } } - if (options.metatileWidth > options.width) + if (options.width != 0 && options.metatileWidth > options.width) options.width = options.metatileWidth; ConvertNtrToPng(inputPath, outputPath, &options); @@ -296,7 +353,11 @@ void HandleNtrToPngCommand(char *inputPath, char *outputPath, int argc, char **a void HandlePngToGbaCommand(char *inputPath, char *outputPath, int argc, char **argv) { char *outputFileExtension = GetFileExtension(outputPath); - int bitDepth = outputFileExtension[0] - '0'; + int bitDepth; + if (strcmp(outputFileExtension, "nbfc") == 0) + bitDepth = 4; + else + bitDepth = outputFileExtension[0] - '0'; struct PngToGbaOptions options; options.numTiles = 0; options.bitDepth = bitDepth; @@ -367,7 +428,8 @@ void HandlePngToNtrCommand(char *inputPath, char *outputPath, int argc, char **a options.byteOrder = true; options.version101 = false; options.sopc = false; - options.scanned = false; + options.scanMode = 0; + options.handleEmpty = false; for (int i = 3; i < argc; i++) { @@ -443,11 +505,23 @@ void HandlePngToNtrCommand(char *inputPath, char *outputPath, int argc, char **a } else if (strcmp(option, "-scanned") == 0) { - options.scanned = true; + if (options.scanMode != 0) + FATAL_ERROR("Scan mode specified more than once.\n-scanned goes back to front as in DP, -scanfronttoback goes front to back as in PtHGSS\n"); + options.scanMode = 1; + } + else if (strcmp(option, "-scanfronttoback") == 0) + { + if (options.scanMode != 0) + FATAL_ERROR("Scan mode specified more than once.\n-scanned goes back to front as in DP, -scanfronttoback goes front to back as in PtHGSS\n"); + options.scanMode = 2; } else if (strcmp(option, "-wrongsize") == 0) { options.wrongSize = true; } + else if (strcmp(option, "-handleempty") == 0) + { + options.handleEmpty = true; + } else { FATAL_ERROR("Unrecognized option \"%s\".\n", option); @@ -732,6 +806,32 @@ void HandleJsonToNtrScreenCommand(char *inputPath, char *outputPath, int argc UN FreeNSCRScreen(options); } +void HandleJsonToNtrAnimationCommand(char *inputPath, char *outputPath, int argc UNUSED, char **argv UNUSED) +{ + struct JsonToAnimationOptions *options; + + options = ParseNANRJson(inputPath); + + options->multiCell = false; + + WriteNtrAnimation(outputPath, options); + + FreeNANRAnimation(options); +} + +void HandleJsonToNtrMulticellAnimationCommand(char *inputPath, char *outputPath, int argc UNUSED, char **argv UNUSED) +{ + struct JsonToAnimationOptions *options; + + options = ParseNANRJson(inputPath); + + options->multiCell = true; + + WriteNtrAnimation(outputPath, options); + + FreeNANRAnimation(options); +} + void HandleLatinFontToPngCommand(char *inputPath, char *outputPath, int argc UNUSED, char **argv UNUSED) { struct Image image; @@ -992,6 +1092,8 @@ int main(int argc, char **argv) { "png", "fwjpnfont", HandlePngToFullwidthJapaneseFontCommand }, { "json", "NCER", HandleJsonToNtrCellCommand }, { "json", "NSCR", HandleJsonToNtrScreenCommand }, + { "json", "NANR", HandleJsonToNtrAnimationCommand }, + { "json", "NMAR", HandleJsonToNtrMulticellAnimationCommand }, { NULL, "huff", HandleHuffCompressCommand }, { NULL, "lz", HandleLZCompressCommand }, { "huff", NULL, HandleHuffDecompressCommand }, diff --git a/tools/nitrogfx/options.h b/tools/nitrogfx/options.h index e67217666..019b2fb63 100644 --- a/tools/nitrogfx/options.h +++ b/tools/nitrogfx/options.h @@ -1,8 +1,9 @@ -// Copyright (c) 2018 huderlem +// Copyright (c) 2018 huderlem, 2021-2023 red031000 #ifndef OPTIONS_H #define OPTIONS_H +#include #include struct GbaToPngOptions { @@ -31,8 +32,21 @@ struct PngToNtrOptions { bool byteOrder; bool version101; bool sopc; - bool scanned; + uint32_t scanMode; bool wrongSize; + bool handleEmpty; +}; + +struct NtrToPngOptions { + char *paletteFilePath; + int bitDepth; + bool hasTransparency; + int width; + int metatileWidth; + int metatileHeight; + int palIndex; + bool scanFrontToBack; + bool handleEmpty; }; struct Attr0 { @@ -91,4 +105,55 @@ struct JsonToScreenOptions { int bitdepth; }; +struct FrameData { + int resultId; + short frameDelay; +}; + +struct SequenceData { + short frameCount; + short loopStartFrame; + short animationElement; + short animationType; + int playbackMode; + struct FrameData **frameData; +}; + +struct AnimationDataSRT { + short index; + unsigned short rotation; + int scaleX; + int scaleY; + short positionX; + short positionY; +}; + +struct AnimationDataT { + short index; + //unsigned short rotation; + short positionX; + short positionY; +}; + +struct AnimationResults { + short resultType; + union { + short index; + struct AnimationDataSRT dataSrt; + struct AnimationDataT dataT; + }; +}; + +struct JsonToAnimationOptions { + bool multiCell; + short sequenceCount; + short frameCount; + struct SequenceData **sequenceData; + struct AnimationResults **animationResults; + bool labelEnabled; + char **labels; + int labelCount; + short resultCount; +}; + #endif // OPTIONS_H diff --git a/tools/nitrogfx/rl.c b/tools/nitrogfx/rl.c index 968c9347e..993ac6449 100644 --- a/tools/nitrogfx/rl.c +++ b/tools/nitrogfx/rl.c @@ -101,7 +101,7 @@ unsigned char *RLCompress(unsigned char *src, int srcSize, int *compressedSize) srcPos++; uncompressedLength++; } - + if (uncompressedLength > 0) { dest[destPos++] = uncompressedLength - 1; diff --git a/tools/nitrogfx/util.h b/tools/nitrogfx/util.h index b757aa4de..080dd4be8 100644 --- a/tools/nitrogfx/util.h +++ b/tools/nitrogfx/util.h @@ -13,4 +13,45 @@ unsigned char *ReadWholeFileZeroPadded(char *path, int *size, int padAmount); void WriteWholeFile(char *path, void *buffer, int bufferSize); void WriteGenericNtrHeader(FILE* fp, const char* magicNumber, uint32_t size, bool byteorder, bool version101, uint16_t sectionCount); +// Unaligned IO +static inline uint8_t ReadU8(const unsigned char *ptr, const size_t offset) { + return ptr[offset]; +} + +static inline uint16_t ReadU16(const unsigned char *ptr, const size_t offset) { + return ptr[offset] | (ptr[offset + 1] << 8); +} + +static inline uint32_t ReadU32(const unsigned char *ptr, const size_t offset) { + return ptr[offset] | (ptr[offset + 1] << 8) | (ptr[offset + 2] << 16) | (ptr[offset + 3] << 24); +} + +static inline int8_t ReadS8(const unsigned char *ptr, const size_t offset) { + return ptr[offset]; +} + +static inline int16_t ReadS16(const unsigned char *ptr, const size_t offset) { + return ptr[offset] | (ptr[offset + 1] << 8); +} + +static inline int32_t ReadS32(const unsigned char *ptr, const size_t offset) { + return ptr[offset] | (ptr[offset + 1] << 8) | (ptr[offset + 2] << 16) | (ptr[offset + 3] << 24); +} + +static inline void WriteU8(unsigned char *ptr, const size_t offset, uint8_t value) { + ptr[offset] = value; +} + +static inline void WriteU16(unsigned char *ptr, const size_t offset, uint16_t value) { + ptr[offset] = value; + ptr[offset + 1] = value >> 8; +} + +static inline void WriteU32(unsigned char *ptr, const size_t offset, uint32_t value) { + ptr[offset] = value; + ptr[offset + 1] = value >> 8; + ptr[offset + 2] = value >> 16; + ptr[offset + 3] = value >> 24; +} + #endif // UTIL_H