DS-Pokemon-Rom-Editor/DS_Map/ROMFiles/ItemData.cs
2025-06-19 11:27:51 +02:00

584 lines
19 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.IO;
using static DSPRE.RomInfo;
using static Microsoft.WindowsAPICodePack.Shell.PropertySystem.SystemProperties.System;
namespace DSPRE.ROMFiles
{
public enum NaturalGiftType
{
Normal = 0,
Fighting = 1,
Flying = 2,
Poison = 3,
Ground = 4,
Rock = 5,
Bug = 6,
Ghost = 7,
Steel = 8,
Fire = 10,
Water = 11,
Grass = 12,
Electric = 13,
Psychic = 14,
Ice = 15,
Dragon = 16,
Dark = 17,
NONE = 31
}
public enum FieldUseFunc : byte
{
Generic = 0,
HealingItem = 1,
Dummy1 = 2,
Dummy2 = 3,
Bicycle = 4,
Dummy3 = 5,
TMHM = 6,
Mail = 7,
Berry = 8,
Dummy4 = 9,
PalPad = 10,
Dummy5 = 11,
Dummy6 = 12,
Dummy7 = 13,
Honey = 14,
Dummy8 = 15,
OldRod = 16,
GoodRod = 17,
SuperRod = 18,
Generic2 = 19,
EvoStone = 20,
EscapeRope = 21,
Dummy9 = 22,
ApricornBox = 23,
BerryPots = 24,
UnownReport = 25,
DowsingMchn = 26,
GbSounds = 27,
Gracidea = 28,
VSRecorder = 29
}
public enum BattleUseFunc : byte
{
No_Use = 0,
Ball = 1,
Healing = 2,
Escape = 3
}
public enum FieldPocket
{
Items = 0,
Medicine = 1,
Balls = 2,
TmHms = 3,
Berries = 4,
Mail = 5,
BattleItems = 6,
KeyItems = 7
}
public enum BattlePocket
{
None = 0,
PokeBalls = 1,
BattleItems = 2,
HpRestore = 4,
StatusHealers = 8,
PpRestore = 16
}
public enum HoldEffect
{
None = 0,
HpRestore = 1,
GiratinaBoost = 2,
DialgaBoost = 3,
PalkiaBoost = 4,
PrzRestore = 5,
SlpRestore = 6,
PsnRestore = 7,
BrnRestore = 8,
FrzRestore = 9,
PpRestore = 10,
ConfuseRestore = 11,
StatusRestore = 12,
HpPctRestore = 13,
HpRestoreSpicy = 14,
HpRestoreDry = 15,
HpRestoreSweet = 16,
HpRestoreBitter = 17,
HpRestoreSour = 18,
WeakenSeFire = 19,
WeakenSeWater = 20,
WeakenSeElectric = 21,
WeakenSeGrass = 22,
WeakenSeIce = 23,
WeakenSeFight = 24,
WeakenSePoison = 25,
WeakenSeGround = 26,
WeakenSeFlying = 27,
WeakenSePsychic = 28,
WeakenSeBug = 29,
WeakenSeRock = 30,
WeakenSeGhost = 31,
WeakenSeDragon = 32,
WeakenSeDark = 33,
WeakenSeSteel = 34,
WeakenNormal = 35,
PinchAtkUp = 36,
PinchDefUp = 37,
PinchSpeedUp = 38,
PinchSpAtkUp = 39,
PinchSpDefUp = 40,
PinchCritrateUp = 41,
PinchRandomUp = 42,
HpRestoreSe = 43,
PinchAccUp = 44,
PinchPriority = 45,
RecoilPhysical = 46,
RecoilSpecial = 47,
AccReduce = 48,
StatdownRestore = 49,
EvsUpSpeedDown = 50,
ExpShare = 51,
SometimesPriority = 52,
FriendshipUp = 53,
HealInfatuation = 54,
ChoiceAtk = 55,
SometimesFlinch = 56,
StrengthenBug = 57,
MoneyUp = 58,
EncountersDown = 59,
LatiSpecial = 60,
ClamperlSpAtk = 61,
ClamperlSpDef = 62,
Flee = 63,
NoEvolve = 64,
MaybeEndure = 65,
ExpUp = 66,
CritrateUp = 67,
StrengthenSteel = 68,
HpRestoreGradual = 69,
EvolveSeadra = 70,
PikaSpAtkUp = 71,
StrengthenGround = 72,
StrengthenRock = 73,
StrengthenGrass = 74,
StrengthenDark = 75,
StrengthenFight = 76,
StrengthenElectric = 77,
StrengthenWater = 78,
StrengthenFlying = 79,
StrengthenPoison = 80,
StrengthenIce = 81,
StrengthenGhost = 82,
StrengthenPsychic = 83,
StrengthenFire = 84,
StrengthenDragon = 85,
StrengthenNormal = 86,
EvolvePorygon = 87,
HpRestoreOnDmg = 88,
ChanseyCritrateUp = 89,
DittoDefUp = 90,
CuboneAtkUp = 91,
FarfetchdCritrateUp = 92,
AccuracyUp = 93,
PowerUpPhys = 94,
PowerUpSpec = 95,
PowerUpSe = 96,
ExtendScreens = 97,
HpDrainOnAtk = 98,
ChargeSkip = 99,
PsnUser = 100,
BrnUser = 101,
DittoSpeedUp = 102,
Endure = 103,
AccuracyUpSlower = 104,
BoostRepeated = 105,
SpeedDownGrounded = 106,
PriorityDown = 107,
ReciprocateInfat = 108,
HpRestorePsnType = 109,
ExtendHail = 110,
ExtendSandstorm = 111,
ExtendSun = 112,
ExtendRain = 113,
ExtendTrapping = 114,
ChoiceSpeed = 115,
DmgUserContactXfr = 116,
LvlupAtkEvUp = 117,
LvlupDefEvUp = 118,
LvlupSpAtkEvUp = 119,
LvlupSpDefEvUp = 120,
LvlupSpeedEvUp = 121,
LvlupHpEvUp = 122,
Switch = 123,
LeechBoost = 124,
ChoiceSpAtk = 125,
ArceusFire = 126,
ArceusWater = 127,
ArceusElectric = 128,
ArceusGrass = 129,
ArceusIce = 130,
ArceusFighting = 131,
ArceusPoison = 132,
ArceusGround = 133,
ArceusFlying = 134,
ArceusPsychic = 135,
ArceusBug = 136,
ArceusRock = 137,
ArceusGhost = 138,
ArceusDragon = 139,
ArceusDark = 140,
ArceusSteel = 141,
EvolveRhydon = 142,
EvolveElectabuzz = 143,
EvolveMagmar = 144,
EvolvePorygon2 = 145,
EvolveDusclops = 146,
// These are hg-engine items, not in gen 4
//BurnDrive = 147,
//ChillDrive = 148,
//DouseDrive = 149,
//ShockDrive = 150,
//EvolveFeebas = 151,
//Eviolite = 152,
//HalveWeight = 153,
//DamageOnContact = 154,
//UngroundDestroyedOnHit = 155,
//ForceSwitchOnDamage = 156,
//LoseTypeImmunities = 157,
//TrappingDamageUp = 158,
//BoostSpecialAttackOnWaterHit = 159,
//BoostAtkOnElectricHit = 160,
//SwitchOutWhenHit = 161,
//BoostAtkAndSpAtkOnSe = 162,
//SpDefBoostNoStatusMoves = 163,
//ArceusFairy = 164,
//EvolveSwirlix = 165,
//EvolveSpritzee = 166,
//BoostSpecialDefenseOnWaterHit = 167,
//BoostAtkOnIceHit = 168,
//SporePowderImmunity = 169,
//WeakenSeFairy = 170,
//BoostDefOnPhysicalHit = 171,
//BoostSpDefOnSpecialHit = 172,
//IntimidateBoostSpeed = 173,
//ExtendTerrain = 174,
//PreventContactEffects = 175,
//BoostDefOnElectricTerrain = 176,
//BoostSpDefOnPsychicTerrain = 177,
//BoostSpDefOnMistyTerrain = 178,
//BoostDefOnGrassyTerrain = 179,
//FightingMemory = 180,
//FlyingMemory = 181,
//PoisonMemory = 182,
//GroundMemory = 183,
//RockMemory = 184,
//BugMemory = 185,
//GhostMemory = 186,
//SteelMemory = 187,
//FireMemory = 188,
//WaterMemory = 189,
//GrassMemory = 190,
//ElectricMemory = 191,
//PsychicMemory = 192,
//IceMemory = 193,
//DragonMemory = 194,
//DarkMemory = 195,
//FairyMemory = 196,
//TransformZacian = 197,
//TransformZamazenta = 198,
//BoostSpAtkOnSoundMove = 199,
//SwitchOutOnStatDrop = 200,
//IgnoreEntryHazards = 201,
//BoostSpeedOnMiss = 202,
//DropSpeedInTrickRoom = 203,
//UnaffectedByRainOrSun = 204,
//DialgaBoostAndTransform = 205,
//PalkiaBoostAndTransform = 206,
//GiratinaBoostAndTransform = 207,
//ArceusNormal = 208,
//ActivateParadoxAbilities = 209,
//PreventAbilityChanges = 210,
//PreventStatDrops = 211,
//CopyStatIncrease = 212,
//IncreasePunchingMoveDmg = 213,
//PreventSecondaryEffects = 214,
//IncreaseMultiStrikeMinimum = 215,
//StrengthenFairy = 216,
//CornerstoneMask = 217,
//WellspringMask = 218,
//HearthflameMask = 219
}
public class ItemData : RomFile
{
public ushort price;
public HoldEffect holdEffect;
public byte HoldEffectParam;
public byte PluckEffect;
public byte FlingEffect;
public byte FlingPower;
public byte NaturalGiftPower;
// Bit-packed 16-bit value
public NaturalGiftType naturalGiftType; // 5 bits
public bool PreventToss; // 1 bit
public bool Selectable; // 1 bit
public FieldPocket fieldPocket; // 4 bits
public BattlePocket battlePocket; // 5 bits
public FieldUseFunc fieldUseFunc;
public BattleUseFunc battleUseFunc;
public byte PartyUse;
public ItemPartyUseParam PartyUseParam;
public ItemData(Stream stream)
{
using (BinaryReader reader = new BinaryReader(stream))
{
price = reader.ReadUInt16();
holdEffect = (HoldEffect)reader.ReadByte();
HoldEffectParam = reader.ReadByte();
PluckEffect = reader.ReadByte();
FlingEffect = reader.ReadByte();
FlingPower = reader.ReadByte();
NaturalGiftPower = reader.ReadByte();
ushort bitfield = reader.ReadUInt16();
naturalGiftType = (NaturalGiftType)(bitfield & 0b0001_1111);
PreventToss = (bitfield & (1 << 5)) != 0;
Selectable = (bitfield & (1 << 6)) != 0;
fieldPocket = (FieldPocket)((bitfield >> 7) & 0b1111);
battlePocket = (BattlePocket)((bitfield >> 11) & 0b11111);
fieldUseFunc = (FieldUseFunc)reader.ReadByte();
battleUseFunc = (BattleUseFunc)reader.ReadByte();
PartyUse = reader.ReadByte();
reader.ReadByte(); // skip 1 byte padding_0D
PartyUseParam = new ItemPartyUseParam(reader);
reader.ReadBytes(2); // skip padding_22
}
}
public ItemData(int ID) : this(new FileStream(RomInfo.gameDirs[DirNames.itemData].unpackedDir + "\\" + ID.ToString("D4"), FileMode.Open)) { }
public override byte[] ToByteArray()
{
using (MemoryStream stream = new MemoryStream())
using (BinaryWriter writer = new BinaryWriter(stream))
{
writer.Write(price);
writer.Write((byte)holdEffect);
writer.Write(HoldEffectParam);
writer.Write(PluckEffect);
writer.Write(FlingEffect);
writer.Write(FlingPower);
writer.Write(NaturalGiftPower);
ushort bitfield = 0;
bitfield |= (ushort)((byte)naturalGiftType & 0b11111);
if (PreventToss) bitfield |= (1 << 5);
if (Selectable) bitfield |= (1 << 6);
bitfield |= (ushort)(((byte)fieldPocket & 0b1111) << 7);
bitfield |= (ushort)(((byte)battlePocket & 0b11111) << 11);
writer.Write(bitfield);
writer.Write((byte)fieldUseFunc);
writer.Write((byte)battleUseFunc);
writer.Write(PartyUse);
writer.Write((byte)0); // padding
PartyUseParam.WriteTo(writer);
writer.Write(new byte[2]); // padding
return stream.ToArray();
}
}
public void SaveToFileDefaultDir(int IDtoReplace, bool showSuccessMessage = true)
{
SaveToFileDefaultDir(DirNames.itemData, IDtoReplace, showSuccessMessage);
}
public void SaveToFileExplorePath(string suggestedFileName, bool showSuccessMessage = true)
{
SaveToFileExplorePath("Gen IV Item data", "bin", suggestedFileName, showSuccessMessage);
}
public class ItemPartyUseParam
{
// Flags (bit-packed)
public bool SlpHeal, PsnHeal, BrnHeal, FrzHeal, PrzHeal, CfsHeal, InfHeal;
public bool GuardSpec;
public bool Revive, ReviveAll, LevelUp, Evolve;
public sbyte AtkStages, DefStages, SpAtkStages, SpDefStages, SpeedStages, AccuracyStages, CritRateStages;
public bool PPUps, PPMax, PPRestore, PPRestoreAll, HPRestore;
public bool[] EVUps = new bool[6]; // hp, atk, def, speed, spatk, spdef
public bool[] FriendshipMods = new bool[3]; // lo, med, hi
public sbyte[] EVParams = new sbyte[6]; // hp, atk, def, speed, spatk, spdef
public byte HPRestoreParam;
public byte PPRestoreParam;
public sbyte[] FriendshipParams = new sbyte[3]; // lo, med, hi
public ItemPartyUseParam(BinaryReader reader)
{
byte[] data = reader.ReadBytes(19);
// Byte 0: HealStatus1
byte healStatus1 = data[0];
SlpHeal = (healStatus1 & (1 << 0)) != 0;
PsnHeal = (healStatus1 & (1 << 1)) != 0;
BrnHeal = (healStatus1 & (1 << 2)) != 0;
FrzHeal = (healStatus1 & (1 << 3)) != 0;
PrzHeal = (healStatus1 & (1 << 4)) != 0;
CfsHeal = (healStatus1 & (1 << 5)) != 0;
InfHeal = (healStatus1 & (1 << 6)) != 0;
GuardSpec = (healStatus1 & (1 << 7)) != 0;
// Byte 1: revive, revive_all, level_up, evolve
byte flags1 = data[1];
Revive = (flags1 & (1 << 0)) != 0;
ReviveAll = (flags1 & (1 << 1)) != 0;
LevelUp = (flags1 & (1 << 2)) != 0;
Evolve = (flags1 & (1 << 3)) != 0;
// Byte 2: atk + def stages (stored 015, mapped to -6 to +6 if needed)
AtkStages = DecodeStage(data[2] & 0x0F);
DefStages = DecodeStage((data[2] >> 4) & 0x0F);
// Byte 3: spatk + spdef
SpAtkStages = DecodeStage(data[3] & 0x0F);
SpDefStages = DecodeStage((data[3] >> 4) & 0x0F);
// Byte 4: speed + accuracy
SpeedStages = DecodeStage(data[4] & 0x0F);
AccuracyStages = DecodeStage((data[4] >> 4) & 0x0F);
// Byte 5: crit rate (2 bits), pp/hp restore flags
byte flags2 = data[5];
CritRateStages = (sbyte)(flags2 & 0x03); // 03
PPUps = (flags2 & (1 << 2)) != 0;
PPMax = (flags2 & (1 << 3)) != 0;
PPRestore = (flags2 & (1 << 4)) != 0;
PPRestoreAll = (flags2 & (1 << 5)) != 0;
HPRestore = (flags2 & (1 << 6)) != 0;
// Byte 6: EV flags
byte evFlags = data[6];
for (int i = 0; i < 6; i++)
EVUps[i] = (evFlags & (1 << i)) != 0;
// Byte 7: friendship flags
byte friendFlags = data[7];
for (int i = 0; i < 3; i++)
FriendshipMods[i] = (friendFlags & (1 << i)) != 0;
// Bytes 813: EVParams (signed)
for (int i = 0; i < 6; i++)
EVParams[i] = (sbyte)data[8 + i];
// Byte 14: HP restore param (0255)
HPRestoreParam = data[14];
// Byte 15: PP restore param (0255)
PPRestoreParam = data[15];
// Bytes 1618: friendship params (signed)
for (int i = 0; i < 3; i++)
FriendshipParams[i] = (sbyte)data[16 + i];
// Skip padding in binary reader (2 bytes expected)
reader.BaseStream.Seek(2, SeekOrigin.Current);
}
public void WriteTo(BinaryWriter writer)
{
byte[] data = new byte[19];
// Byte 0: HealStatus1
data[0] = 0;
if (SlpHeal) data[0] |= (1 << 0);
if (PsnHeal) data[0] |= (1 << 1);
if (BrnHeal) data[0] |= (1 << 2);
if (FrzHeal) data[0] |= (1 << 3);
if (PrzHeal) data[0] |= (1 << 4);
if (CfsHeal) data[0] |= (1 << 5);
if (InfHeal) data[0] |= (1 << 6);
if (GuardSpec) data[0] |= (1 << 7);
// Byte 1: revive, revive_all, level_up, evolve
data[1] = 0;
if (Revive) data[1] |= (1 << 0);
if (ReviveAll) data[1] |= (1 << 1);
if (LevelUp) data[1] |= (1 << 2);
if (Evolve) data[1] |= (1 << 3);
// Byte 2: atk + def stages
data[2] = (byte)((EncodeStage(DefStages) << 4) | EncodeStage(AtkStages));
// Byte 3: spatk + spdef
data[3] = (byte)((EncodeStage(SpDefStages) << 4) | EncodeStage(SpAtkStages));
// Byte 4: speed + accuracy
data[4] = (byte)((EncodeStage(AccuracyStages) << 4) | EncodeStage(SpeedStages));
// Byte 5: crit rate + flags
data[5] = (byte)(CritRateStages & 0x03);
if (PPUps) data[5] |= (1 << 2);
if (PPMax) data[5] |= (1 << 3);
if (PPRestore) data[5] |= (1 << 4);
if (PPRestoreAll) data[5] |= (1 << 5);
if (HPRestore) data[5] |= (1 << 6);
// Byte 6: EV flags
for (int i = 0; i < 6; i++)
if (EVUps[i]) data[6] |= (byte)(1 << i);
// Byte 7: friendship flags
for (int i = 0; i < 3; i++)
if (FriendshipMods[i]) data[7] |= (byte)(1 << i);
// Bytes 813: EVParams
for (int i = 0; i < 6; i++)
data[8 + i] = (byte)EVParams[i];
// Byte 14: HPRestoreParam
data[14] = HPRestoreParam;
// Byte 15: PPRestoreParam
data[15] = PPRestoreParam;
// Bytes 1618: FriendshipParams
for (int i = 0; i < 3; i++)
data[16 + i] = (byte)FriendshipParams[i];
// Write struct + padding
writer.Write(data);
writer.Write(new byte[2]);
}
// Replace the problematic line with the following implementation of Clamp:
private static byte EncodeStage(sbyte val) => (byte)((val + 6 < 0) ? 0 : (val + 6 > 15) ? 15 : val + 6);
// Decodes 0 to 15 to -6 to +9 range (limited logic for now)
private static sbyte DecodeStage(int val) => (sbyte)(val - 6);
}
}
}