Code edit (13 edits merged)
Please save this source code
User prompt
Fix Bug: 'SecurityError: Permission denied to access property "removeChild" on cross-origin object' in or related to this line: 'baseDestroy();' Line Number: 529
Code edit (1 edits merged)
Please save this source code
User prompt
Fix Bug: 'TypeError: t is undefined' in or related to this line: 'symbolAsset = self.attachAsset(newSymbol, {' Line Number: 183
Code edit (2 edits merged)
Please save this source code
User prompt
in the transitionPlanets function, destroy all traders and reset the array
User prompt
in the transitionPlanets function, destroy all asteroids and reset the array
Code edit (6 edits merged)
Please save this source code
User prompt
Remove any remaining console logs
Code edit (1 edits merged)
Please save this source code
Code edit (4 edits merged)
Please save this source code
User prompt
Add an asset with id "point" to BorderedSymbol and SymbolText
User prompt
Add an asset with id "point" to BorderedText, BorderedSymbol and SymbolText
Code edit (1 edits merged)
Please save this source code
User prompt
Created traders should be added to the foreground
User prompt
Created asteroids should be added to the midground and created traders should be added to the foreground
Code edit (9 edits merged)
Please save this source code
User prompt
add two containers to the game object called foreground and midground. Created asteroids should be added to the midground and created traders should be added to the foreground
Code edit (1 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
User prompt
Fix Bug: 'ReferenceError: trySpawnTrader is not defined' in or related to this line: 'trySpawnTrader();' Line Number: 1518
Code edit (1 edits merged)
Please save this source code
User prompt
In the Trader's constructor, if its setTrade object is defined, then create a TraderDialogue (sellName, sellAmount, buyName, buyAmount are all in the setTrade object), and add a new function to handle the callback with a bool param
Code edit (8 edits merged)
Please save this source code
User prompt
Add a new Trader class inheriting from ConfigContainer and has params of config and setTrade, with a trader asset attached
/****
* Classes
****/
var ConfigContainer = Container.expand(function (config) {
var self = Container.call(this);
;
config = config || {};
self.x = config.x || 0;
self.y = config.y || 0;
self.rotation = config.rotation || 0;
if (config.width !== undefined) {
self.width = config.width;
}
if (config.height !== undefined) {
self.height = config.height;
}
if (self.anchor) {
self.anchor.set(config.anchorX || 0, config.anchorY || 0);
}
;
return self;
});
var BorderedText = Container.expand(function (string, config) {
var self = Container.call(this);
config = config || {};
var textList = [];
var anchorX = config.anchorX !== undefined ? config.anchorX : 0;
var anchorY = config.anchorY !== undefined ? config.anchorY : 0;
var borderConfig = {
fill: config.border || TEXT_DEFAULT_BORDER,
font: config.font || TEXT_DEFAULT_FONT,
size: config.size || TEXT_DEFAULT_SIZE
};
var textConfig = {
fill: config.fill || TEXT_DEFAULT_FILL,
font: config.font || TEXT_DEFAULT_FONT,
size: config.size || TEXT_DEFAULT_SIZE
};
for (var i = 0; i < TEXT_OFFSETS.length; i++) {
var localSettings = i === TEXT_OFFSETS.length - 1 ? textConfig : borderConfig;
var text = self.addChild(new Text2(string, localSettings));
text.x += TEXT_OFFSETS[i][0] * TEXT_BORDER_WEIGHT;
text.y += TEXT_OFFSETS[i][1] * TEXT_BORDER_WEIGHT;
text.anchor.set(anchorX, anchorY);
textList.push(text);
}
;
self.x = config.x || 0;
self.y = config.y || 0;
self.setText = setText;
self.setFill = setFill;
;
function setText(string) {
for (var i = 0; i < textList.length; i++) {
textList[i].setText(string);
}
}
function setFill(newFill) {
textList[textList.length - 1].fill = newFill;
}
});
var CurrencySymbol = Container.expand(function (config) {
var self = Container.call(this);
config = config || {};
var mainSymbol;
var anchorX = config.anchorX !== undefined ? config.anchorX : .5;
var anchorY = config.anchorY !== undefined ? config.anchorY : .5;
var borderSettings = {
fill: 0x000000,
// fill: config.border || TEXT_DEFAULT_BORDER,
size: config.size || TEXT_DEFAULT_SIZE
};
var symbolSettings = {
fill: 0xFFFFFF,
// fill: config.fill || TEXT_DEFAULT_FILL,
size: config.size || TEXT_DEFAULT_SIZE
};
for (var i = 0; i < TEXT_OFFSETS.length; i++) {
var localConfig = i === TEXT_OFFSETS.length - 1 ? symbolSettings : borderSettings;
var symbol = self.attachAsset('currencySymbol', {
x: TEXT_OFFSETS[i][0] * TEXT_BORDER_WEIGHT,
y: TEXT_OFFSETS[i][1] * TEXT_BORDER_WEIGHT,
tint: localConfig.fill,
scaleX: localConfig.size / 100,
scaleY: localConfig.size / 100,
anchorX: anchorX,
anchorY: anchorY
});
;
if (i === TEXT_OFFSETS.length - 1) {
mainSymbol = symbol;
}
}
;
self.x = config.x || 0;
self.y = config.y || 0;
self.setFill = setFill;
;
function setFill(newFill) {
mainSymbol.tint = newFill;
}
});
var CurrencyText = Container.expand(function (amount, config) {
var self = Container.call(this);
config = config || {};
var anchorX = config.anchorX !== undefined ? config.anchorX : .5;
var anchorY = config.anchorY !== undefined ? config.anchorY : .5;
var margin = config.margin || CURRENCY_DEFAULT_MARGIN;
var currencySymbol = self.addChild(new CurrencySymbol({
anchorX: 0,
anchorY: anchorY
}));
var textAmount = self.addChild(new BorderedText(amount, {
anchorX: 0,
anchorY: anchorY
}));
;
self.x = config.x || 0;
self.y = config.y || 0;
self.setAmount = setAmount;
;
function alignText() {
var totalWidth = currencySymbol.width + margin + textAmount.width;
currencySymbol.x = -totalWidth * anchorX;
textAmount.x = currencySymbol.x + currencySymbol.width + margin;
}
function setAmount(newAmount) {
textAmount.setText(newAmount);
alignText();
}
;
alignText();
});
var Player = ConfigContainer.expand(function (config) {
var self = ConfigContainer.call(this, config);
var actionCountdown = PLAYER_ACTION_INTERVAL;
var playerGraphics = self.attachAsset('player', {
rotation: MATH_HALF_PI,
anchorX: 0.5,
anchorY: 0.5
});
;
self.update = update;
;
function update() {
var currentAngle = Math.atan2(self.y, self.x);
var angleDifference = targetAngle - currentAngle;
angleDifference = mod(angleDifference + Math.PI, MATH_2_PI) - Math.PI;
if (angleDifference < -MATH_APPROX_ZERO || angleDifference > MATH_APPROX_ZERO) {
var direction = angleDifference / Math.abs(angleDifference);
var angleStep = PLAYER_SPEED / planet.radius;
var newAngle = currentAngle + direction * Math.min(Math.abs(angleDifference), angleStep);
self.x = Math.cos(newAngle) * planet.radius;
self.y = Math.sin(newAngle) * planet.radius;
playerGraphics.scale.x = direction < 0 ? -1 : 1;
playerGraphics.rotation = newAngle + MATH_HALF_PI;
actionCountdown = 0; // Perform action immediately after stopping
} else if (--actionCountdown <= 0) {
actionCountdown = PLAYER_ACTION_INTERVAL;
performAction(currentAngle);
}
}
function performAction(angle) {
var count = planet.nodes.length;
var baseIndex = mod(Math.round(angle / MATH_2_PI * count), count);
var baseNode = planet.nodes[baseIndex];
if (baseNode && !baseNode.tryAction()) {
var iterations = Math.floor(PLAYER_ACTION_DIST / (planet.radius * MATH_2_PI / planet.nodes.length));
var prev = baseNode.prev;
var next = baseNode.next;
while (iterations > 0) {
iterations--;
if (next && next.tryAction()) {
break;
}
if (prev && prev.tryAction()) {
break;
}
prev = prev ? prev.prev : null;
next = next ? next.next : null;
}
}
}
});
var Ship = Container.expand(function (x, y) {
var self = Container.call(this);
var background = self.addChild(new Container());
var shipGraphics = self.attachAsset('ship', {
anchorX: 0.10,
anchorY: 0.5
});
var counter = 0;
var particles = [];
background.rotation = -MATH_HALF_PI;
;
self.update = update;
self.launch = launch;
self.x = x;
self.y = y;
self.direction = -1;
;
function update() {
if (self.direction < 0) {
self.x -= ROCKET_SPEED_REVERSE;
if (self.x <= planet.radius) {
self.x = planet.radius;
self.direction = 0;
player = planet.addChild(new Player({
rotation: ship.rotation,
x: ship.x,
y: ship.y
}));
}
} else if (self.direction > 0) {
counter++;
var speed = Math.pow(ROCKET_SPEED_BASE, counter / ROCKET_SPEED_DIV - ROCKET_SPEED_DELAY);
self.x += speed;
if (self.x > ROCKET_DIST_LEAVE) {
counter = 0;
self.direction = -1;
transitionPlanets();
}
}
if (self.direction) {
particles.push(background.addChild(new FlameParticle({
x: (Math.random() - 0.5) * ROCKET_FLAME_BREDTH
})));
}
updateList(particles);
}
function launch(direction) {
if (!self.direction) {
self.direction = direction;
if (direction > 0) {
player.destroy();
player = undefined;
}
}
}
});
var FlameParticle = ConfigContainer.expand(function (config) {
var self = ConfigContainer.call(this, config);
var flameGraphics = self.attachAsset('flame', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.5
});
var lifetime = ROCKET_FLAME_LIFETIME;
;
self.update = update;
;
function update() {
var remaining = lifetime / ROCKET_FLAME_LIFETIME;
self.y -= ROCKET_FLAME_SPEED;
flameGraphics.alpha = 0.5 * remaining;
flameGraphics.scale.set(remaining);
return --lifetime <= 0;
}
});
var Plant = ConfigContainer.expand(function (type, growStage, config) {
var self = ConfigContainer.call(this, config);
var details = PLANT_DETAILS[type];
;
self.update = update;
self.harvest = harvest;
self.updateStage = updateStage;
self.refreshGraphics = refreshGraphics;
self.refreshCountdown = refreshCountdown;
self.type = type;
self.fruit = details.fruit;
self.growStage = growStage;
self.growStages = details.stages;
self.growthTime = details.growthTime;
self.growthVariance = details.growthVariance;
self.growthCountdown = 0;
self.harvestable = growStage === self.growStages;
;
function update() {
if (--self.growthCountdown <= 0 && self.growStage < self.growStages) {
self.updateStage(self.growStage + 1);
}
}
function harvest() {
if (self.harvestable) {
if (self.growStage === self.growStages) {
new Fruit(self.fruit, {
x: self.parent.x,
y: self.parent.y,
rotation: self.parent.rotation
});
}
self.parent.plant = undefined;
self.destroy();
return true;
}
}
function updateStage(newStage) {
self.growStage = newStage;
self.refreshGraphics();
if (self.growStage === self.growStages) {
self.harvestable = true;
} else {
self.refreshCountdown();
}
}
function refreshGraphics() {
if (self.graphics) {
self.graphics.destroy();
}
self.graphics = self.createAsset(self.type + (self.growStage - 1), {
anchorX: 0.5,
anchorY: 1,
scaleX: Math.random() < 0.5 ? 1 : -1
});
}
function refreshCountdown() {
var baseTime = self.growthTime + Math.random() * self.growthVariance;
self.growthCountdown = Math.floor(PLANT_GROWTH_FACTOR * baseTime);
}
;
refreshCountdown();
refreshGraphics();
return self;
});
var PlantWeeds = Plant.expand(function (growthStage, config) {
var self = Plant.call(this, 'plantWeeds', growthStage, config);
var baseUpdate = self.update;
var spreadCountdown = 0;
;
self.harvestable = true;
self.update = update;
;
function update() {
baseUpdate();
;
if (self.growStage === self.growStages && --spreadCountdown <= 0) {
var node = self.parent;
var nextPlant = node.next.plant;
var prevPlant = node.prev.plant;
var nextSpreadable = !nextPlant || nextPlant.type !== self.type && nextPlant.type !== 'plantDiamond';
var prevSpreadable = !prevPlant || prevPlant.type !== self.type && prevPlant.type !== 'plantDiamond';
if (nextSpreadable || prevSpreadable) {
var targetNode;
if (nextSpreadable && prevSpreadable) {
targetNode = Math.random() < 0.5 ? node.next : node.prev;
} else {
targetNode = nextSpreadable ? node.next : node.prev;
}
targetNode.addPlant('plantWeeds', 1);
}
refreshCountdown();
}
}
function refreshCountdown() {
var baseTime = WEEDS_SPREAD_TIME + Math.random() * WEEDS_SPREAD_VARIANCE;
spreadCountdown = Math.floor(PLANT_GROWTH_FACTOR * baseTime);
}
;
refreshCountdown();
});
var PlantBush = Plant.expand(function (growthStage, config) {
var self = Plant.call(this, 'plantBush', growthStage, config);
var baseDestroy = self.destroy;
var baseUpdateStage = self.updateStage;
var fruitCount = 0;
var maxFruitCount = 3;
;
self.destroy = destroy;
self.updateStage = updateStage;
self.harvest = harvest;
;
function destroy() {
baseDestroy();
}
function updateStage(newStage) {
if (newStage === self.growStages) {
self.refreshCountdown();
if (fruitCount < maxFruitCount) {
fruitCount++;
self.harvestable = true;
}
} else {
baseUpdateStage(newStage);
}
}
function harvest() {
if (self.harvestable && fruitCount > 0) {
return true;
}
}
function updateVisibleFruit() {}
});
var PlantStalk = Plant.expand(function (growthStage, config) {
var self = Plant.call(this, 'plantStalk', growthStage, config);
});
var PlantEyeball = Plant.expand(function (growthStage, config) {
var self = Plant.call(this, 'plantEyeball', growthStage, config);
});
var PlantFlower = Plant.expand(function (growthStage, config) {
var self = Plant.call(this, 'plantFlower', growthStage, config);
});
var PlantDiamond = Plant.expand(function (growthStage, config) {
var self = Plant.call(this, 'plantDiamond', growthStage, config);
});
var PlantNode = ConfigContainer.expand(function (config) {
var self = ConfigContainer.call(this, config);
;
self.update = update;
self.addPlant = addPlant;
self.tryAction = tryAction;
self.offset = 20;
self.plant;
self.farm;
self.prev;
self.next;
;
function update() {
if (self.plant) {
self.plant.update();
}
}
function addPlant(plantName, stage) {
if (self.plant) {
self.plant.destroy();
}
var plantBlueprint = PLANT_DETAILS[plantName].blueprint;
self.plant = self.addChild(new plantBlueprint(stage, {
y: self.offset
}));
}
function tryAction() {
if (self.plant && self.plant.harvestable && self.plant.harvest()) {
return true;
}
}
;
return self;
});
var WeedsNode = PlantNode.expand(function (config) {
var self = PlantNode.call(this, config);
var baseUpdate = self.update;
var baseAddPlant = self.addPlant;
var baseTryAction = self.tryAction;
;
self.update = update;
self.addPlant = addPlant;
self.tryAction = tryAction;
;
function update() {
baseUpdate();
if (!self.plant && --spawnCountdown <= 0) {
self.addPlant('plantWeeds', 1);
}
}
function addPlant(plantName, stage) {
baseAddPlant(plantName, stage);
refreshCountdown();
}
function tryAction() {
if (baseTryAction()) {
refreshCountdown();
return true;
}
}
function refreshCountdown() {
var baseTime = WEEDS_SPAWN_TIME + Math.random() * WEEDS_SPAWN_VARIANCE;
spawnCountdown = Math.floor(PLANT_GROWTH_FACTOR * baseTime);
}
;
refreshCountdown();
});
var FarmNode = PlantNode.expand(function (config) {
var self = PlantNode.call(this, config);
var baseOffset = self.offset;
var baseUpdate = self.update;
var baseAddPlant = self.addPlant;
var baseTryAction = self.tryAction;
var targetAlpha = 0;
var planterButton;
var planterLinger = 0;
var currentAlpha = targetAlpha;
var farmGraphics = self.attachAsset('farm', {
anchorX: 0.5,
anchorY: 0.6,
alpha: currentAlpha
});
;
self.update = update;
self.addPlant = addPlant;
self.tryAction = tryAction;
self.tryPlantFruit = tryPlantFruit;
self.offset = -20;
self.potted = false;
;
function update() {
baseUpdate();
if (currentAlpha !== targetAlpha) {
if (currentAlpha < targetAlpha) {
currentAlpha = Math.min(targetAlpha, currentAlpha + PLOT_ALPHA_STEP);
} else {
currentAlpha = Math.max(targetAlpha, currentAlpha - PLOT_ALPHA_STEP);
}
farmGraphics.alpha = currentAlpha;
}
if (planterLinger > 0) {
planterLinger--;
} else if (planterButton) {
planterButton.destroy();
planterButton = undefined;
}
}
function addPlant(plantName, stage, potted) {
baseAddPlant(plantName, stage);
if (!potted && plantName === 'plantWeeds') {
self.plant.y = baseOffset;
targetAlpha = 0;
} else {
targetAlpha = 1;
}
self.potted = potted;
}
function tryAction() {
if (baseTryAction()) {
targetAlpha = 1;
return true;
} else if (self.alpha === 1 && !self.plant && inventory.allowed) {
var fruitName = inventory.getSelection();
var quantity = inventory.getQuantity(fruitName);
if (quantity > 0) {
if (planterButton) {
planterButton.updateImage(fruitName);
} else {
planterButton = self.addChild(new PlantButton(fruitName, function () {
self.tryPlantFruit(inventory.getSelection());
}, {}));
}
planterLinger = PLAYER_ACTION_INTERVAL + PLOT_EXTRA_LINGER;
} else {
planterLinger = 0;
}
} else {
planterLinger = 0;
}
}
function tryPlantFruit(fruitName) {
if (!self.plant) {
var plantName = FRUIT_DETAILS[fruitName].plant;
self.addPlant(plantName, 1, true);
inventory.adjustItem(fruitName, -1);
if (plantName === 'plantWeeds') {
self.plant.harvestable = false;
}
}
}
});
var Planet = ConfigContainer.expand(function (planetName, config, barren) {
var self = ConfigContainer.call(this, config);
var details = PLANET_DETAILS[planetName];
var perimeter = MATH_2_PI * details.radius;
var numPlots = Math.floor(perimeter / (PLOT_SIZE + PLOT_GAP));
var numNodes = numPlots * 4;
var nodes = [];
var fruitList = [];
var background = self.addChild(new Container());
var planetScale = 2 * details.radius / 1000;
var planetGraphics = self.createAsset(planetName, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: planetScale,
scaleY: planetScale
});
;
self.update = update;
self.name = planetName;
self.barren = !!barren;
self.nodes = nodes;
self.background = background;
self.fruitList = fruitList;
self.spin = details.spin;
self.radius = details.radius;
;
function update(ticks) {
self.rotation += self.spin;
updateList(nodes);
updateList(fruitList);
}
function createNodes() {
if (!barren) {
var defaultPlant = 'plantWeeds';
var maxPlantStage = PLANT_DETAILS[defaultPlant].stages;
for (var i = 0; i < numNodes; i++) {
var angle = i / numNodes * MATH_2_PI;
var nodeX = self.radius * Math.cos(angle);
var nodeY = self.radius * Math.sin(angle);
var rotation = angle + MATH_HALF_PI;
var farmNode = i !== 0 && i % 4 === 0;
var nodeType = farmNode ? FarmNode : i % 2 === 0 ? WeedsNode : PlantNode;
var node = self.addChild(new nodeType({
x: nodeX,
y: nodeY,
rotation: rotation
}));
if (farmNode) {
node.addPlant(defaultPlant, maxPlantStage);
} else if (Math.random() < WEEDS_SPAWN_CHANCE) {
node.addPlant(defaultPlant, 1 + Math.floor(Math.random() * maxPlantStage));
}
if (i !== 0) {
node.prev = nodes[i - 1];
node.prev.next = node;
if (i === numNodes - 1) {
node.next = nodes[0];
node.next.prev = node;
}
}
nodes.push(node);
}
}
}
;
createNodes();
return self;
});
var PlanetGrey = Planet.expand(function (config) {
var self = Planet.call(this, 'planetGrey', config);
});
var PlanetRed = Planet.expand(function (config) {
var self = Planet.call(this, 'planetRed', config);
});
var PlanetBlue = Planet.expand(function (config) {
var self = Planet.call(this, 'planetBlue', config);
});
var PlanetOmni = Planet.expand(function (config) {
var self = Planet.call(this, 'planetOmni', config);
});
var PlanetGold = Planet.expand(function (config) {
var self = Planet.call(this, 'planetGold', config, true);
});
var Crosshair = Container.expand(function () {
var self = Container.call(this);
var counter = 0;
var arrows = [];
var arrowOffsets = [{
x: 0,
y: -1
}, {
x: 1,
y: 0
}, {
x: 0,
y: 1
}, {
x: -1,
y: 0
}];
for (var i = 0; i < arrowOffsets.length; i++) {
var arrow = self.attachAsset('arrow', {
anchorX: 0.5,
anchorY: 1
});
arrow.rotation = MATH_HALF_PI * i;
arrows.push(arrow);
self.addChild(arrow);
}
;
self.rotation = MATH_QUARTER_PI;
self.update = update;
;
function update() {
if (currentPlanet !== destinationPlanet) {
counter++;
var distance = CROSSHAIR_DIST + CROSSHAIR_VARIANCE * Math.sin(counter / CROSSHAIR_PERIOD);
setDistance(distance);
} else if (counter > 0) {
counter = 0;
setDistance(CROSSHAIR_DIST);
}
}
function setDistance(distance) {
for (var i = 0; i < arrows.length; i++) {
arrows[i].x = arrowOffsets[i].x * distance;
arrows[i].y = arrowOffsets[i].y * distance;
}
}
;
setDistance(CROSSHAIR_DIST);
});
var NavigationButton = ConfigContainer.expand(function (planetName, callback, config) {
var self = ConfigContainer.call(this, config);
var details = PLANET_DETAILS[planetName];
var buttonGraphics = self.attachAsset('navigationButton', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0xFFAAAA
});
var planetGraphics = self.createAsset(planetName, {
anchorX: 0.5,
anchorY: 0.5,
width: buttonGraphics.width * 0.4,
height: buttonGraphics.width * 0.4
});
var currencyText = self.addChild(new CurrencyText(details.cost));
;
self.unlock = unlock;
self.cost = details.cost;
self.planet = planetName;
self.unlocked = !details.cost;
self.on('down', function () {
callback(planetName);
});
;
function unlock() {
self.unlocked = true;
buttonGraphics.tint = 0xFFFFFF;
currencyText.destroy();
}
;
if (self.unlocked) {
unlock();
}
});
var NavigationInterface = Container.expand(function (x, y) {
var self = Container.call(this);
var buttons = {};
var baseOffset = -NAVIGATION.length / 2 + 0.5;
var firstPlanet = NAVIGATION[0];
for (var i = 0; i < NAVIGATION.length; i++) {
var planet = NAVIGATION[i];
var buttonX = (baseOffset + i) * 200;
buttons[planet] = self.addChild(new NavigationButton(planet, buttonCallback, {
x: buttonX,
y: 0
}));
}
buttons[firstPlanet].addChild(crosshair);
self.x = x;
self.y = y;
;
function buttonCallback(planet) {
var button = buttons[planet];
if (button.unlocked) {
setDestination(planet);
} else if (money >= button.cost) {
moneyDisplay.setAmount(money -= button.cost);
button.unlock();
}
}
self.setDestination = setDestination;
;
function setDestination(planet) {
if (destinationPlanet !== planet && ship.direction === 0) {
destinationPlanet = planet;
buttons[planet].addChild(crosshair);
ship.launch(1);
}
}
buttonCallback(firstPlanet);
});
var WinningMessage = Container.expand(function (x, y, completionTicks) {
var self = Container.call(this);
var seconds = Math.floor(completionTicks / 60);
var minutes = Math.floor(seconds / 60);
var hours = Math.floor(minutes / 60);
seconds = seconds % 60;
minutes = minutes % 60;
var winningTime = (hours > 0 ? hours + 'h ' : '') + (minutes > 0 ? minutes + 'm ' : '') + seconds + 's';
var messageStatTitles = ['Credits', 'Harvests', 'Weeds', 'Trades'];
var messageStatKeys = ['creditsEarned', 'cropsHarvested', 'weedsPulled', 'salesDone'];
var timeText = self.addChild(new BorderedText('You reached the Gold Planet in: ' + winningTime, {
anchorX: .5,
anchorY: 1,
y: -TEXT_WINNING_OFFSET
}));
self.addChild(new BorderedText('Congratulations, you win!', {
anchorX: .5,
anchorY: 1,
size: 80,
y: timeText.y - timeText.height - 10
}));
self.addChild(new BorderedText(messageStatTitles.map(mapTitle).join('\n'), {
anchorX: 1,
anchorY: 0,
y: TEXT_WINNING_OFFSET
}));
self.addChild(new BorderedText(messageStatKeys.map(mapKey).join('\n'), {
anchorX: 0,
anchorY: 0,
y: TEXT_WINNING_OFFSET
}));
;
self.x = x;
self.y = y;
;
function mapTitle(title) {
return '• ' + title + ' ';
}
function mapKey(key) {
var stat = winningStats[key];
var extra = stat - stats[key];
return ': ' + stat + (extra ? ' (+ ' + extra + ')' : '');
}
});
var Background = Container.expand(function () {
var self = Container.call(this);
var backgroundGraphics = self.attachAsset('background', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.5
});
backgroundGraphics.width = GAME_WIDTH * 1.05;
backgroundGraphics.height = GAME_WIDTH * 1.05;
;
self.x = GAME_WIDTH / 2;
self.y = GAME_HEIGHT / 2;
self.refresh = refresh;
;
function refresh() {
backgroundGraphics.rotation += Math.PI / 2;
}
});
var InventorySlot = ConfigContainer.expand(function (index, config) {
var self = ConfigContainer.call(this, config);
var itemDisplay;
var frame = self.attachAsset('inventoryFrame', {
anchorX: .5,
anchorY: .5
});
var quantityText = self.addChild(new BorderedText('', {
size: 30,
anchorX: .5,
anchorY: .5,
y: INVENTORY_SLOT_SIZE / 2.2
}));
frame.width = INVENTORY_SLOT_SIZE;
frame.height = INVENTORY_SLOT_SIZE;
;
self.setItem = setItem;
self.adjustQuantity = adjustQuantity;
self.index = index;
self.item = null;
self.quantity = 0;
;
function adjustQuantity(amount) {
self.quantity += amount;
quantityText.setText(self.quantity);
}
function setItem(itemName) {
self.item = itemName;
if (itemDisplay) {
itemDisplay.destroy();
}
itemDisplay = self.attachAsset(itemName, {
anchorX: 0.5,
anchorY: 0.5
});
itemDisplay.scale.set(INVENTORY_SLOT_SIZE / 100 * INVENTORY_ICON_SCALE);
}
;
self.on('down', function () {
self.parent.selectSlot(self.index);
});
});
var Inventory = ConfigContainer.expand(function (config) {
var self = ConfigContainer.call(this, config);
var slots = [];
var itemIndices = {};
var selectedIndex = 0;
var widthOffset = INVENTORY_SLOT_SIZE * INVENTORY_COLS * (config.anchorX || 0);
var heightOffset = INVENTORY_SLOT_SIZE * INVENTORY_ROWS * (config.anchorY || 0);
for (var row = 0; row < INVENTORY_ROWS; row++) {
for (var col = 0; col < INVENTORY_COLS; col++) {
var index = row * INVENTORY_COLS + col;
slots.push(self.addChild(new InventorySlot(index, {
x: (col + .5) * INVENTORY_SLOT_SIZE - widthOffset,
y: (row + .5) * INVENTORY_SLOT_SIZE - heightOffset
})));
}
}
var selector = new InventorySelector();
var warningText = self.addChild(new BorderedText('', {
anchorX: 0.5,
anchorY: 0,
y: INVENTORY_SLOT_SIZE * INVENTORY_ROWS / 2 + 20
}));
warningText.visible = false;
;
self.adjustItem = adjustItem;
self.selectSlot = selectSlot;
self.getQuantity = getQuantity;
self.getSelection = getSelection;
self.refreshAllowed = refreshAllowed;
self.selector = selector;
self.allowed = false;
;
function selectSlot(index) {
slots[index].addChild(selector);
selectedIndex = index;
refreshAllowed();
}
function adjustItem(item, quantity) {
var slotIndex = itemIndices[item];
var newItem = false;
if (slotIndex === undefined) {
for (slotIndex = 0; slotIndex < slots.length; slotIndex++) {
if (!slots[slotIndex].item) {
break;
}
}
slots[slotIndex].setItem(item);
newItem = true;
}
itemIndices[item] = slotIndex;
slots[slotIndex].adjustQuantity(quantity);
if (newItem && slotIndex === selectedIndex) {
slots[slotIndex].addChild(selector);
refreshAllowed();
}
}
function getSelection() {
return slots[selectedIndex].item;
}
function getQuantity(item) {
var slotIndex = itemIndices[item];
return slotIndex === undefined ? 0 : slots[slotIndex].quantity;
}
function refreshAllowed() {
var selection = getSelection();
var allowed = true;
if (selection) {
var itemDetails = FRUIT_DETAILS[selection];
var allowedTypes = PLANET_DETAILS[planet.name].plantTypes;
allowed = allowedTypes.includes(itemDetails.type);
if (!allowed) {
var warning = planet.barren ? GROW_WARNING_BARREN : GROW_WARNING_GENERAL;
warningText.setText(warning);
}
}
self.allowed = allowed;
selector.toggleAllowed(allowed);
warningText.visible = !allowed;
}
;
selectSlot(0);
refreshAllowed();
adjustItem('fruitWeeds', 0);
});
var InventorySelector = Container.expand(function () {
var self = Container.call(this);
var selector = self.attachAsset('inventorySelector', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0xFF3333
});
var crossAsset = self.attachAsset('cross', {
anchorX: 0.5,
anchorY: 0.5
});
;
self.toggleAllowed = toggleAllowed;
;
function toggleAllowed(bool) {
crossAsset.alpha = bool ? 0 : 1;
}
});
var Asteroid = ConfigContainer.expand(function (config) {
var self = ConfigContainer.call(this, config);
var randomScale = ASTEROID_SCALE_MIN + Math.random() * ASTEROID_SCALE_VAR;
var asteroidGraphics = self.attachAsset('asteroid', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: randomScale,
scaleY: randomScale,
rotation: Math.random() * MATH_2_PI
});
var side = self.x < 0;
var targetY = ASTEROID_TARGET_OFFSET + Math.random() * (GAME_HEIGHT - 2 * ASTEROID_TARGET_OFFSET);
var targetX = side ? GAME_WIDTH + ASTEROID_MARGIN : -ASTEROID_MARGIN;
var rotationSpeed = (Math.random() - 0.5) * 2 * ASTEROID_ROTATION_MAX;
var angle = Math.atan2(targetY - self.y, targetX - self.x);
var velocityX = ASTEROID_SPEED * Math.cos(angle);
var velocityY = ASTEROID_SPEED * Math.sin(angle);
;
self.update = update;
;
function update() {
self.rotation += rotationSpeed;
self.x += velocityX;
self.y += velocityY;
var dx = self.x - planet.x;
var dy = self.y - planet.y;
var distanceSquared = dx * dx + dy * dy;
if (distanceSquared <= planet.radius * planet.radius) {
if (Math.random() < ASTEROID_DROP_CHANCE) {
var angle = Math.atan2(self.y - planet.y, self.x - planet.x) - planet.rotation;
var fruitX = Math.cos(angle) * planet.radius;
var fruitY = Math.sin(angle) * planet.radius;
var fruit = planet.addChild(new Fruit('fruitDiamondDust', {
rotation: angle + MATH_HALF_PI,
x: fruitX,
y: fruitY
}));
}
var explosion = game.addChild(new Explosion({
x: self.x,
y: self.y,
scale: randomScale
}));
return true;
}
return side ? self.x > targetX : self.x < targetX;
}
});
var Explosion = ConfigContainer.expand(function (config) {
var self = ConfigContainer.call(this, config);
var baseScale = config.scale;
var frameCount = 0;
var explosionGraphics = self.attachAsset('explosion', {
anchorX: 0.25,
anchorY: 0.5,
scaleX: baseScale,
scaleY: baseScale,
alpha: 0.5,
rotation: Math.atan2(self.y - planet.y, self.x - planet.x)
});
;
self.update = update;
;
function update() {
frameCount++;
explosionGraphics.alpha -= 0.5 / EXPLOSION_FRAMES;
explosionGraphics.scale.set(baseScale * (1 + frameCount / EXPLOSION_FRAMES));
if (frameCount >= EXPLOSION_FRAMES) {
self.destroy();
return true;
}
}
;
effectsList.push(self);
});
var Fruit = ConfigContainer.expand(function (fruitName, config) {
var self = ConfigContainer.call(this, config);
var fruitGraphics = self.attachAsset(fruitName, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: PLANT_FRUIT_SCALE * Math.random() < 0.5 ? 1 : -1,
scaleY: PLANT_FRUIT_SCALE
});
;
self.fruitName = fruitName;
self.update = update;
;
function update() {
if (player) {
var dx = self.x - player.x;
var dy = self.y - player.y;
var sqrDistance = dx * dx + dy * dy;
if (sqrDistance < PLAYER_ACTION_SQRDIST) {
inventory.adjustItem(fruitName, 1);
return true;
}
}
}
;
planet.fruitList.push(planet.addChild(self));
});
var TraderDialogue = ConfigContainer.expand(function (sellName, sellAmount, buyName, buyAmount, callback, config) {
var self = ConfigContainer.call(this, config);
var dialogueBackground = self.attachAsset('traderDialogue', {
anchorX: 0.5,
anchorY: 0.5
});
var horizonAssets = [];
var createAssetOrCurrencyText = function createAssetOrCurrencyText(name, amount, isCurrency) {
if (isCurrency) {
return self.addChild(new CurrencyText(amount, {
anchorX: 0,
anchorY: 0.5
}));
} else {
var asset = self.attachAsset(name, {
anchorX: 0.5,
anchorY: 0.5
});
var amountText = self.addChild(new BorderedText(amount.toString(), {
anchorX: 1,
anchorY: 0.5
}));
horizonAssets.push(asset);
return amountText;
}
};
var sellAsset = createAssetOrCurrencyText(sellName, sellAmount, sellName === 'credits');
var arrowAsset = self.attachAsset('arrow', {
anchorX: 0.5,
anchorY: 0.5
});
horizonAssets.push(arrowAsset);
var buyAsset = createAssetOrCurrencyText(buyName, buyAmount, buyName === 'credits');
// Position the assets horizontally
var totalWidth = sellAsset.width + arrowAsset.width + buyAsset.width;
var currentX = -totalWidth / 2;
for (var i = 0; i < horizonAssets.length; i++) {
horizonAssets[i].x = currentX + horizonAssets[i].width / 2;
currentX += horizonAssets[i].width;
}
// Add interaction
var buttonContainer = self.addChild(new Container());
var tickButton = buttonContainer.addChild(new BasicButton('tick', function () {
callback(true);
}, {
x: -50,
y: dialogueBackground.height / 2 + 20
}));
var crossButton = buttonContainer.addChild(new BasicButton('cross', function () {
callback(false);
}, {
x: 50,
y: dialogueBackground.height / 2 + 20
}));
buttonContainer.x = -tickButton.width;
buttonContainer.y = dialogueBackground.height / 2 + 20;
});
var BasicButton = ConfigContainer.expand(function (imageName, callback, config) {
var self = ConfigContainer.call(this, config);
var buttonBackground = self.attachAsset('buttonBackground', {
anchorX: 0.5,
anchorY: 0.5
});
var imageAsset;
if (imageName) {
imageAsset = self.attachAsset(imageName, {
anchorX: 0.5,
anchorY: 0.5
});
}
;
self.updateImage = updateImage;
self.imageName = imageName;
self.imageAsset = imageAsset;
self.buttonBackground = buttonBackground;
;
function updateImage(newImageName) {
if (newImageName !== self.imageName) {
self.imageName = newImageName;
if (imageAsset) {
imageAsset.destroy();
}
if (newImageName) {
imageAsset = self.attachAsset(newImageName, {
x: buttonBackground.x,
y: buttonBackground.y,
anchorX: 0.5,
anchorY: 0.5
});
}
}
}
;
buttonBackground.on('down', callback);
return self;
});
var Trader = ConfigContainer.expand(function (config, setTrade) {
var self = ConfigContainer.call(this, config);
var traderGraphics = self.attachAsset('trader', {
anchorX: 0.5,
anchorY: 0.5
});
self.setTrade = setTrade;
// Add any additional setup or methods required for the Trader here.
return self;
});
var PlantButton = BasicButton.expand(function (plantName, callback, config) {
var self = BasicButton.call(this, plantName, callback, config);
var arrow = self.attachAsset('arrow', {
y: PLANT_BUTTON_OFFSET / 2,
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2,
scaleY: 2
});
;
self.buttonBackground.y = PLANT_BUTTON_OFFSET;
self.imageAsset.y = PLANT_BUTTON_OFFSET;
;
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000 // Init game with black background
});
/****
* Game Code
****/
// Math constants / pre-calculations
var MATH_2_PI = Math.PI * 2;
var MATH_HALF_PI = Math.PI / 2;
var MATH_QUARTER_PI = Math.PI / 4;
var MATH_HALF_ROOT_3 = Math.sqrt(3) / 2;
var MATH_APPROX_ZERO = 0.0000001;
var EXPLOSION_FRAMES = 15; // Number of frames for the explosion animation to last
// Game constants
var GAME_TICKS = 60;
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2732;
// Rocket constants
var ROCKET_DIST_REVERSE = 300;
var ROCKET_DIST_LEAVE = 2500;
var ROCKET_SPEED_BASE = 1.2;
var ROCKET_SPEED_DIV = 5;
var ROCKET_SPEED_DELAY = 10;
var ROCKET_SPEED_REVERSE = 2;
var ROCKET_FLAME_BREDTH = 30;
var ROCKET_FLAME_LIFETIME = 30;
var ROCKET_FLAME_SPEED = 5;
// Farm constants
var PLOT_SIZE = 65;
var PLOT_GAP = 90;
var PLOT_ALPHA_STEP = 1 / GAME_TICKS;
var PLOT_EXTRA_LINGER = Math.floor(GAME_TICKS / 2);
// Interface settings
var TEXT_OFFSETS = [[0, 1], [MATH_HALF_ROOT_3, 0.5], [MATH_HALF_ROOT_3, -0.5], [0, -1], [-MATH_HALF_ROOT_3, -0.5], [-MATH_HALF_ROOT_3, 0.5], [0, 0]];
var TEXT_BORDER_WEIGHT = 4;
var TEXT_DEFAULT_SIZE = 50;
var TEXT_DEFAULT_FONT = 'Arial';
var TEXT_DEFAULT_FILL = '#FFFFFF';
var TEXT_DEFAULT_BORDER = '#000000';
var TEXT_WINNING_OFFSET = 300;
var CURRENCY_DEFAULT_MARGIN = 0;
var CROSSHAIR_DIST = 40;
var CROSSHAIR_VARIANCE = 10;
var CROSSHAIR_PERIOD = 1.25 * GAME_TICKS / MATH_2_PI;
// Inventory constants
var INVENTORY_ROWS = 1;
var INVENTORY_COLS = 8;
var INVENTORY_ICON_SCALE = 0.5;
var INVENTORY_SLOT_SIZE = 100;
// Asteroid constants
var ASTEROID_SPAWN_CHANCE = 0.001;
var ASTEROID_DROP_CHANCE = 0.1; // 10% chance
var ASTEROID_ROTATION_MAX = 0.02;
var ASTEROID_SPEED = 5;
var ASTEROID_MARGIN = 100;
var ASTEROID_SCALE_MIN = 0.75;
var ASTEROID_SCALE_VAR = 0.5;
var ASTEROID_TARGET_OFFSET = 500;
// Player constants
var PLAYER_SPEED = 5;
var PLAYER_ACTION_INTERVAL = Math.floor(GAME_TICKS / 4);
var PLAYER_ACTION_DIST = 80;
var PLAYER_ACTION_SQRDIST = PLAYER_ACTION_DIST * PLAYER_ACTION_DIST;
var PLAYER_BUFFER_DIST = 400;
var PLAYER_BUFFER_SQRDIST = PLAYER_BUFFER_DIST * PLAYER_BUFFER_DIST;
var PLAYER_START_ANGLE = Math.PI / 16;
// Plant constants
var WEEDS_SPAWN_CHANCE = 0.3;
var WEEDS_SPAWN_TIME = 5 * 60 * GAME_TICKS;
var WEEDS_SPAWN_VARIANCE = 2 * 60 * GAME_TICKS;
var WEEDS_SPREAD_TIME = 1 * 60 * GAME_TICKS;
var WEEDS_SPREAD_VARIANCE = 20 * GAME_TICKS;
var GROW_WARNING_BARREN = 'Nothing grows on this planet!';
var GROW_WARNING_GENERAL = 'Cannot grow this plant here...';
var PLANT_GROWTH_FACTOR = 1.0;
var PLANT_BUTTON_OFFSET = -220;
var PLANT_FRUIT_SCALE = 0.8;
var PLANT_DETAILS = {
plantWeeds: {
blueprint: PlantWeeds,
stages: 4,
fruit: 'fruitWeeds',
growthTime: 60 * GAME_TICKS,
growthVariance: 10 * GAME_TICKS
},
plantBush: {
blueprint: PlantBush,
stages: 5,
fruit: 'fruitBush',
growthTime: 120 * GAME_TICKS,
growthVariance: 30 * GAME_TICKS
},
plantStalk: {
blueprint: PlantStalk,
stages: 7,
fruit: 'fruitStalk',
growthTime: 60 * GAME_TICKS,
growthVariance: 20 * GAME_TICKS
},
plantEyeball: {
blueprint: PlantEyeball,
stages: 5,
fruit: 'fruitEyeball',
growthTime: 40 * GAME_TICKS,
growthVariance: 10 * GAME_TICKS
},
plantFlower: {
blueprint: PlantFlower,
stages: 4,
fruit: 'fruitFlower',
growthTime: 40 * GAME_TICKS,
growthVariance: 10 * GAME_TICKS
},
plantDiamond: {
blueprint: PlantDiamond,
stages: 4,
fruit: 'fruitDiamond',
growthTime: 80 * GAME_TICKS,
growthVariance: 30 * GAME_TICKS
}
};
var FRUIT_DETAILS = {
fruitWeeds: {
value: 1,
type: 'green',
plant: 'plantWeeds'
},
fruitBush: {
value: 5,
type: 'green',
plant: 'plantBush'
},
fruitStalk: {
value: 5,
type: 'red',
plant: 'plantBean'
},
fruitEyeball: {
value: 10,
type: 'red',
plant: 'plantEyeball'
},
fruitFlower: {
value: 50,
type: 'blue',
plant: 'plantFlower'
},
fruitDiamondDust: {
value: 0,
type: 'omni',
plant: 'plantDiamond'
},
fruitDiamond: {
value: 250,
type: 'none',
plant: 'none'
}
};
// Planet & navigation settings
var NAVIGATION = ['planetGrey', 'planetRed', 'planetBlue', 'planetOmni', 'planetGold'];
var PLANET_DETAILS = {
planetGrey: {
cost: 0,
radius: 200,
spin: 0.001,
blueprint: PlanetGrey,
plantTypes: ['green'],
buy: ['credits', 'fruitBush', 'fruitStalk'],
sell: ['credits', 'fruitWeeds', 'fruitBush']
},
planetRed: {
cost: 100,
radius: 400,
spin: -0.0002,
blueprint: PlanetRed,
plantTypes: ['green', 'red'],
buy: ['credits', 'fruitStalk', 'fruitEyeball'],
sell: ['credits', 'fruitWeeds', 'fruitBush', 'fruitStalk', 'fruitEyeball']
},
planetBlue: {
cost: 250,
radius: 350,
spin: 0.001,
blueprint: PlanetBlue,
plantTypes: ['green', 'blue'],
buy: ['credits', 'fruitFlower'],
sell: ['credits', 'fruitWeeds', 'fruitBush', 'fruitFlower']
},
planetOmni: {
cost: 800,
radius: 500,
spin: 0.005,
blueprint: PlanetOmni,
plantTypes: ['green', 'blue', 'red', 'omni'],
buy: ['credits'],
sell: ['fruitStalk', 'fruitEyeball', 'fruitFlower', 'fruitDiamond', 'fruitDiamond']
},
planetGold: {
cost: 3000,
radius: 250,
spin: -0.001,
blueprint: PlanetGold,
plantTypes: [],
buy: [],
sell: []
}
};
;
var money = 10000;
var asteroidList = [];
var stats = {
creditsEarned: 0,
cropsHarvested: 0,
cropsOverrun: 0,
weedsPulled: 0,
salesDone: 0,
salesRejected: 0
};
var winningStats = {};
var winningTick = -1;
var winningTime = '';
var winningMessage;
var effectsList = [];
var player;
var targetAngle = PLAYER_START_ANGLE;
var currentPlanet = NAVIGATION[0];
var destinationPlanet = NAVIGATION[0];
var background = game.addChild(new Background());
var planet = game.addChild(new PlanetGrey({
x: GAME_WIDTH / 2,
y: GAME_HEIGHT / 2,
rotation: Math.random() * MATH_2_PI
}));
var ship = planet.background.addChild(new Ship(planet.radius + ROCKET_DIST_REVERSE, 0));
var planetMap = {};
var inventory = LK.gui.top.addChild(new Inventory({
y: INVENTORY_SLOT_SIZE / 2 + 10,
anchorX: .5,
anchorY: .5
}));
var moneyDisplay = LK.gui.top.addChild(new CurrencyText(money, {
x: inventory.width / 2 + 25,
y: inventory.y,
size: 70,
anchorX: 0
}));
var crosshair = new Crosshair();
var navigation = LK.gui.bottom.addChild(new NavigationInterface(0, -100));
planetMap[planet.name] = planet;
;
LK.on('tick', function () {
if (player) {
player.update();
}
ship.update();
planet.update();
crosshair.update();
updateList(asteroidList);
updateList(effectsList);
trySpawnAsteroid();
});
game.on('down', function (obj) {
console.log(obj);
if (player) {
var clickPosition = obj.event.getLocalPosition(game);
var dx = clickPosition.x - planet.x;
var dy = clickPosition.y - planet.y;
var sqrDistance = dx * dx + dy * dy;
var range = planet.radius + PLAYER_BUFFER_DIST;
if (sqrDistance <= range * range) {
targetAngle = Math.atan2(dy, dx) - planet.rotation;
}
}
});
;
function updateList(list) {
for (var i = list.length - 1; i >= 0; i--) {
var item = list[i];
if (item.update && item.update()) {
item.destroy();
list.splice(i, 1);
}
}
}
function trySpawnAsteroid() {
if (Math.random() < ASTEROID_SPAWN_CHANCE) {
var side = Math.random() < 0.5;
asteroidList.push(game.addChild(new Asteroid({
x: side ? -ASTEROID_MARGIN : GAME_WIDTH + ASTEROID_MARGIN,
y: Math.random() * GAME_HEIGHT,
vx: side ? ASTEROID_SPEED : -ASTEROID_SPEED
})));
}
}
function transitionPlanets() {
LK.effects.flashScreen(0x000000, 500);
currentPlanet = destinationPlanet;
planet.parent.removeChild(planet);
planet = planetMap[currentPlanet];
if (!planet) {
var planetClass = PLANET_DETAILS[currentPlanet].blueprint;
planet = planetMap[currentPlanet] = new planetClass({
x: GAME_WIDTH / 2,
y: GAME_HEIGHT / 2
});
}
if (currentPlanet === NAVIGATION[NAVIGATION.length - 1]) {
if (winningTick < 0) {
saveStats();
winningTick = LK.ticks;
}
winningMessage = LK.gui.center.addChild(new WinningMessage(0, -100, winningTick));
} else if (winningMessage) {
winningMessage.destroy();
winningMessage = undefined;
}
game.addChild(planet);
planet.background.addChild(ship);
planet.rotation = Math.random() * MATH_2_PI;
ship.x = planet.radius + ROCKET_DIST_REVERSE;
background.refresh();
inventory.refreshAllowed();
}
function mod(x, base) {
return (x % base + base) % base;
}
function saveStats() {
for (var key in stats) {
winningStats[key] = stats[key];
}
}
pixel art of a tiny planet. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
pixel art of a planet. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
pixel art of an alien currency symbol. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
pixel art of a planet made of gold ore. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
plain black background with stars. 2d repeating Texture.
pixel art of a asteroid. Game asset. 2d. Blank background. High contrast. No shadows.
pixel art of a cute alien farmer, side view. Game asset. 2d. Blank background. High contrast. No shadows.
pixel art of a rocky explosion.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
pixel art flame particle. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
pixel art of a large white, empty, rectangular, speech bubble. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
pixel art of a red chevron. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
Pixel art of yellow grapes. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.