Prereqs: Everything. Don’t try this at home.
This guide is split into parts rather than steps due to complexity.
Export the /scripts folder and open it in VSCode for better searchability.
Search for maxShopSpinners, initially set to 41 (around line 8424). Avoid arbitrarily high values like 99.
In /scripts/frame5.DoAction.as, locate this logic:
spinnersMC.gotoAndStop("shop");
var i = 0;
while(i < maxShopSpinners) {
// ...
}
Also note:
eval("spinnersMC.subSpinnersMC.indicatorMC" + selectedShopSpinner).play();
Relevant code in frame5.DoAction.as:
function validatePurchaseClientSide(purchaseCost) {
if(Number(player.zqkPmT) >= purchaseCost) {
shopPurchaseCost = purchaseCost;
displayShopMessage("\r" + shopText[20] + purchaseCost.toString() + shopText[21], "window304ShopConfirmMessageMC", true);
return true;
}
displayShopMessage(shopText[31], "window304ShopNotEnoughCredMessageMC", true);
return false;
}
function performShopPurchase() {
if(shopPurchaseType == _shopSpinnerType) {
player.spinners[player.spinners.length] = {num:selectedShopSpinner, red0:cR[0], green0:cG[0], blue0:cB[0], red1:cR[1], green1:cG[1], blue1:cB[1]};
player.sendBuyItem(100 + selectedShopSpinner, cR[0], cG[0], cB[0], cR[1], cG[1], cB[1]);
} else if(shopPurchaseType == _shopPetType) {
player.pets[player.pets.length] = {num:selectedShopPet + 1, red0:cR[0], green0:cG[0], blue0:cB[0], red1:cR[1], green1:cG[1], blue1:cB[1]};
player.sendBuyItem(200 + selectedShopPet + 1, cR[0], cG[0], cB[0], cR[1], cG[1], cB[1]);
} else if(shopPurchaseType == _shopMapSlotType) {
player.jhJkpo = Number(player.jhJkpo) + 1;
updateMapSlotsShop();
player.sendBuyItem(240, 0, 0, 0, 0, 0, 0);
}
player.zqkPmT = Number(player.zqkPmT) - shopPurchaseCost;
credText0.text = credText1.text = formatNumber(player.zqkPmT);
displayShopMessage(purchaseSuccessMessage, "window304ShopMessageMC", true);
}
function updateLocalPlayerSpinnerAndPet() {
var _loc2_ = player.spinners[player.jhHtWQ];
fqTEcOL.attachMovie("indicatorMC" + padStr(_loc2_.num, 2), "charIndicatorMC", 1555);
setCustomObject2Colors(...);
var _loc1_ = player.pets[player.vwEGyv];
gxyAWm.attachMovie("petBehavior" + petBehavior[Number(_loc1_.num)] + "MC", "charPetMC", 7777);
var _loc3_ = gxyAWm.charPetMC.subPetMC.attachMovie("petMC" + padStr(_loc1_.num, 2), "petMC", 1, {_x:70,_y:-80});
_loc3_._xscale = _loc3_._yscale = petScale;
setCustomObject2Colors(...);
}
Search indicatorMC in JPEXS. For example: indicatorMC81 is Builder.
Find last purchasable spinner ID (e.g., 51), and choose next (e.g., 52).
To make spinners like indicatorMC83 (Moderator) purchasable, change their ID to match an available slot.
In scripts/frame1.DoAction.as, set maxShopSpinners = 55 or higher.
This reserves slot 55 for your custom spinner.
In JPEXS, search indicatorMC83. Use DefineSprite (6803: indicatorMC83).
To rename it to indicatorMC55, continue to next step (ExportAssets).
In others/ExportAssets, find the one pointing to indicatorMC83.
Edit it → click the plus → double click indicatorMC83 → rename to indicatorMC55 → save.
Now the sprite will be labeled correctly as indicatorMC55.
In settings558b.ini, add: &sSpinnerText55=Moderator&
In upgradevalues558b.ini, add: &sSpinnerCost55=1000&
Insert into database via phpMyAdmin:
INSERT INTO stick_arena (id, itemID, cost)
VALUES (replaceThisWithAnActualId, 155, 1000);
To keep both the original and the modified spinner, retrieve indicatorMC83 from another SWF.
Slot 55 can now serve as a placeholder for custom spinner experimentation.