490 lines
14 KiB
C

#ifndef GUARD_BM_UNIT_H
#define GUARD_BM_UNIT_H
#include "global.h"
struct SupportData;
// Config
enum { UNIT_LEVEL_MAX = 20 };
enum { UNIT_ITEM_COUNT = 5 };
enum { UNIT_DEFINITION_ITEM_COUNT = 4 };
// Meaningful constants
enum { UNIT_EXP_DISABLED = 0xFF };
struct CharacterData
{
/* 00 */ u16 nameTextId;
/* 02 */ u16 descTextId;
/* 04 */ u8 number;
/* 05 */ u8 defaultClass;
/* 06 */ u16 portraitId;
/* 08 */ u8 miniPortrait;
/* 09 */ u8 affinity;
/* 0A */ u8 sort_order;
/* 0B */ s8 baseLevel;
/* 0C */ s8 baseHP;
/* 0D */ s8 basePow;
/* 0E */ s8 baseSkl;
/* 0F */ s8 baseSpd;
/* 10 */ s8 baseDef;
/* 11 */ s8 baseRes;
/* 12 */ s8 baseLck;
/* 13 */ s8 baseCon;
/* 14 */ u8 baseRanks[8];
/* 1C */ u8 growthHP;
/* 1D */ u8 growthPow;
/* 1E */ u8 growthSkl;
/* 1F */ u8 growthSpd;
/* 20 */ u8 growthDef;
/* 21 */ u8 growthRes;
/* 22 */ u8 growthLck;
/* 23 */ u8 _u23;
/* 24 */ u8 _u24;
/* 25 */ u8 _u25;
/* 26 */ u8 _u26;
/* 27 */ u8 _u27;
/* 28 */ u32 attributes;
/* 2C */ const struct SupportData* pSupportData;
/* 30 */ u8 visit_group;
/* 31 */ u8 _pad_[0x34 - 0x31];
};
struct ClassData
{
/* 00 */ u16 nameTextId;
/* 02 */ u16 descTextId;
/* 04 */ u8 number;
/* 05 */ u8 promotion;
/* 06 */ u8 SMSId;
/* 07 */ u8 slowWalking;
/* 08 */ u16 defaultPortraitId;
/* 0A */ u8 sort_order;
/* 0B */ s8 baseHP;
/* 0C */ s8 basePow;
/* 0D */ s8 baseSkl;
/* 0E */ s8 baseSpd;
/* 0F */ s8 baseDef;
/* 10 */ s8 baseRes;
/* 11 */ s8 baseCon;
/* 12 */ s8 baseMov;
/* 13 */ s8 maxHP;
/* 14 */ s8 maxPow;
/* 15 */ s8 maxSkl;
/* 16 */ s8 maxSpd;
/* 17 */ s8 maxDef;
/* 18 */ s8 maxRes;
/* 19 */ s8 maxCon;
/* 1A */ s8 classRelativePower;
/* 1B */ s8 growthHP;
/* 1C */ s8 growthPow;
/* 1D */ s8 growthSkl;
/* 1E */ s8 growthSpd;
/* 1F */ s8 growthDef;
/* 20 */ s8 growthRes;
/* 21 */ s8 growthLck;
/* 22 */ u8 promotionHp;
/* 23 */ u8 promotionPow;
/* 24 */ u8 promotionSkl;
/* 25 */ u8 promotionSpd;
/* 26 */ u8 promotionDef;
/* 27 */ u8 promotionRes;
/* 28 */ u32 attributes;
/* 2C */ u8 baseRanks[8];
/* 34 */ const void* pBattleAnimDef;
/* 38 */ const s8* pMovCostTable[3]; // standard, rain, snow
/* 44 */ const s8* pTerrainAvoidLookup;
/* 48 */ const s8* pTerrainDefenseLookup;
/* 4C */ const s8* pTerrainResistanceLookup;
//* 44 */ const s8* pTerrainBonusTables[3]; // def, avo, res
/* 50 */ const void* _pU50;
};
struct Unit
{
/* 00 */ const struct CharacterData* pCharacterData;
/* 04 */ const struct ClassData* pClassData;
/* 08 */ s8 level;
/* 09 */ u8 exp;
/* 0A */ u8 aiFlags;
/* 0B */ s8 index;
/* 0C */ u32 state;
/* 10 */ s8 xPos;
/* 11 */ s8 yPos;
/* 12 */ s8 maxHP;
/* 13 */ s8 curHP;
/* 14 */ s8 pow;
/* 15 */ s8 skl;
/* 16 */ s8 spd;
/* 17 */ s8 def;
/* 18 */ s8 res;
/* 19 */ s8 lck;
/* 1A */ s8 conBonus;
/* 1B */ u8 rescue;
/* 1C */ u8 ballistaIndex;
/* 1D */ s8 movBonus;
/* 1E */ u16 items[UNIT_ITEM_COUNT];
/* 28 */ u8 ranks[8];
/* 30 */ u8 statusIndex : 4;
/* 30 */ u8 statusDuration : 4;
/* 31 */ u8 torchDuration : 4;
/* 31 */ u8 barrierDuration : 4;
/* 32 */ u8 supports[UNIT_SUPPORT_MAX_COUNT];
/* 39 */ s8 supportBits;
/* 3A */ u8 _u3A;
/* 3B */ u8 _u3B;
/* 3C */ struct SMSHandle* pMapSpriteHandle;
/* 40 */ u16 ai3And4;
/* 42 */ u8 ai1;
/* 43 */ u8 ai1data;
/* 44 */ u8 ai2;
/* 45 */ u8 ai2data;
/* 46 */ u8 _u46;
/* 47 */ u8 _u47;
};
struct BITPACKED UnitDefinition
{
/* 00 */ u8 charIndex;
/* 01 */ u8 classIndex;
/* 02 */ u8 leaderCharIndex;
/* 03 */ u8 autolevel : 1;
/* 03 */ u8 allegiance : 2;
/* 03 */ u8 level : 5;
/* 04 */ u16 xPosition : 6; /* 04:0 to 04:5 */
/* 04 */ u16 yPosition : 6; /* 04:6 to 05:3 */
/* 05 */ u16 genMonster : 1; /* 05:4 */
/* 05 */ u16 itemDrop : 1; /* 05:5 */
/* 05 */ u16 sumFlag : 1; /* 05:6 */
/* 05 */ u16 extraData : 9; /* 05:7 to 06:7 */
/* 07 */ u16 redaCount : 8;
/* 08 */ const void* redas;
/* 0C */ u8 items[UNIT_DEFINITION_ITEM_COUNT];
/* 10 */ u8 ai[4];
};
enum
{
// Unit state constant masks
US_NONE = 0,
US_HIDDEN = (1 << 0),
US_UNSELECTABLE = (1 << 1),
US_DEAD = (1 << 2),
US_NOT_DEPLOYED = (1 << 3),
US_RESCUING = (1 << 4),
US_RESCUED = (1 << 5),
US_HAS_MOVED = (1 << 6), // Bad name?
US_CANTOING = US_HAS_MOVED, // Alias
US_UNDER_A_ROOF = (1 << 7),
US_BIT8 = (1 << 8), // has been seen?
US_BIT9 = (1 << 9), // hidden by fog?
US_HAS_MOVED_AI = (1 << 10),
US_IN_BALLISTA = (1 << 11),
US_DROP_ITEM = (1 << 12),
US_GROWTH_BOOST = (1 << 13),
US_SOLOANIM_1 = (1 << 14),
US_SOLOANIM_2 = (1 << 15),
US_BIT16 = (1 << 16),
US_BIT17 = (1 << 17),
US_BIT18 = (1 << 18),
US_BIT19 = (1 << 19),
US_BIT20 = (1 << 20),
US_BIT21 = (1 << 21),
US_BIT22 = (1 << 22),
US_BIT23 = (1 << 23),
// = (1 << 24),
US_BIT25 = (1 << 25),
US_BIT26 = (1 << 26),
US_BIT27 = (1 << 27),
// = (1 << 28),
// = (1 << 29),
// = (1 << 30),
// = (1 << 31),
// Helpers
US_UNAVAILABLE = (US_DEAD | US_NOT_DEPLOYED | US_BIT16),
};
enum
{
// Unit status identifiers
UNIT_STATUS_NONE = 0,
UNIT_STATUS_POISON = 1,
UNIT_STATUS_SLEEP = 2,
UNIT_STATUS_SILENCED = 3,
UNIT_STATUS_BERSERK = 4,
UNIT_STATUS_ATTACK = 5,
UNIT_STATUS_DEFENSE = 6,
UNIT_STATUS_CRIT = 7,
UNIT_STATUS_AVOID = 8,
UNIT_STATUS_SICK = 9,
UNIT_STATUS_RECOVER = 10,
UNIT_STATUS_PETRIFY = 11,
UNIT_STATUS_12 = 12,
UNIT_STATUS_13 = 13,
};
enum {
FACTION_BLUE = 0x00, // player units
FACTION_GREEN = 0x40, // ally npc units
FACTION_RED = 0x80, // enemy units
FACTION_PURPLE = 0xC0, // link arena 4th team
};
enum
{
FACTION_ID_BLUE = 0,
FACTION_ID_GREEN = 1,
FACTION_ID_RED = 2,
FACTION_ID_PURPLE = 3,
};
enum
{
// Character/Class attributes
CA_NONE = 0,
CA_MOUNTEDAID = (1 << 0),
CA_CANTO = (1 << 1),
CA_STEAL = (1 << 2),
CA_THIEF = (1 << 3),
CA_DANCE = (1 << 4),
CA_PLAY = (1 << 5),
CA_CRITBONUS = (1 << 6),
CA_BALLISTAE = (1 << 7),
CA_PROMOTED = (1 << 8),
CA_SUPPLY = (1 << 9),
CA_MOUNTED = (1 << 10),
CA_WYVERN = (1 << 11),
CA_PEGASUS = (1 << 12),
CA_LORD = (1 << 13),
CA_FEMALE = (1 << 14),
CA_BOSS = (1 << 15),
CA_LOCK_1 = (1 << 16),
CA_LOCK_2 = (1 << 17),
CA_LOCK_3 = (1 << 18), // Dragons or Monster depending of game
CA_MAXLEVEL10 = (1 << 19),
CA_UNSELECTABLE = (1 << 20),
CA_TRIANGLEATTACK_PEGASI = (1 << 21),
CA_TRIANGLEATTACK_ARMORS = (1 << 22),
CA_BIT_23 = (1 << 23),
CA_NEGATE_LETHALITY = (1 << 24),
CA_ASSASSIN = (1 << 25),
CA_MAGICSEAL = (1 << 26),
CA_SUMMON = (1 << 27),
CA_LOCK_4 = (1 << 28),
CA_LOCK_5 = (1 << 29),
CA_LOCK_6 = (1 << 30),
CA_LOCK_7 = (1 << 31),
// Helpers
CA_REFRESHER = CA_DANCE | CA_PLAY,
CA_FLYER = CA_WYVERN | CA_PEGASUS,
CA_TRIANGLEATTACK_ANY = CA_TRIANGLEATTACK_ARMORS | CA_TRIANGLEATTACK_PEGASI,
};
enum
{
// To check result of GetUnit[Item]UseBits
UNIT_USEBIT_WEAPON = (1 << 0),
UNIT_USEBIT_STAFF = (1 << 1),
};
enum unit_affinity_index {
UNIT_AFFIN_FIRE = 1,
UNIT_AFFIN_THUNDER,
UNIT_AFFIN_WIND,
UNIT_AFFIN_ICE,
UNIT_AFFIN_DARK,
UNIT_AFFIN_LIGHT,
UNIT_AFFIN_ANIMA,
};
// TODO: MOVE ELSEWHERE
extern CONST_DATA struct ClassData gClassData[]; // gClassData
extern CONST_DATA struct CharacterData gCharacterData[]; // gCharacterData
extern struct UnitDefinition gUnitDef1;
extern struct UnitDefinition gUnitDef2;
extern struct UnitDefinition gUnitDefEggHatching;
extern struct UnitDefinition gUnitDefSumDK[];
extern struct Unit gUnitArrayBlue[62];
extern struct Unit gUnitArrayRed[50];
extern struct Unit gUnitArrayGreen[20];
extern CONST_DATA struct Unit *gUnitLookup[0x100];
void InitUnits(void);
void ClearUnit(struct Unit* unit);
void CopyUnit(struct Unit* from, struct Unit* to);
struct Unit* GetFreeUnit(int faction);
struct Unit* GetFreeBlueUnit(const struct UnitDefinition* uDef);
int GetUnitFogViewRange(struct Unit* unit);
void SetUnitStatus(struct Unit* unit, int statusId);
void SetUnitStatusExt(struct Unit* unit, int status, int duration);
int GetUnitSMSId(struct Unit* unit);
bool UnitAddItem(struct Unit* unit, int item);
void UnitClearInventory(struct Unit* unit);
void UnitRemoveInvalidItems(struct Unit* unit);
int GetUnitItemCount(struct Unit* unit);
bool UnitHasItem(struct Unit* unit, int item);
int LoadUnits(const struct UnitDefinition* uDef);
void sub_8017A54(struct Unit* unit);
bool CanClassWieldWeaponType(u8 classId, u8 wpnType);
struct Unit* LoadUnit(const struct UnitDefinition* uDef);
void UnitInitFromDefinition(struct Unit* unit, const struct UnitDefinition* uDef);
void UnitLoadItemsFromDefinition(struct Unit* unit, const struct UnitDefinition* uDef);
void UnitLoadStatsFromChracter(struct Unit* unit, const struct CharacterData* character);
void FixROMUnitStructPtr(struct Unit* unit);
void UnitLoadSupports(struct Unit* unit);
void UnitAutolevelWExp(struct Unit* unit, const struct UnitDefinition* uDef);
void UnitAutolevelCore(struct Unit* unit, u8 classId, int levelCount);
void UnitAutolevelPenalty(struct Unit* unit, u8 classId, int levelCount);
void UnitApplyBonusLevels(struct Unit* unit, int levelCount);
void UnitAutolevel(struct Unit* unit);
void UnitAutolevelRealistic(struct Unit* unit);
void UnitCheckStatCaps(struct Unit* unit);
struct Unit* GetUnitFromCharId(int charId);
struct Unit* GetUnitFromCharIdAndFaction(int charId, int faction);
bool CanUnitRescue(struct Unit* actor, struct Unit* target);
void UnitRescue(struct Unit* actor, struct Unit* target);
void UnitDrop(struct Unit* actor, int xTarget, int yTarget);
s8 UnitGive(struct Unit* actor, struct Unit* target);
void UnitKill(struct Unit* unit);
void UnitChangeFaction(struct Unit* unit, int faction);
void UnitFinalizeMovement(struct Unit* unit);
void UnitGetDeathDropLocation(struct Unit* unit, int* xOut, int* yOut);
void UnitBeginAction(struct Unit* unit);
void UnitBeginCantoAction(struct Unit* unit);
void MoveActiveUnit(int x, int y);
void ClearActiveFactionGrayedStates(void);
void TickActiveFactionTurn(void);
void SetAllUnitNotBackSprite(void); // TODO: better name
void UnitUpdateUsedItem(struct Unit* unit, int itemSlot);
int GetUnitAid(struct Unit* unit);
int GetUnitMagBy2Range(struct Unit* unit);
bool UnitHasMagicRank(struct Unit* unit);
void sub_8018A7C(struct Unit* unit, int x, int y);
int GetUnitKeyItemSlotForTerrain(struct Unit* unit, int terrain);
int GetUnitAidIconId(u32 attributes);
int GetUnitWeaponUsabilityBits(struct Unit* unit);
int GetCombinedEnemyWeaponUsabilityBits(void);
bool CanUnitMove(void);
bool IsPositionMagicSealed(int x, int y);
bool IsUnitMagicSealed(struct Unit* unit);
int GetUnitLastItem(struct Unit* unit);
const s8* GetUnitMovementCost(struct Unit* unit);
int GetClassSMSId(int classId);
void UpdatePrevDeployStates(void);
void LoadUnitPrepScreenPositions(void);
void ClearTemporaryUnits(void);
bool IsUnitSlotAvailable(int faction);
void sub_8018F80(void);
void sub_8018FC0(void);
u16 CountAvailableBlueUnits(void);
int CountRedUnits(void);
int CountGreenUnits(void);
void ClearCutsceneUnits(void);
void sub_8019108(void);
int GetUnitCurrentHp(struct Unit* unit);
int GetUnitMaxHp(struct Unit* unit);
int GetUnitPower(struct Unit* unit);
int GetUnitSkill(struct Unit* unit);
int GetUnitSpeed(struct Unit* unit);
int GetUnitDefense(struct Unit* unit);
int GetUnitResistance(struct Unit* unit);
int GetUnitLuck(struct Unit* unit);
int GetUnitPortraitId(struct Unit* unit);
int GetUnitMiniPortraitId(struct Unit* unit);
int GetUnitLeaderCharId(struct Unit* unit);
void SetUnitLeaderCharId(struct Unit* unit, int charId);
void SetUnitHp(struct Unit* unit, int value);
void AddUnitHp(struct Unit* unit, int amount);
char* GetUnitRescueName(struct Unit* unit);
char* GetUnitStatusName(struct Unit* unit);
struct Unit* GetUnit(int id);
const struct ClassData* GetClassData(int classId);
const struct CharacterData* GetCharacterData(int charId);
void UnitRemoveItem(struct Unit* unit, int slot);
#define UNIT_IS_VALID(aUnit) ((aUnit) && (aUnit)->pCharacterData)
#define UNIT_CHAR_ID(aUnit) ((aUnit)->pCharacterData->number)
#define UNIT_CLASS_ID(aUnit) ((aUnit)->pClassData->number)
#define UNIT_FACTION(aUnit) ((aUnit)->index & 0xC0)
#define UNIT_CATTRIBUTES(aUnit) ((aUnit)->pCharacterData->attributes | (aUnit)->pClassData->attributes)
#define UNIT_NAME_ID(aUnit) ((aUnit)->pCharacterData->nameTextId)
#define UNIT_MHP_MAX(aUnit) (UNIT_FACTION(unit) == FACTION_RED ? 120 : 60)
#define UNIT_POW_MAX(aUnit) ((aUnit)->pClassData->maxPow)
#define UNIT_SKL_MAX(aUnit) ((aUnit)->pClassData->maxSkl)
#define UNIT_SPD_MAX(aUnit) ((aUnit)->pClassData->maxSpd)
#define UNIT_DEF_MAX(aUnit) ((aUnit)->pClassData->maxDef)
#define UNIT_RES_MAX(aUnit) ((aUnit)->pClassData->maxRes)
#define UNIT_LCK_MAX(aUnit) (30)
#define UNIT_CON_MAX(aUnit) ((aUnit)->pClassData->maxCon)
#define UNIT_MOV_MAX(aUnit) (15)
#define UNIT_CON_BASE(aUnit) ((aUnit)->pClassData->baseCon + (aUnit)->pCharacterData->baseCon)
#define UNIT_MOV_BASE(aUnit) ((aUnit)->pClassData->baseMov)
#define UNIT_CON(aUnit) (UNIT_CON_BASE(aUnit) + (aUnit)->conBonus)
#define UNIT_MOV(aUnit) ((aUnit)->movBonus + UNIT_MOV_BASE(aUnit))
#define UNIT_IS_GORGON_EGG(aUnit) (((aUnit)->pClassData->number == CLASS_GORGONEGG) || ((aUnit)->pClassData->number == CLASS_GORGONEGG2))
#define UNIT_IS_PHANTOM(aUnit) ((aUnit)->pClassData->number == CLASS_PHANTOM)
#define UNIT_ARENA_LEVEL(aUnit) (((aUnit)->state >> 17) & 0x7)
#define UNIT_SUPPORT_DATA(aUnit) ((aUnit)->pCharacterData->pSupportData)
// NOTE: if this ends up being only used in [Get|Set]UnitLeaderCharId, having this as a macro may end up being unnecessary
#define UNIT_LEADER_CHARACTER(aUnit) ((aUnit)->supports[UNIT_SUPPORT_MAX_COUNT-1])
#endif // GUARD_BM_UNIT_H