JPEXS Modding Guide - Advanced

Extend Spinner Shop with Custom Spinners [Expert]

Prereqs: Everything. Don’t try this at home.

This guide is split into parts rather than steps due to complexity.

Part 1: Setup & Understanding

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();

Part 2: Purchase Logic

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);
}

Part 3: Spinner Rendering

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(...);
}

Part 4: Sprite Searching

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.

Part 5: Preparing Slot for New Spinner

In scripts/frame1.DoAction.as, set maxShopSpinners = 55 or higher.

This reserves slot 55 for your custom spinner.

Part 6: Renaming the Sprite

In JPEXS, search indicatorMC83. Use DefineSprite (6803: indicatorMC83).

To rename it to indicatorMC55, continue to next step (ExportAssets).

Part 7: Change ExportAssets Reference

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.

Part 8: Add Spinner Text and Cost

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);

Part 9: Restore or Repurpose the Original Spinner

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.