User prompt
Make font colors white
User prompt
After rolling, print the name of the item and the chance rate on the screen.
User prompt
Change the item names to Water, Stone, Flame, Breeze and Amber
User prompt
Change "Blue Box" name a "Water"
User prompt
Please fix the bug: 'Uncaught RangeError: Maximum call stack size exceeded' in or related to this line: 'rollBtn.down(x, y, obj);' Line Number: 358
Code edit (1 edits merged)
Please save this source code
User prompt
Loot of Odds: The RNG Collection
Initial prompt
: I want to create a random loot-based RNG game. The game contains a growing list of unique items, each with a specific rarity. Rarities are defined as 1 in X chances (e.g., 1/2, 1/4, 1/1000, etc.), and the odds vary non-linearly. Some rarities are close, while others have large gaps. The items are labeled with fitting names that reflect their rarity (e.g., "Water" is common, while "Eternity" is extremely rare). There are currently 50 items, each with a rarity value. More items will be added in the future, either between existing items or at the end. When a new item is added between two existing ones, the others are pushed down but their internal numbers remain stable (i.e., item #23 stays #23 even if a new item is inserted before it and becomes #24). The rarity values are not always neat powers of two or rounded numbers; some values are arbitrary like 1/384000 or 1/12999999 to make the system feel more organic. I want you to simulate or help code this system. The structure should allow: Random rolls that select items based on their defined rarity Easy insertion of new items without breaking existing IDs or logic Optional: output of the rolled item and its rarity
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
collection: []
});
/****
* Classes
****/
// Collection item icon (for collection view)
var CollectionIcon = Container.expand(function () {
var self = Container.call(this);
self.asset = null;
self.overlayText = null;
self.setItem = function (itemDef, owned) {
if (self.asset) {
self.removeChild(self.asset);
self.asset = null;
}
if (self.overlayText) {
self.removeChild(self.overlayText);
self.overlayText = null;
}
self.asset = self.attachAsset(itemDef.asset, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.5
});
if (itemDef.rotation) self.asset.rotation = itemDef.rotation;
if (itemDef.overlay) {
self.overlayText = new Text2(itemDef.overlay, {
size: 60,
fill: "#fff"
});
self.overlayText.anchor.set(0.5, 0.5);
self.addChild(self.overlayText);
}
// If not owned, gray out
if (!owned) self.asset.alpha = 0.25;else self.asset.alpha = 1;
};
return self;
});
// Item display class
var ItemDisplay = Container.expand(function () {
var self = Container.call(this);
self.asset = null;
self.overlayText = null;
self.setItem = function (itemDef) {
// Remove previous
if (self.asset) {
self.removeChild(self.asset);
self.asset = null;
}
if (self.overlayText) {
self.removeChild(self.overlayText);
self.overlayText = null;
}
// Add shape
self.asset = self.attachAsset(itemDef.asset, {
anchorX: 0.5,
anchorY: 0.5
});
if (itemDef.rotation) self.asset.rotation = itemDef.rotation;
// Overlay text if needed
if (itemDef.overlay) {
self.overlayText = new Text2(itemDef.overlay, {
size: 120,
fill: "#fff"
});
self.overlayText.anchor.set(0.5, 0.5);
self.addChild(self.overlayText);
}
};
return self;
});
// Roll button class
var RollButton = Container.expand(function () {
var self = Container.call(this);
self.bg = self.attachAsset('roll_btn', {
anchorX: 0.5,
anchorY: 0.5
});
self.label = new Text2("ROLL", {
size: 70,
fill: "#fff"
});
self.label.anchor.set(0.5, 0.5);
self.addChild(self.label);
// Simple press effect
self.down = function (x, y, obj) {
tween(self.bg, {
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 80,
easing: tween.cubicIn
});
};
self.up = function (x, y, obj) {
tween(self.bg, {
scaleX: 1,
scaleY: 1
}, {
duration: 80,
easing: tween.cubicOut
});
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x181818
});
/****
* Game Code
****/
// --- State ---
/*
We will use simple shapes for items (boxes, ellipses) and a "roll" button.
Each item will have a unique color and shape for visual distinction.
*/
// We'll rotate this to look like a triangle
// We'll overlay text for "star"
// We'll overlay text for "hex"
// Item definitions: id, name, rarity (1 in X), asset, extra (for shape/rotation/text)
var ITEM_DEFS = [{
id: 0,
name: "Water",
rarity: 2,
asset: 'item_box'
}, {
id: 1,
name: "Stone",
rarity: 3,
asset: 'item_ellipse'
}, {
id: 2,
name: "Flame",
rarity: 7,
asset: 'item_triangle',
rotation: Math.PI / 4
}, {
id: 3,
name: "Breeze",
rarity: 20,
asset: 'item_star',
overlay: "★"
}, {
id: 4,
name: "Amber",
rarity: 50,
asset: 'item_hex',
overlay: "⬡"
}];
// Helper: get item by id
function getItemDef(id) {
for (var i = 0; i < ITEM_DEFS.length; ++i) {
if (ITEM_DEFS[i].id === id) return ITEM_DEFS[i];
}
return null;
}
var collection = storage.collection || []; // array of owned item ids
var lastRollResult = null; // id of last rolled item
var rolling = false; // is animation running
var showCollection = false;
// --- UI Elements ---
// Title
var titleTxt = new Text2("Loot Roll", {
size: 120,
fill: "#fff"
});
titleTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(titleTxt);
// Rarity info
var rarityTxt = new Text2("", {
size: 60,
fill: "#fff"
});
rarityTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(rarityTxt);
// Main item display
var itemDisplay = new ItemDisplay();
itemDisplay.x = 2048 / 2;
itemDisplay.y = 900;
game.addChild(itemDisplay);
// Roll button
var rollBtn = new RollButton();
rollBtn.x = 2048 / 2;
rollBtn.y = 1800;
game.addChild(rollBtn);
// "Show Collection" button
var showCollBtn = new Container();
var showCollBg = showCollBtn.attachAsset('roll_btn', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.7,
scaleY: 0.7
});
var showCollLabel = new Text2("COLLECTION", {
size: 48,
fill: "#fff"
});
showCollLabel.anchor.set(0.5, 0.5);
showCollBtn.addChild(showCollLabel);
showCollBtn.x = 2048 / 2;
showCollBtn.y = 2050;
game.addChild(showCollBtn);
// Collection view overlay
var collectionOverlay = new Container();
collectionOverlay.visible = false;
game.addChild(collectionOverlay);
// "Back" button for collection
var backBtn = new Container();
var backBg = backBtn.attachAsset('roll_btn', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.5
});
var backLabel = new Text2("BACK", {
size: 48,
fill: "#fff"
});
backLabel.anchor.set(0.5, 0.5);
backBtn.addChild(backLabel);
backBtn.x = 2048 / 2;
backBtn.y = 2500;
collectionOverlay.addChild(backBtn);
// Collection grid
var collectionIcons = [];
function updateCollectionGrid() {
// Remove old
for (var i = 0; i < collectionIcons.length; ++i) collectionOverlay.removeChild(collectionIcons[i]);
collectionIcons = [];
// Layout: 3 per row, centered
var perRow = 3;
var spacing = 320;
var startX = 2048 / 2 - spacing;
var startY = 600;
for (var i = 0; i < ITEM_DEFS.length; ++i) {
var item = ITEM_DEFS[i];
var owned = collection.indexOf(item.id) !== -1;
var icon = new CollectionIcon();
icon.setItem(item, owned);
icon.x = startX + i % perRow * spacing;
icon.y = startY + Math.floor(i / perRow) * spacing;
// Name and rarity
var nameTxt = new Text2(item.name, {
size: 36,
fill: "#fff"
});
nameTxt.anchor.set(0.5, 0);
nameTxt.x = 0;
nameTxt.y = 90;
icon.addChild(nameTxt);
var rareTxt = new Text2("1 in " + item.rarity, {
size: 28,
fill: "#aaa"
});
rareTxt.anchor.set(0.5, 0);
rareTxt.x = 0;
rareTxt.y = 130;
icon.addChild(rareTxt);
collectionOverlay.addChild(icon);
collectionIcons.push(icon);
}
}
// --- Functions ---
function updateMainDisplay() {
// Show last rolled item or first item
var itemId = lastRollResult !== null ? lastRollResult : 0;
var itemDef = getItemDef(itemId);
itemDisplay.setItem(itemDef);
// Show name and rarity
rarityTxt.setText(itemDef.name + " • 1 in " + itemDef.rarity);
}
function rollForItem() {
// Weighted random roll
var totalWeight = 0;
for (var i = 0; i < ITEM_DEFS.length; ++i) {
totalWeight += 1 / ITEM_DEFS[i].rarity;
}
var r = Math.random() * totalWeight;
var acc = 0;
for (var i = 0; i < ITEM_DEFS.length; ++i) {
acc += 1 / ITEM_DEFS[i].rarity;
if (r <= acc) return ITEM_DEFS[i].id;
}
return ITEM_DEFS[ITEM_DEFS.length - 1].id;
}
function animateRoll(resultId) {
rolling = true;
// Flash through random items, then land on result
var flashes = 12;
var flashTime = 60;
var i = 0;
function flashNext() {
if (i < flashes) {
var fakeId = Math.floor(Math.random() * ITEM_DEFS.length);
itemDisplay.setItem(getItemDef(fakeId));
++i;
LK.setTimeout(flashNext, flashTime);
} else {
// Land on result
itemDisplay.setItem(getItemDef(resultId));
// Animate scale
itemDisplay.scale.set(1.2, 1.2);
tween(itemDisplay, {
scaleX: 1,
scaleY: 1
}, {
duration: 200,
easing: tween.bounceOut
});
rolling = false;
// Show rolled item name and chance rate
var rolledItem = getItemDef(resultId);
rarityTxt.setText(rolledItem.name + " • 1 in " + rolledItem.rarity);
}
}
flashNext();
}
// --- Event Handlers ---
// Roll button
rollBtn.down = function (x, y, obj) {
if (rolling || showCollection) return;
// Call the original RollButton.down (the class method), not this event handler
if (typeof RollButton.prototype.down === "function") {
RollButton.prototype.down.call(rollBtn, x, y, obj);
}
};
rollBtn.up = function (x, y, obj) {
if (rolling || showCollection) return;
// Do roll
var resultId = rollForItem();
lastRollResult = resultId;
// Add to collection if new
if (collection.indexOf(resultId) === -1) {
collection.push(resultId);
storage.collection = collection;
}
animateRoll(resultId);
updateMainDisplay();
// Call the original RollButton.up (the class method), not this event handler
if (typeof RollButton.prototype.up === "function") {
RollButton.prototype.up.call(rollBtn, x, y, obj);
}
};
// Show collection
showCollBtn.down = function (x, y, obj) {
if (rolling) return;
showCollBg.scaleX = 0.95;
showCollBg.scaleY = 0.95;
};
showCollBtn.up = function (x, y, obj) {
if (rolling) return;
showCollBg.scaleX = 1;
showCollBg.scaleY = 1;
showCollection = true;
collectionOverlay.visible = true;
updateCollectionGrid();
};
// Back from collection
backBtn.down = function (x, y, obj) {
backBg.scaleX = 0.95;
backBg.scaleY = 0.95;
};
backBtn.up = function (x, y, obj) {
backBg.scaleX = 1;
backBg.scaleY = 1;
showCollection = false;
collectionOverlay.visible = false;
};
// --- Initial State ---
updateMainDisplay();
collectionOverlay.visible = false;
// --- GUI Layout ---
titleTxt.x = 2048 / 2;
titleTxt.y = 40;
rarityTxt.x = 2048 / 2;
rarityTxt.y = 200;
// --- Touch Handling (prevent drag) ---
game.move = function (x, y, obj) {};
game.down = function (x, y, obj) {};
game.up = function (x, y, obj) {};
// --- Game Update ---
game.update = function () {
// No per-frame logic needed for MVP
}; ===================================================================
--- original.js
+++ change.js
@@ -32,9 +32,9 @@
if (itemDef.rotation) self.asset.rotation = itemDef.rotation;
if (itemDef.overlay) {
self.overlayText = new Text2(itemDef.overlay, {
size: 60,
- fill: "#222"
+ fill: "#fff"
});
self.overlayText.anchor.set(0.5, 0.5);
self.addChild(self.overlayText);
}
@@ -67,9 +67,9 @@
// Overlay text if needed
if (itemDef.overlay) {
self.overlayText = new Text2(itemDef.overlay, {
size: 120,
- fill: "#222"
+ fill: "#fff"
});
self.overlayText.anchor.set(0.5, 0.5);
self.addChild(self.overlayText);
}
Water. In-Game asset. 2d. High contrast. No shadows
Stone. In-Game asset. 2d. High contrast. No shadows
Flame. In-Game asset. 2d. High contrast. No shadows
Breeze. In-Game asset. 2d. High contrast. No shadows
Ember. In-Game asset. 2d. High contrast. No shadows
light green moss. In-Game asset. 2d. High contrast. No shadows
Crystal. In-Game asset. 2d. High contrast. No shadows
sand. In-Game asset. 2d. High contrast. No shadows
Gray ash. In-Game asset. 2d. High contrast. No shadows
Iron bar. In-Game asset. 2d. High contrast. No shadows
Rectangular button. In-Game asset. 2d. High contrast. No shadows
Quartz. In-Game asset. 2d. High contrast. No shadows
smoke. In-Game asset. 2d. High contrast. No shadows
Frozen human. In-Game asset. 2d. High contrast. No shadows
Thunder. In-Game asset. 2d. High contrast. No shadows
Vine. In-Game asset. 2d. High contrast. No shadows
spark. In-Game asset. 2d. High contrast. No shadows
lucky pebble. In-Game asset. 2d. High contrast. No shadows
Fortune Leaf. In-Game asset. 2d. High contrast. No shadows