added missing configs and implemented item configs

This commit is contained in:
cawtds
2024-07-02 23:15:22 +02:00
parent 168bafaccb
commit f0c9e5beb4
13 changed files with 1285 additions and 34 deletions

View File

@@ -0,0 +1,21 @@
#ifndef GUARD_CONFIG_LEVEL_CAP_H
#define GUARD_CONFIG_LEVEL_CAP_H
// Constants
#define EXP_CAP_NONE 0 // Regular behavior, no level caps are applied
#define EXP_CAP_HARD 1 // Pokémon with a level >= the level cap cannot gain any experience
#define EXP_CAP_SOFT 2 // Pokémon with a level >= the level cap will gain reduced experience
#define LEVEL_CAP_NONE 0 // No level cap, only applicable if B_EXP_CAP_TYPE is EXP_CAP_NONE
#define LEVEL_CAP_FLAG_LIST 1 // Level cap is chosen according to the first unset flag in `sLevelCapFlagMap`
#define LEVEL_CAP_VARIABLE 2 // Level cap is chosen according to the contents of the event variable specified by B_LEVEL_CAP_VARIABLE
// Configs
#define B_EXP_CAP_TYPE EXP_CAP_NONE // [EXP_CAP_NONE, EXP_CAP_HARD, EXP_CAP_SOFT] choose the type of level cap to apply
#define B_LEVEL_CAP_TYPE LEVEL_CAP_NONE // [LEVEL_CAP_NONE, LEVEL_CAP_FLAG_LIST, LEVEL_CAP_VARIABLE] choose the method to derive the level cap
#define B_LEVEL_CAP_VARIABLE 0 // event variable used to derive level cap if B_LEVEL_CAP_TYPE is set to LEVEL_CAP_VARIABLE
#define B_RARE_CANDY_CAP FALSE // If set to true, Rare Candies can't be used to go over the level cap
#define B_LEVEL_CAP_EXP_UP FALSE // If set to true, mons under level cap will receive more experience
#endif /* GUARD_CONFIG_LEVEL_CAP_H */

23
include/config/save.h Normal file
View File

@@ -0,0 +1,23 @@
#ifndef GUARD_CONFIG_SAVE_H
#define GUARD_CONFIG_SAVE_H
// SaveBlock1 configs
#define FREE_EXTRA_SEEN_FLAGS_SAVEBLOCK1 FALSE // Free up unused Pokédex seen flags (52 bytes).
#define FREE_TRAINER_HILL FALSE // Frees up Trainer Hill data (28 bytes).
#define FREE_MYSTERY_EVENT_BUFFERS FALSE // Frees up ramScript (1104 bytes).
#define FREE_MATCH_CALL FALSE // Frees up match call and rematch / VS Seeker data. (104 bytes).
#define FREE_UNION_ROOM_CHAT FALSE // Frees up union room chat (212 bytes).
#define FREE_ENIGMA_BERRY FALSE // Frees up E-Reader Enigma Berry data (52 bytes).
#define FREE_LINK_BATTLE_RECORDS FALSE // Frees up link battle record data (88 bytes).
#define FREE_MYSTERY_GIFT FALSE // Frees up Mystery Gift data (876 bytes).
// SaveBlock1 total: 2516 bytes
// SaveBlock2 configs
#define FREE_BATTLE_TOWER_E_READER FALSE // Frees up Battle Tower E-Reader data (188 bytes).
#define FREE_POKEMON_JUMP FALSE // Frees up Pokémon Jump data (16 bytes).
#define FREE_RECORD_MIXING_HALL_RECORDS FALSE // Frees up hall records for record mixing (1032 bytes).
#define FREE_EXTRA_SEEN_FLAGS_SAVEBLOCK2 FALSE // Free up unused Pokédex seen flags (108 bytes).
// SaveBlock2 total: 1274 bytes
// Grand Total: 3790
#endif // GUARD_CONFIG_SAVE_H

1138
include/config/test.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -4,7 +4,7 @@
#include "config/battle.h"
#include "config/debug.h"
#include "config/item.h"
// #include "config/level_caps.h"
#include "config/level_caps.h"
#include "config/pokemon.h"
#include "config/overworld.h"
@@ -134,4 +134,9 @@
#define CONNECTION_DIVE 5
#define CONNECTION_EMERGE 6
#if TESTING
#include "config/test.h"
#endif
#endif //GUARD_CONSTANTS_GLOBAL_H

View File

@@ -43,6 +43,7 @@ u8 *CopyItemNameHandlePlural(u16 itemId, u8 *string, u32 quantity);
bool8 IsBagPocketNonEmpty(u8 pocket);
bool8 CheckBagHasItem(u16 itemId, u16 count);
bool8 CheckBagHasSpace(u16 itemId, u16 count);
u32 GetFreeSpaceForItemInBag(u16 itemId);
bool8 RemoveBagItem(u16 itemId, u16 count);
u8 GetPocketByItemId(u16 itemId);
void ClearItemSlots(struct ItemSlot *itemSlots, u8 b);

View File

@@ -986,6 +986,8 @@ extern const u8 gText_InBagVar1[];
extern const u8 gText_Var1AndYouWantedVar2[];
extern const u8 gText_HereYouGoThankYou[];
extern const u8 gText_NoMoreRoomForThis[];
extern const u8 gText_ThrowInPremierBall[];
extern const u8 gText_ThrowInPremierBalls[];
// pokedex_screen
extern const u8 gText_PokedexTableOfContents[];

View File

@@ -10,6 +10,8 @@
#define NUM_ALTERING_CAVE_TABLES 9
#define FISHING_CHAIN_LENGTH_MAX 20
struct WildPokemon
{
u8 minLevel;
@@ -36,6 +38,7 @@ struct WildPokemonHeader
extern const struct WildPokemonHeader gWildMonHeaders[];
extern bool8 gIsFishingEncounter;
extern bool8 gIsSurfingEncounter;
extern u8 gChainFishingDexNavStreak;
void DisableWildEncounters(bool8 disabled);
u8 PickWildMonNature(void);

View File

@@ -187,36 +187,36 @@ bool8 HasAtLeastOneBerry(void)
bool8 CheckBagHasSpace(u16 itemId, u16 count)
{
u8 i;
u8 pocket;
if (ItemId_GetPocket(itemId) == 0)
if (ItemId_GetPocket(itemId) == POCKET_NONE)
return FALSE;
pocket = ItemId_GetPocket(itemId) - 1;
// Check for item slots that contain the item
return GetFreeSpaceForItemInBag(itemId) >= count;
}
u32 GetFreeSpaceForItemInBag(u16 itemId)
{
u8 i;
u8 pocket = ItemId_GetPocket(itemId) - 1;
u16 ownedCount;
u32 spaceForItem = 0;
if (ItemId_GetPocket(itemId) == POCKET_NONE)
return 0;
// Check space in any existing item slots that already contain this item
for (i = 0; i < gBagPockets[pocket].capacity; i++)
{
if (gBagPockets[pocket].itemSlots[i].itemId == itemId)
{
u16 quantity;
// Does this stack have room for more??
quantity = GetBagItemQuantity(&gBagPockets[pocket].itemSlots[i].quantity);
if (quantity + count <= 999)
return TRUE;
// RS and Emerald check whether there is enough of the
// item across all stacks.
// For whatever reason, FR/LG assume there's only one
// stack of the item.
else
return FALSE;
ownedCount = GetBagItemQuantity(&gBagPockets[pocket].itemSlots[i].quantity);
spaceForItem += max(0, MAX_BAG_ITEM_CAPACITY - ownedCount);
}
else if (gBagPockets[pocket].itemSlots[i].itemId == ITEM_NONE)
{
spaceForItem += MAX_BAG_ITEM_CAPACITY;
}
}
if (BagPocketGetFirstEmptySlot(pocket) != -1)
return TRUE;
return FALSE;
return spaceForItem;
}
bool8 AddBagItem(u16 itemId, u16 count)

View File

@@ -1830,10 +1830,12 @@ static void ReturnToBagMenuFromSubmenu_Sell(void)
GoToBagMenu(ITEMMENULOCATION_SHOP, OPEN_BAG_LAST, CB2_ReturnToField);
}
#define ITEM_SELL_FACTOR ((I_SELL_VALUE_FRACTION >= GEN_9) ? 4 : 2)
static void Task_PrintSaleConfirmationText(u8 taskId)
{
s16 *data = gTasks[taskId].data;
ConvertIntToDecimalStringN(gStringVar3, ItemId_GetPrice(BagGetItemIdByPocketPosition(gBagMenuState.pocket + 1, data[1])) / 2 * data[8], STR_CONV_MODE_LEFT_ALIGN, 6);
ConvertIntToDecimalStringN(gStringVar3, (ItemId_GetPrice(BagGetItemIdByPocketPosition(gBagMenuState.pocket + 1, data[1])) / ITEM_SELL_FACTOR) * data[8], STR_CONV_MODE_LEFT_ALIGN, 6);
StringExpandPlaceholders(gStringVar4, gText_ICanPayThisMuch_WouldThatBeOkay);
DisplayItemMessageInBag(taskId, GetDialogBoxFontId(), gStringVar4, Task_ShowSellYesNoMenu);
}
@@ -1863,7 +1865,7 @@ static void Task_InitSaleQuantitySelectInterface(u8 taskId)
ConvertIntToDecimalStringN(gStringVar1, 1, STR_CONV_MODE_LEADING_ZEROS, 2);
StringExpandPlaceholders(gStringVar4, gText_TimesStrVar1);
BagPrintTextOnWindow(r4, FONT_SMALL, gStringVar4, 4, 10, 1, 0, 0xFF, 1);
UpdateSalePriceDisplay(ItemId_GetPrice(BagGetItemIdByPocketPosition(gBagMenuState.pocket + 1, data[1])) / 2 * data[8]);
UpdateSalePriceDisplay((ItemId_GetPrice(BagGetItemIdByPocketPosition(gBagMenuState.pocket + 1, data[1])) / ITEM_SELL_FACTOR) * data[8]);
BagPrintMoneyAmount();
CreatePocketScrollArrowPair_SellQuantity();
gTasks[taskId].func = Task_SelectQuantityToSell;
@@ -1880,7 +1882,7 @@ static void Task_SelectQuantityToSell(u8 taskId)
if (AdjustQuantityAccordingToDPadInput(&data[8], data[2]) == TRUE)
{
UpdateQuantityToTossOrDeposit(data[8], 2);
UpdateSalePriceDisplay(ItemId_GetPrice(BagGetItemIdByPocketPosition(gBagMenuState.pocket + 1, data[1])) / 2 * data[8]);
UpdateSalePriceDisplay((ItemId_GetPrice(BagGetItemIdByPocketPosition(gBagMenuState.pocket + 1, data[1])) / ITEM_SELL_FACTOR) * data[8]);
}
else if (JOY_NEW(A_BUTTON))
{
@@ -1913,7 +1915,7 @@ static void Task_SellItem_Yes(u8 taskId)
PutWindowTilemap(0);
ScheduleBgCopyTilemapToVram(0);
CopyItemName(gSpecialVar_ItemId, gStringVar1);
ConvertIntToDecimalStringN(gStringVar3, ItemId_GetPrice(BagGetItemIdByPocketPosition(gBagMenuState.pocket + 1, data[1])) / 2 * data[8], STR_CONV_MODE_LEFT_ALIGN, 6);
ConvertIntToDecimalStringN(gStringVar3, (ItemId_GetPrice(BagGetItemIdByPocketPosition(gBagMenuState.pocket + 1, data[1])) / ITEM_SELL_FACTOR) * data[8], STR_CONV_MODE_LEFT_ALIGN, 6);
StringExpandPlaceholders(gStringVar4, gText_TurnedOverItemsWorthYen);
DisplayItemMessageInBag(taskId, FONT_NORMAL, gStringVar4, Task_FinalizeSaleToShop);
}
@@ -1923,7 +1925,7 @@ static void Task_FinalizeSaleToShop(u8 taskId)
s16 *data = gTasks[taskId].data;
PlaySE(SE_SHOP);
RemoveBagItem(gSpecialVar_ItemId, data[8]);
AddMoney(&gSaveBlock1Ptr->money, ItemId_GetPrice(gSpecialVar_ItemId) / 2 * data[8]);
AddMoney(&gSaveBlock1Ptr->money, (ItemId_GetPrice(gSpecialVar_ItemId) / ITEM_SELL_FACTOR) * data[8]);
RecordItemTransaction(gSpecialVar_ItemId, data[8], QL_EVENT_SOLD_ITEM - QL_EVENT_USED_POKEMART);
DestroyListMenuTask(data[0], &gBagMenuState.cursorPos[gBagMenuState.pocket], &gBagMenuState.itemsAbove[gBagMenuState.pocket]);
Pocket_CalculateNItemsAndMaxShowed(gBagMenuState.pocket);

View File

@@ -30,6 +30,7 @@
#include "field_specials.h"
#include "berry.h"
#include "recorded_battle.h"
#include "wild_encounter.h"
#include "constants/items.h"
#include "constants/item_effects.h"
#include "constants/cries.h"
@@ -1266,6 +1267,8 @@ void CreateBoxMon(struct BoxPokemon *boxMon, u16 species, u8 level, u8 fixedIV,
totalRerolls += I_SHINY_CHARM_ADDITIONAL_ROLLS;
if (LURE_STEP_COUNT != 0)
totalRerolls += 1;
if (I_FISHING_CHAIN && gIsFishingEncounter)
totalRerolls += (1 + (2 * gChainFishingDexNavStreak));
while (GET_SHINY_VALUE(value, personality) >= SHINY_ODDS && totalRerolls > 0)
{

View File

@@ -995,10 +995,34 @@ static void BuyMenuSubtractMoney(u8 taskId)
static void Task_ReturnToItemListAfterItemPurchase(u8 taskId)
{
s16 *data = gTasks[taskId].data;
if (JOY_NEW(A_BUTTON) || JOY_NEW(B_BUTTON))
{
u16 premierBallsToAdd = tItemCount / 10;
if (premierBallsToAdd >= 1
&& ((I_PREMIER_BALL_BONUS <= GEN_7 && tItemId == ITEM_POKE_BALL)
|| (I_PREMIER_BALL_BONUS >= GEN_8 && (ItemId_GetPocket(tItemId) == POCKET_POKE_BALLS))))
{
u32 spaceAvailable = GetFreeSpaceForItemInBag(ITEM_PREMIER_BALL);
if (spaceAvailable < premierBallsToAdd)
premierBallsToAdd = spaceAvailable;
}
else
{
premierBallsToAdd = 0;
}
PlaySE(SE_SELECT);
BuyMenuReturnToItemList(taskId);
AddBagItem(ITEM_PREMIER_BALL, premierBallsToAdd);
if (premierBallsToAdd > 0)
{
ConvertIntToDecimalStringN(gStringVar1, premierBallsToAdd, STR_CONV_MODE_LEFT_ALIGN, MAX_ITEM_DIGITS);
BuyMenuDisplayMessage(taskId, (premierBallsToAdd >= 2 ? gText_ThrowInPremierBalls : gText_ThrowInPremierBall), BuyMenuReturnToItemList);
}
else
{
BuyMenuReturnToItemList(taskId);
}
}
}

View File

@@ -246,7 +246,8 @@ const u8 gText_NoMoreRoomForThis[] = _("You have no more room for this\nitem.{PA
const u8 gText_SpaceForVar1Full[] = _("{STR_VAR_1}を\nいれる ばしょが いっぱいです{PAUSE_UNTIL_PRESS}");
const u8 gText_AnythingElseICanHelp[] = _("Is there anything else I can do?");
const u8 gText_CanIHelpWithAnythingElse[] = _("その ほかに\nなにか ちからに なれることは?");
const u8 gText_ThrowInPremierBall[] = _("プレミアボ-ル 1コ\nおまけ しておきますね!{PAUSE_UNTIL_PRESS}");
const u8 gText_ThrowInPremierBall[] = _("I'll throw in a Premier Ball, too.{PAUSE_UNTIL_PRESS}");
const u8 gText_ThrowInPremierBalls[] = _("I'll throw in {STR_VAR_1} Premier Balls, too.{PAUSE_UNTIL_PRESS}");
const u8 gText_OhNoICantBuyThat[] = _("{STR_VAR_1}? Oh, no.\nI can't buy that.{PAUSE_UNTIL_PRESS}");
const u8 gText_HowManyWouldYouLikeToSell[] = _("{STR_VAR_1}?\nHow many would you like to sell?");
const u8 gText_ICanPayThisMuch_WouldThatBeOkay[] = _("I can pay ¥{STR_VAR_3}.\nWould that be okay?");

View File

@@ -51,9 +51,12 @@ static EWRAM_DATA struct WildEncounterData sWildEncounterData = {};
static EWRAM_DATA bool8 sWildEncountersDisabled = FALSE;
EWRAM_DATA bool8 gIsFishingEncounter = 0;
EWRAM_DATA bool8 gIsSurfingEncounter = 0;
EWRAM_DATA u8 gChainFishingDexNavStreak = 0;
EWRAM_DATA static u16 sLastFishingSpecies = 0;
static bool8 UnlockedTanobyOrAreNotInTanoby(void);
static u32 GenerateUnownPersonalityByLetter(u8 letter);
static void UpdateChainFishingSpeciesAndStreak(u32 species);
static bool8 IsWildLevelAllowedByRepel(u8 level);
static void ApplyFluteEncounterRateMod(u32 *rate);
static u8 GetMaxLevelOfSpeciesInWildTable(const struct WildPokemon *wildMon, u16 species, u8 area);
@@ -444,13 +447,15 @@ static bool8 TryGenerateWildMon(const struct WildPokemonInfo * wildMonInfo, u8 a
return TRUE;
}
static u16 GenerateFishingEncounter(const struct WildPokemonInfo * info, u8 rod)
static u16 GenerateFishingEncounter(const struct WildPokemonInfo * wildMonInfo, u8 rod)
{
u8 wildMonIndex = ChooseWildMonIndex_Fishing(rod);
u8 level = ChooseWildMonLevel(info->wildPokemon, wildMonIndex, WILD_AREA_FISHING);
u16 wildMonSpecies = wildMonInfo->wildPokemon[wildMonIndex].species;
u8 level = ChooseWildMonLevel(wildMonInfo->wildPokemon, wildMonIndex, WILD_AREA_FISHING);
CreateWildMon(info->wildPokemon[wildMonIndex].species, level, wildMonIndex);
return info->wildPokemon[wildMonIndex].species;
UpdateChainFishingSpeciesAndStreak(wildMonSpecies);
CreateWildMon(wildMonSpecies, level, wildMonIndex);
return wildMonSpecies;
}
static bool8 DoWildEncounterRateDiceRoll(u16 encounterRate)
@@ -717,6 +722,29 @@ bool8 DoesCurrentMapHaveFishingMons(void)
return TRUE;
}
static void HandleChainFishingStreak(u32 species)
{
if (species != sLastFishingSpecies)
{
gChainFishingDexNavStreak = 0;
return;
}
if (gChainFishingDexNavStreak >= FISHING_CHAIN_LENGTH_MAX)
return;
gChainFishingDexNavStreak++;
}
static void UpdateChainFishingSpeciesAndStreak(u32 species)
{
if (!I_FISHING_CHAIN)
return;
HandleChainFishingStreak(species);
sLastFishingSpecies = species;
}
void FishingWildEncounter(u8 rod)
{
GenerateFishingEncounter(gWildMonHeaders[GetCurrentMapWildMonHeaderId()].fishingMonsInfo, rod);