Add Colorful Screw collector button-cheat

Trainer editor, press button to have them auto-collected to inventory.
Some modifiers available for those wanting to reset all or get a list of all for manual hunting :)
This commit is contained in:
Kurt 2025-10-31 20:39:50 -05:00
parent d047f02410
commit 7013250688
3 changed files with 243 additions and 0 deletions

View File

@ -0,0 +1,209 @@
using System.Collections.Generic;
namespace PKHeX.Core;
/// <summary>
/// Provides functionality for managing and interacting with "Colorful Screws" in the game.
/// </summary>
/// <remarks>This class includes methods for collecting screws, updating inventory, and retrieving the locations
/// of screws. It operates on the provided save data and event work flag storage to manage the state of
/// screws.</remarks>
public static class ColorfulScrew9a
{
public const ushort ColorfulScrewItemIndex = 2619;
/// <summary>
/// Collects screws from the specified save data and updates the player's inventory with the collected count.
/// </summary>
/// <returns>The number of screws collected. Returns 0 if no screws were found.</returns>
public static int CollectScrews(SAV9ZA sav)
{
// Collect Screws
var block = sav.Blocks.FieldItems;
var count = CollectScrews(block);
if (count == 0)
return count;
// Update Inventory with updated quantity.
var items = sav.Items;
var exist = items.GetItemQuantity(ColorfulScrewItemIndex);
var update = (ushort)(exist + count);
if (update > 100)
update = 100; // Why did the player cheat in extra quantity? Just be safe.
items.SetItemQuantity(ColorfulScrewItemIndex, update);
return count;
}
private static int CollectScrews(EventWorkFlagStorage block)
{
// "Collect" the screw by marking the overworld item-ball spawner as inactive (hidden = true).
int count = 0;
foreach (var screw in ColorfulScrews)
{
var hash = FnvHash.HashFnv1a_64(screw.FieldItem);
var index = block.GetIndex(hash);
if (index == -1)
continue; // Shouldn't happen. All screws should be populated in a save file.
var value = block.GetValue(index);
if (value)
continue; // Already collected.
block.SetValue(index, true);
count++;
}
// Return the count of screws collected, that should be added to the player's inventory.
return count;
}
/// <inheritdoc cref="GetScrewLocations(EventWorkFlagStorage, bool)"/>
public static IEnumerable<(string FieldItem, (float X, float Y, float Z) Point)> GetScrewLocations(SAV9ZA sav, bool state) =>
GetScrewLocations(sav.Blocks.FieldItems, state);
/// <summary>
/// Retrieves the locations of screws that match the specified state.
/// </summary>
/// <param name="block">The storage block containing screw data and their associated states.</param>
/// <param name="state">The state to filter screws by. Only screws with this state will be included.</param>
public static IEnumerable<(string FieldItem, (float X, float Y, float Z) Point)> GetScrewLocations(EventWorkFlagStorage block, bool state = false)
{
foreach (var screw in ColorfulScrews)
{
var hash = FnvHash.HashFnv1a_64(screw.FieldItem);
var index = block.GetIndex(hash);
if (index == -1)
continue; // Shouldn't happen. All screws should be populated in a save file.
var value = block.GetValue(index);
if (value != state)
continue;
yield return screw;
}
}
/// <summary>
/// Locations of all Colorful Screws in the game.
/// </summary>
private static readonly (string FieldItem, (float X, float Y, float Z) Point)[] ColorfulScrews =
[
// 99 screws outside.
("itb_a0101_25", (-611.7629f ,0.2509685f ,-594.8188f)),
("itb_a0101_81", (-912.0365f ,9.002547f ,-750.05414f)),
("itb_a0101_83", (-846.563f ,4.1388083f ,-811.1325f)),
("itb_a0101_84", (-848.9131f ,12.781971f ,-737.83496f)),
("itb_a0101_89", (-681.5279f ,17.51269f ,-591.0863f)),
("itb_a0101_94", (-619.4882f ,9.134821f ,-554.0143f)),
("itb_a0101_97", (-687.6974f ,18.378315f ,-627.687f)),
("itb_a0101_99", (-575.8895f ,4.3793745f ,-552.3689f)),
("itb_a0101_101", (-751.99054f ,5.4620757f ,-732.8448f)),
("itb_a0101_103", (-921.3577f ,11.460509f ,-677.5147f)),
("itb_a0101_105", (-823.5497f ,17.546358f ,-783.28516f)),
("itb_a0101_106", (-710.679f ,27.860916f ,-843.5154f)),
("itb_a0101_114", (-734.02185f ,23.055899f ,-713.5946f)),
("itb_a0102_40", (-487.75266f ,6.8545384f ,-947.9376f)),
("itb_a0102_87", (-535.5792f ,20.537054f ,-730.7836f)),
("itb_a0102_108", (-612.5779f ,6.74156f ,-840.2996f)),
("itb_a0102_117", (-613.5178f ,7.555528f ,-759.1486f)),
("itb_a0102_120", (-574.815f ,18.27181f ,-826.5897f)),
("itb_a0102_122", (-554.20825f ,12.109058f ,-731.9376f)),
("itb_a0102_128", (-546.3892f ,3.1391847f ,-755.3944f)),
("itb_a0102_130", (-560.5767f ,14.321938f ,-679.1879f)),
("itb_a0102_131", (-687.17236f ,4.5935855f ,-831.19507f)),
("itb_a0201_58", (-366.6956f ,15.044577f ,-831.9763f)),
("itb_a0201_61", (-406.0901f ,11.309174f ,-975.0717f)),
("itb_a0201_64", (-356.07993f ,8.858809f ,-902.7882f)),
("itb_a0201_67", (-323.23798f ,12.752846f ,-773.8171f)),
("itb_a0201_70", (-334.69022f ,19.0464f ,-754.7411f)),
("itb_a0201_73", (-481.9776f ,7.3682528f ,-690.87823f)),
("itb_a0201_75", (-431.6641f ,10.888694f ,-756.9131f)),
("itb_a0201_78", (-484.75323f ,17.47603f ,-923.1219f)),
("itb_a0201_79", (-311.2337f ,18.81803f ,-785.0195f)),
("itb_a0201_80", (-404.22302f ,4.299103f ,-976.53735f)),
("itb_a0201_81", (-331.591f ,17.176617f ,-910.36633f)),
("itb_a0202_51", (-298.79434f ,18.605236f ,-643.80164f)),
("itb_a0202_89", (-113.88871f ,12.77f ,-797.11523f)),
("itb_a0202_94", (-45.78526f ,0.14146906f ,-674.23206f)),
("itb_a0202_96", (-302.68326f ,21.765139f ,-744.53894f)),
("itb_a0202_99", (-190.47188f ,3.3071632f ,-706.84216f)),
("itb_a0202_104", (-188.0446f ,10.365694f ,-705.0904f)),
("itb_a0301_12", (-133.65852f ,9.468117f ,-557.42645f)),
("itb_a0301_85", (-22.70829f ,5.66999f ,-422.1258f)),
("itb_a0301_87", (-55.555252f ,15.3061905f ,-501.03577f)),
("itb_a0301_90", (-390.6782f ,4.24647f ,-525.0898f)),
("itb_a0301_93", (-139.23645f ,14.698685f ,-433.89874f)),
("itb_a0301_96", (-139.34392f ,2.9998174f ,-430.98022f)),
("itb_a0301_101", (-212.95015f ,0.16039793f ,-447.62796f)),
("itb_a0301_102", (-55.400597f ,6.0117397f ,-501.29865f)),
("itb_a0301_106", (-111.60038f ,30.824907f ,-529.86273f)),
("itb_a0302_101", (-153.0837f ,24.55992f ,-206.02f)),
("itb_a0302_81", (-124.19311f ,12.239148f ,-215.39864f)),
("itb_a0302_87", (-107.24101f ,13.461311f ,-218.01112f)),
("itb_a0302_92", (-113.791084f ,1.5038356f ,-324.2796f)),
("itb_a0302_94", (-400.23975f ,9.024075f ,-407.45197f)),
("itb_a0302_96", (-180.98009f ,25.06243f ,-191.85275f)),
("itb_a0302_104", (-174.84079f ,15.428678f ,-321.31717f)),
("itb_a0401_17", (-453.57413f ,17.11317f ,-213.88242f)),
("itb_a0401_29", (-362.32007f ,13.29676f ,-162.73178f)),
("itb_a0401_31", (-314.40524f ,26.549751f ,-164.79158f)),
("itb_a0401_63", (-316.57678f ,23.494171f ,-220.47177f)),
("itb_a0401_71", (-347.9144f ,19.847963f ,-74.24183f)),
("itb_a0401_75", (-267.1446f ,7.992974f ,-78.38538f)),
("itb_a0401_77", (-258.93777f ,12.331233f ,-81.74573f)),
("itb_a0401_79", (-485.23636f ,3.8256838f ,-108.836044f)),
("itb_a0401_80", (-382.20947f ,11.210755f ,-306.4857f)),
("itb_a0401_83", (-388.05774f ,12.896254f ,-287.38943f)),
("itb_a0401_85", (-447.53406f ,13.137535f ,-324.10864f)),
("itb_a0401_88", (-460.5163f ,2.1669445f ,-340.6761f)),
("itb_a0401_91", (-419.12234f ,3.9772782f ,-111.23066f)),
("itb_a0401_93", (-476.40057f ,19.878263f ,-119.772644f)),
("itb_a0401_96", (-394.24576f ,23.499132f ,-279.23523f)),
("itb_a0402_68", (-588.6553f ,8.951744f ,-333.55008f)),
("itb_a0402_72", (-722.8337f ,8.128692f ,-172.50806f)),
("itb_a0402_74", (-666.81683f ,14.745333f ,-131.40936f)),
("itb_a0402_77", (-671.4622f ,7.892555f ,-104.47086f)),
("itb_a0402_81", (-572.95905f ,11.094018f ,-22.257357f)),
("itb_a0402_85", (-550.1979f ,7.9077163f ,-21.212116f)),
("itb_a0402_90", (-609.4243f ,25.186445f ,-51.041454f)),
("itb_a0402_91", (-608.473f ,5.526315f ,-273.13983f)),
("itb_a0402_92", (-666.3514f ,3.4637678f ,-115.272934f)),
("itb_a0402_97", (-637.05756f ,14.554916f ,-233.7284f)),
("itb_a0501_77", (-915.48694f ,15.225559f ,-293.09912f)),
("itb_a0501_81", (-663.87964f ,9.650265f ,-294.52002f)),
("itb_a0501_84", (-629.3896f ,20.765638f ,-396.69833f)),
("itb_a0501_87", (-891.1155f ,15.639636f ,-270.57614f)),
("itb_a0501_91", (-742.5943f ,3.4883833f ,-273.4928f)),
("itb_a0501_99", (-791.7427f ,26.136696f ,-315.88742f)),
("itb_a0501_100", (-661.34973f ,25.947884f ,-397.19485f)),
("itb_a0501_102", (-710.76935f ,6.968615f ,-351.74802f)),
("itb_a0501_103", (-611.01355f ,28.322855f ,-369.91714f)),
("itb_a0501_104", (-851.59247f ,22.666864f ,-211.58481f)),
("itb_a0502_87", (-762.0602f ,15.46941f ,-495.2859f)),
("itb_a0502_89", (-862.32495f ,32.34224f ,-456.9059f)),
("itb_a0502_95", (-853.2598f ,25.766558f ,-493.55304f)),
("itb_a0502_96", (-647.7033f ,3.0009127f ,-473.63446f)),
("itb_a0502_97", (-934.56256f ,22.475294f ,-444.34705f)),
("itb_a0502_98", (-800.14276f ,20.435688f ,-561.7759f)),
("itb_a0502_109", (-833.0822f ,29.57602f ,-451.5477f)),
("itb_a0502_110", (-683.0301f ,26.340189f ,-482.3554f)),
("itb_a0502_111", (-923.0192f ,23.67176f ,-419.16327f)),
// 100th screw is indoors.
("itb_t1_i011_01", (-1.736374f ,0.036360174f ,-10.29498f)),
];
/// <summary>
/// Utility function to set all screws to collected or uncollected state.
/// </summary>
public static void SetAllScrews(SAV9ZA sav, bool collected = false)
{
foreach (var screw in ColorfulScrews)
{
var hash = FnvHash.HashFnv1a_64(screw.FieldItem);
var index = sav.Blocks.FieldItems.GetIndex(hash);
if (index == -1)
continue; // Shouldn't happen. All screws should be populated in a save file.
sav.Blocks.FieldItems.SetValue(index, collected);
}
}
}

View File

@ -118,6 +118,7 @@ private void InitializeComponent()
P_Picture1 = new System.Windows.Forms.PictureBox();
P_Picture2 = new System.Windows.Forms.PictureBox();
P_Picture3 = new System.Windows.Forms.PictureBox();
B_CollectScrews = new System.Windows.Forms.Button();
TC_Editor.SuspendLayout();
Tab_Overview.SuspendLayout();
Tab_MiscValues.SuspendLayout();
@ -699,6 +700,7 @@ private void InitializeComponent()
//
// Tab_MiscValues
//
Tab_MiscValues.Controls.Add(B_CollectScrews);
Tab_MiscValues.Controls.Add(label3);
Tab_MiscValues.Controls.Add(L_RoyaleTicketPointsInfinite);
Tab_MiscValues.Controls.Add(L_RoyaleRegularTicketPoints);
@ -982,6 +984,16 @@ private void InitializeComponent()
P_Picture3.TabStop = false;
P_Picture3.Click += P_Picture3_Click;
//
// B_CollectScrews
//
B_CollectScrews.Location = new System.Drawing.Point(365, 106);
B_CollectScrews.Name = "B_CollectScrews";
B_CollectScrews.Size = new System.Drawing.Size(120, 64);
B_CollectScrews.TabIndex = 85;
B_CollectScrews.Text = "Collect All Colorful Screws";
B_CollectScrews.UseVisualStyleBackColor = true;
B_CollectScrews.Click += B_CollectScrews_Click;
//
// SAV_Trainer9a
//
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
@ -1107,5 +1119,6 @@ private void InitializeComponent()
private System.Windows.Forms.PictureBox P_Picture1;
private System.Windows.Forms.PictureBox P_Picture2;
private System.Windows.Forms.PictureBox P_Picture3;
private System.Windows.Forms.Button B_CollectScrews;
}
}

View File

@ -200,4 +200,25 @@ private void Change255(object sender, EventArgs e)
private void P_Picture1_Click(object sender, EventArgs e) => SAV_Trainer9.IMG_Save(P_Picture1.Image!, nameof(KPictureSBCData));
private void P_Picture2_Click(object sender, EventArgs e) => SAV_Trainer9.IMG_Save(P_Picture2.Image!, nameof(KPictureInitialData));
private void P_Picture3_Click(object sender, EventArgs e) => SAV_Trainer9.IMG_Save(P_Picture3.Image!, nameof(KPictureCurrentData));
private void B_CollectScrews_Click(object sender, EventArgs e)
{
var itemName = GameInfo.Strings.Item[ColorfulScrew9a.ColorfulScrewItemIndex];
// For those who wish to do it manually in-game with the assistance of a Map/list.
if (ModifierKeys == Keys.Alt)
{
var uncollected = ColorfulScrew9a.GetScrewLocations(SAV.Blocks.FieldItems);
var msg = string.Join(Environment.NewLine, uncollected.Select(s => $"{s.FieldItem} at ({s.Point.X}, {s.Point.Y}, {s.Point.Z})"));
Clipboard.SetText(msg);
WinFormsUtil.Alert($"Uncollected {itemName} locations copied to clipboard.");
return;
}
var count = ColorfulScrew9a.CollectScrews(SAV);
if (count == 0)
WinFormsUtil.Alert($"No {itemName} available to collect.");
else
WinFormsUtil.Alert($"Collected {count} {itemName}!");
}
}