mirror of
https://github.com/pret/pmd-red.git
synced 2026-04-25 07:28:17 -05:00
461 lines
12 KiB
C
461 lines
12 KiB
C
#include "global.h"
|
|
#include "dungeon_ai_item_weight.h"
|
|
|
|
#include "constants/status.h"
|
|
#include "constants/targeting.h"
|
|
#include "dungeon_ai_targeting.h"
|
|
#include "dungeon_map_access.h"
|
|
#include "dungeon_pokemon_attributes.h"
|
|
#include "dungeon_util.h"
|
|
#include "moves.h"
|
|
#include "number_util.h"
|
|
#include "status_checks_1.h"
|
|
|
|
u32 EvaluateItem(struct DungeonEntity *targetPokemon, struct ItemSlot *item, u32 itemTargetFlags)
|
|
{
|
|
struct DungeonEntityData *pokemonData = targetPokemon->entityData;
|
|
s32 itemWeight = 0;
|
|
bool8 targetOther = itemTargetFlags & 1;
|
|
u16 targetAlly = (itemTargetFlags >> 1) & 1;
|
|
s32 i;
|
|
struct PokemonMove *move;
|
|
struct PokemonMove *move2;
|
|
switch (item->itemIndex)
|
|
{
|
|
case ITEM_ID_STICK:
|
|
case ITEM_ID_IRON_THORN:
|
|
case ITEM_ID_SILVER_SPIKE:
|
|
case ITEM_ID_GOLD_FANG:
|
|
case ITEM_ID_CACNEA_SPIKE:
|
|
case ITEM_ID_CORSOLA_TWIG:
|
|
case ITEM_ID_GRAVELEROCK:
|
|
case ITEM_ID_GEO_PEBBLE:
|
|
if (targetOther)
|
|
{
|
|
itemWeight = 70;
|
|
}
|
|
break;
|
|
case ITEM_ID_DIET_RIBBON:
|
|
if (targetOther && RoundUpFixedPoint(pokemonData->belly) > 0)
|
|
{
|
|
return 50;
|
|
}
|
|
else
|
|
{
|
|
itemWeight = 0;
|
|
}
|
|
break;
|
|
case ITEM_ID_WHIFF_SPECS:
|
|
case ITEM_ID_NO_AIM_SCOPE:
|
|
if (targetOther)
|
|
{
|
|
return 50;
|
|
}
|
|
else
|
|
{
|
|
itemWeight = 0;
|
|
}
|
|
break;
|
|
case ITEM_ID_ORAN_BERRY:
|
|
case ITEM_ID_SITRUS_BERRY:
|
|
if (pokemonData->HP < pokemonData->maxHP && pokemonData->HP <= pokemonData->maxHP / 4)
|
|
{
|
|
if (!targetOther)
|
|
{
|
|
if (CanTargetAdjacentPokemon(targetPokemon))
|
|
{
|
|
itemWeight = 100;
|
|
}
|
|
else
|
|
{
|
|
itemWeight = 50;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
itemWeight = 50;
|
|
}
|
|
}
|
|
break;
|
|
case ITEM_ID_MAX_ELIXIR:
|
|
itemWeight = 0;
|
|
move = pokemonData->moves;
|
|
move2 = move;
|
|
for (i = 0; i < MAX_MON_MOVES; move++, move2++, i++)
|
|
{
|
|
if (move->moveFlags & MOVE_FLAG_EXISTS)
|
|
{
|
|
if (move->PP == 0)
|
|
{
|
|
itemWeight += 30;
|
|
}
|
|
if (move->PP != GetMoveMaxPP(move2))
|
|
{
|
|
itemWeight += 6;
|
|
}
|
|
}
|
|
}
|
|
if (itemWeight >= 99)
|
|
{
|
|
itemWeight = 99;
|
|
}
|
|
break;
|
|
case ITEM_ID_HEAL_SEED:
|
|
if (HasNegativeStatus(targetPokemon))
|
|
{
|
|
itemWeight = 80;
|
|
}
|
|
else
|
|
{
|
|
itemWeight = 0;
|
|
}
|
|
break;
|
|
case ITEM_ID_PROTEIN:
|
|
if (pokemonData->attack > 249)
|
|
{
|
|
itemWeight = 0;
|
|
}
|
|
else
|
|
{
|
|
itemWeight = 100;
|
|
}
|
|
break;
|
|
case ITEM_ID_CALCIUM:
|
|
if (pokemonData->specialAttack > 249)
|
|
{
|
|
itemWeight = 0;
|
|
}
|
|
else
|
|
{
|
|
itemWeight = 100;
|
|
}
|
|
break;
|
|
case ITEM_ID_IRON:
|
|
if (pokemonData->defense > 249)
|
|
{
|
|
itemWeight = 0;
|
|
}
|
|
else
|
|
{
|
|
itemWeight = 100;
|
|
}
|
|
break;
|
|
case ITEM_ID_ZINC:
|
|
if (pokemonData->specialDefense > 249)
|
|
{
|
|
itemWeight = 0;
|
|
}
|
|
else
|
|
{
|
|
itemWeight = 100;
|
|
}
|
|
break;
|
|
case ITEM_ID_LIFE_SEED:
|
|
if (!targetOther)
|
|
{
|
|
if (CanTargetAdjacentPokemon(targetPokemon))
|
|
{
|
|
itemWeight = 10;
|
|
}
|
|
else
|
|
{
|
|
itemWeight = 100;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
itemWeight = 0;
|
|
}
|
|
break;
|
|
case ITEM_ID_EYEDROP_SEED:
|
|
if (!CanSeeInvisible(targetPokemon))
|
|
{
|
|
if (CanTargetAdjacentPokemon(targetPokemon))
|
|
{
|
|
itemWeight = 80;
|
|
}
|
|
else
|
|
{
|
|
itemWeight = 5;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
break;
|
|
case ITEM_ID_QUICK_SEED:
|
|
if (targetPokemon->entityData->movementSpeed < MAX_MOVEMENT_SPEED)
|
|
{
|
|
if (CanTargetAdjacentPokemon(targetPokemon))
|
|
{
|
|
itemWeight = 80;
|
|
}
|
|
else
|
|
{
|
|
itemWeight = 5;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
break;
|
|
case ITEM_ID_ALLURE_SEED:
|
|
if (pokemonData->eyesightStatus != EYESIGHT_STATUS_CROSS_EYED)
|
|
{
|
|
if (CanTargetAdjacentPokemon(targetPokemon))
|
|
{
|
|
itemWeight = 80;
|
|
}
|
|
else
|
|
{
|
|
itemWeight = 5;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
break;
|
|
case ITEM_ID_CHERI_BERRY:
|
|
if (pokemonData->nonVolatileStatus != NON_VOLATILE_STATUS_PARALYZED)
|
|
{
|
|
return 0;
|
|
}
|
|
else if (CanTargetAdjacentPokemon(targetPokemon))
|
|
{
|
|
itemWeight = 80;
|
|
}
|
|
else
|
|
{
|
|
itemWeight = 30;
|
|
}
|
|
break;
|
|
case ITEM_ID_TOTTER_SEED:
|
|
if (pokemonData->volatileStatus != VOLATILE_STATUS_CONFUSED)
|
|
{
|
|
if (CanTargetAdjacentPokemon(targetPokemon))
|
|
{
|
|
itemWeight = 80;
|
|
}
|
|
else
|
|
{
|
|
itemWeight = 15;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
break;
|
|
case ITEM_ID_PECHA_BERRY:
|
|
if (pokemonData->nonVolatileStatus != NON_VOLATILE_STATUS_POISONED &&
|
|
pokemonData->nonVolatileStatus != NON_VOLATILE_STATUS_BADLY_POISONED)
|
|
{
|
|
return 0;
|
|
}
|
|
else if (CanTargetAdjacentPokemon(targetPokemon))
|
|
{
|
|
itemWeight = 100;
|
|
}
|
|
else
|
|
{
|
|
itemWeight = 50;
|
|
}
|
|
break;
|
|
case ITEM_ID_BLINKER_SEED:
|
|
if (pokemonData->eyesightStatus != EYESIGHT_STATUS_BLINKER)
|
|
{
|
|
if (CanTargetAdjacentPokemon(targetPokemon))
|
|
{
|
|
itemWeight = 80;
|
|
}
|
|
else
|
|
{
|
|
itemWeight = 5;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
break;
|
|
case ITEM_ID_WARP_SEED:
|
|
if (!targetAlly)
|
|
{
|
|
if (CanTargetAdjacentPokemon(targetPokemon))
|
|
{
|
|
itemWeight = 40;
|
|
}
|
|
else
|
|
{
|
|
itemWeight = 5;
|
|
}
|
|
}
|
|
else if (pokemonData->HP < pokemonData->maxHP && pokemonData->HP < 20)
|
|
{
|
|
if (!targetOther)
|
|
{
|
|
if (CanTargetAdjacentPokemon(targetPokemon))
|
|
{
|
|
itemWeight = 100;
|
|
}
|
|
else
|
|
{
|
|
itemWeight = 50;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
itemWeight = 50;
|
|
}
|
|
}
|
|
break;
|
|
case ITEM_ID_PATSY_BAND:
|
|
itemWeight = 40;
|
|
break;
|
|
case ITEM_ID_SLEEP_SEED:
|
|
if (pokemonData->sleepStatus != SLEEP_STATUS_SLEEP &&
|
|
pokemonData->sleepStatus != SLEEP_STATUS_NAPPING &&
|
|
pokemonData->sleepStatus != SLEEP_STATUS_NIGHTMARE)
|
|
{
|
|
if (CanTargetAdjacentPokemon(targetPokemon))
|
|
{
|
|
itemWeight = 80;
|
|
}
|
|
else
|
|
{
|
|
itemWeight = 5;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
break;
|
|
case ITEM_ID_CHESTO_BERRY:
|
|
if (pokemonData->sleepStatus != SLEEP_STATUS_SLEEPLESS)
|
|
{
|
|
itemWeight = 5;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
break;
|
|
case ITEM_ID_JOY_SEED:
|
|
if (pokemonData->level < 99)
|
|
{
|
|
itemWeight = 80;
|
|
}
|
|
else
|
|
{
|
|
itemWeight = 0;
|
|
}
|
|
break;
|
|
case ITEM_ID_GINSENG:
|
|
itemWeight = 80;
|
|
break;
|
|
case ITEM_ID_RAWST_BERRY:
|
|
if (pokemonData->nonVolatileStatus == NON_VOLATILE_STATUS_BURNED)
|
|
{
|
|
return 50;
|
|
}
|
|
else
|
|
{
|
|
itemWeight = 0;
|
|
}
|
|
break;
|
|
case ITEM_ID_HUNGER_SEED:
|
|
if (RoundUpFixedPoint(pokemonData->belly) > 0)
|
|
{
|
|
return 50;
|
|
}
|
|
else
|
|
{
|
|
itemWeight = 0;
|
|
}
|
|
break;
|
|
case ITEM_ID_DOOM_SEED:
|
|
if (pokemonData->level > 1)
|
|
{
|
|
itemWeight = 80;
|
|
}
|
|
else
|
|
{
|
|
itemWeight = 0;
|
|
}
|
|
break;
|
|
case ITEM_ID_STUN_SEED:
|
|
if (pokemonData->immobilizeStatus == IMMOBILIZE_STATUS_PETRIFIED)
|
|
{
|
|
return 0;
|
|
}
|
|
else if (CanTargetAdjacentPokemon(targetPokemon))
|
|
{
|
|
itemWeight = 80;
|
|
}
|
|
else
|
|
{
|
|
itemWeight = 5;
|
|
}
|
|
break;
|
|
case ITEM_ID_BLAST_SEED:
|
|
if (CanTargetAdjacentPokemon(targetPokemon))
|
|
{
|
|
itemWeight = 80;
|
|
}
|
|
else
|
|
{
|
|
itemWeight = 30;
|
|
}
|
|
break;
|
|
case ITEM_ID_APPLE:
|
|
case ITEM_ID_BIG_APPLE:
|
|
case ITEM_ID_HUGE_APPLE:
|
|
if (RoundUpFixedPoint(pokemonData->belly) < 10)
|
|
{
|
|
return 100;
|
|
}
|
|
else
|
|
{
|
|
itemWeight = 0;
|
|
}
|
|
break;
|
|
case ITEM_ID_GRIMY_FOOD:
|
|
itemWeight = 30;
|
|
break;
|
|
case ITEM_ID_ROLLCALL_ORB:
|
|
move = pokemonData->moves; // Fixes a regswap.
|
|
if (targetOther)
|
|
{
|
|
itemWeight = 0;
|
|
}
|
|
else
|
|
{
|
|
itemWeight = 20;
|
|
}
|
|
break;
|
|
default:
|
|
itemWeight = 0;
|
|
}
|
|
return itemWeight;
|
|
}
|
|
|
|
bool8 CanTargetAdjacentPokemon(struct DungeonEntity *pokemon)
|
|
{
|
|
s32 facingDir;
|
|
for (facingDir = 0; facingDir < NUM_DIRECTIONS; facingDir++)
|
|
{
|
|
struct MapTile *mapTile = GetMapTile_1(pokemon->posWorld.x + gAdjacentTileOffsets[facingDir].x, pokemon->posWorld.y + gAdjacentTileOffsets[facingDir].y);
|
|
struct DungeonEntity *adjacentPokemon = mapTile->pokemon;
|
|
if (adjacentPokemon != NULL && GetEntityType(adjacentPokemon) != ENTITY_NONE &&
|
|
CanTarget(pokemon, adjacentPokemon, FALSE, TRUE) == TARGET_CAPABILITY_CAN_TARGET)
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|