/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// ActionButton class
var ActionButton = Container.expand(function () {
var self = Container.call(this);
self.actionType = '';
self.label = '';
self.iconId = '';
self.onAction = null;
self.init = function (actionType, label, iconId, onAction) {
self.actionType = actionType;
self.label = label;
self.iconId = iconId;
self.onAction = onAction;
var icon = self.attachAsset(iconId, {
anchorX: 0.5,
anchorY: 0.5
});
self.icon = icon;
var txt = new Text2(label, {
size: 48,
fill: "#fff"
});
txt.anchor.set(0.5, 0);
txt.y = 50;
self.addChild(txt);
self.txt = txt;
};
// Touch/click event
self.down = function (x, y, obj) {
if (typeof self.onAction === 'function') {
self.onAction(self.actionType);
}
};
return self;
});
// EventPopup class
var EventPopup = Container.expand(function () {
var self = Container.call(this);
self.text = '';
self.onAcknowledge = null;
self.init = function (text, onAcknowledge) {
self.text = text;
self.onAcknowledge = onAcknowledge;
var bg = self.attachAsset('event', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.5,
scaleY: 1.5
});
self.bg = bg;
var txt = new Text2(text, {
size: 60,
fill: "#fff",
font: "Tahoma"
});
txt.anchor.set(0.5, 0.5);
txt.y = 0;
self.addChild(txt);
self.txt = txt;
};
self.down = function (x, y, obj) {
if (typeof self.onAcknowledge === 'function') {
self.onAcknowledge();
}
self.destroy();
};
return self;
});
// Office class (player or rival)
var Office = Container.expand(function () {
var self = Container.call(this);
self.level = 1;
self.employees = 1;
self.upgrades = 0;
self.marketing = 0;
self.cash = 1000;
self.revenue = 0;
self.expenses = 0;
self.isRival = false;
self.updateStats = function (stats) {
if (stats.level !== undefined) self.level = stats.level;
if (stats.employees !== undefined) self.employees = stats.employees;
if (stats.upgrades !== undefined) self.upgrades = stats.upgrades;
if (stats.marketing !== undefined) self.marketing = stats.marketing;
if (stats.cash !== undefined) self.cash = stats.cash;
};
self.getRevenue = function () {
// Revenue: base + employees + upgrades + marketing
return 200 * self.level + 120 * self.employees + 180 * self.upgrades + 100 * self.marketing;
};
self.getExpenses = function () {
// Expenses: base + employees + upgrades + marketing
return 100 * self.level + 80 * self.employees + 60 * self.upgrades + 40 * self.marketing;
};
self.getScore = function () {
// Score: cash + revenue - expenses
return self.cash + self.getRevenue() - self.getExpenses();
};
self.attachVisuals = function () {
var assetId = self.isRival ? 'rivalOffice' : 'office';
var officeAsset = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
self.officeAsset = officeAsset;
};
self.flash = function (color) {
LK.effects.flashObject(self, color, 600);
};
self.attachVisuals();
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0xf4f6fa
});
/****
* Game Code
****/
// Event icon
// Expand icon
// Marketing icon
// Upgrade icon
// Employee icon
// Rival office
// Office (main player asset)
// --- Game State ---
var round = 1;
var maxRounds = 30;
var milestoneCash = 10000;
var milestoneEmployees = 15;
var milestoneLevel = 5;
var player, rival;
var actionButtons = [];
var infoTexts = {};
var eventPopup = null;
var isActionPhase = true;
var lastEvent = null;
var gameOver = false;
// --- UI Setup ---
// Info text for round
var roundTxt = new Text2('Round 1', {
size: 80,
fill: "#222"
});
roundTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(roundTxt);
// Player cash
var cashTxt = new Text2('$1000', {
size: 60,
fill: 0x2ECC71
});
cashTxt.anchor.set(0.5, 0);
cashTxt.y = 90;
LK.gui.top.addChild(cashTxt);
// Rival progress
var rivalTxt = new Text2('Rival: $1000', {
size: 48,
fill: 0xE74C3C
});
rivalTxt.anchor.set(0.5, 0);
rivalTxt.y = 160;
LK.gui.top.addChild(rivalTxt);
// --- Offices ---
player = new Office();
player.x = 2048 / 2 - 400;
player.y = 1100;
game.addChild(player);
rival = new Office();
rival.isRival = true;
rival.x = 2048 / 2 + 400;
rival.y = 1100;
game.addChild(rival);
// --- Action Buttons ---
var actions = [{
type: 'hire',
label: 'Hire',
icon: 'employee'
}, {
type: 'upgrade',
label: 'Upgrade',
icon: 'upgrade'
}, {
type: 'marketing',
label: 'Marketing',
icon: 'marketing'
}, {
type: 'expand',
label: 'Expand',
icon: 'expand'
}];
for (var i = 0; i < actions.length; i++) {
var ab = new ActionButton();
ab.init(actions[i].type, actions[i].label, actions[i].icon, handleAction);
ab.x = 2048 / 2 - 300 + i * 200;
ab.y = 1800;
game.addChild(ab);
actionButtons.push(ab);
}
// --- Info Texts (player stats) ---
var statsTxt = new Text2('', {
size: 48,
fill: 0x34495E
});
statsTxt.anchor.set(0.5, 0);
statsTxt.x = 2048 / 2 - 400;
statsTxt.y = 1350;
game.addChild(statsTxt);
var rivalStatsTxt = new Text2('', {
size: 48,
fill: 0xC0392B
});
rivalStatsTxt.anchor.set(0.5, 0);
rivalStatsTxt.x = 2048 / 2 + 400;
rivalStatsTxt.y = 1350;
game.addChild(rivalStatsTxt);
// --- Event Popup (hidden by default) ---
function showEventPopup(text, onAcknowledge) {
if (eventPopup) eventPopup.destroy();
eventPopup = new EventPopup();
eventPopup.init(text, onAcknowledge);
eventPopup.x = 2048 / 2;
eventPopup.y = 900;
game.addChild(eventPopup);
}
// --- Game Logic ---
function updateUI() {
roundTxt.setText('Round ' + round);
cashTxt.setText('$' + player.cash);
rivalTxt.setText('Rival: $' + rival.cash);
statsTxt.setText('Lvl: ' + player.level + ' Emp: ' + player.employees + ' Upg: ' + player.upgrades + ' Mkt: ' + player.marketing + '\nRevenue: $' + player.getRevenue() + ' Expenses: $' + player.getExpenses());
rivalStatsTxt.setText('Lvl: ' + rival.level + ' Emp: ' + rival.employees + ' Upg: ' + rival.upgrades + ' Mkt: ' + rival.marketing + '\nRevenue: $' + rival.getRevenue() + ' Expenses: $' + rival.getExpenses());
}
function handleAction(actionType) {
if (!isActionPhase || gameOver) return;
var cost = 0;
var msg = '';
if (actionType === 'hire') {
cost = 300 + 50 * player.employees;
if (player.cash >= cost) {
player.employees += 1;
player.cash -= cost;
msg = 'Hired 1 employee for $' + cost + '!';
} else {
msg = 'Not enough cash to hire!';
}
} else if (actionType === 'upgrade') {
cost = 500 + 100 * player.upgrades;
if (player.cash >= cost) {
player.upgrades += 1;
player.cash -= cost;
msg = 'Upgraded efficiency for $' + cost + '!';
} else {
msg = 'Not enough cash to upgrade!';
}
} else if (actionType === 'marketing') {
cost = 400 + 80 * player.marketing;
if (player.cash >= cost) {
player.marketing += 1;
player.cash -= cost;
msg = 'Launched marketing for $' + cost + '!';
} else {
msg = 'Not enough cash for marketing!';
}
} else if (actionType === 'expand') {
cost = 1000 + 200 * player.level;
if (player.cash >= cost) {
player.level += 1;
player.cash -= cost;
msg = 'Expanded office for $' + cost + '!';
} else {
msg = 'Not enough cash to expand!';
}
}
updateUI();
if (msg) {
player.flash(0x2ecc71);
showEventPopup(msg, function () {
isActionPhase = false;
nextPhase();
});
}
}
function nextPhase() {
// After action, process round: revenue, expenses, events, rival
if (gameOver) return;
// 1. Player revenue/expenses
var revenue = player.getRevenue();
var expenses = player.getExpenses();
player.cash += revenue - expenses;
// 2. Rival AI: simple catch-up logic
var rivalAction = Math.floor(Math.random() * 4);
if (rivalAction === 0) {
rival.employees += 1;
} else if (rivalAction === 1) {
rival.upgrades += 1;
} else if (rivalAction === 2) {
rival.marketing += 1;
} else if (rivalAction === 3) {
rival.level += 1;
}
rival.cash += rival.getRevenue() - rival.getExpenses();
// 3. Random event
var eventRoll = Math.random();
var eventMsg = '';
var eventEffect = null;
if (eventRoll < 0.18) {
// Good event
var bonus = 400 + Math.floor(Math.random() * 200);
eventMsg = 'Viral Success! You gain $' + bonus;
eventEffect = function eventEffect() {
player.cash += bonus;
};
} else if (eventRoll < 0.36) {
// Bad event
var loss = 300 + Math.floor(Math.random() * 200);
eventMsg = 'Unexpected Expense! Lose $' + loss;
eventEffect = function eventEffect() {
player.cash -= loss;
};
} else if (eventRoll < 0.48) {
// Neutral event
eventMsg = 'Market is stable. No major events this round.';
eventEffect = function eventEffect() {};
} else if (eventRoll < 0.60) {
// Rival gets boost
var rivalBonus = 400 + Math.floor(Math.random() * 200);
eventMsg = 'Rival gets a boost! Rival gains $' + rivalBonus;
eventEffect = function eventEffect() {
rival.cash += rivalBonus;
};
} else if (eventRoll < 0.70) {
// Employee leaves
if (player.employees > 1) {
eventMsg = 'An employee left! -1 employee';
eventEffect = function eventEffect() {
player.employees -= 1;
};
}
} else if (eventRoll < 0.80) {
// Free upgrade
eventMsg = 'Efficiency breakthrough! Free upgrade!';
eventEffect = function eventEffect() {
player.upgrades += 1;
};
} else if (eventRoll < 0.90) {
// Rival loses cash
var rivalLoss = 300 + Math.floor(Math.random() * 200);
eventMsg = 'Rival faces setback! Rival loses $' + rivalLoss;
eventEffect = function eventEffect() {
rival.cash -= rivalLoss;
};
} else {
// Nothing
eventMsg = 'Quiet round. Focus on your strategy!';
eventEffect = function eventEffect() {};
}
// 4. Update UI and show event
updateUI();
// 5. Check for win/lose
var win = false,
lose = false,
winMsg = '',
loseMsg = '';
if (player.cash >= milestoneCash || player.employees >= milestoneEmployees || player.level >= milestoneLevel) {
win = true;
winMsg = 'Congratulations! You built a market leader startup!';
} else if (player.cash < 0) {
lose = true;
loseMsg = 'You went bankrupt! Game Over.';
} else if (rival.cash >= milestoneCash || rival.employees >= milestoneEmployees || rival.level >= milestoneLevel) {
lose = true;
loseMsg = 'Rival overtook you! Game Over.';
} else if (round >= maxRounds) {
if (player.cash > rival.cash) {
win = true;
winMsg = 'You survived 30 rounds and outperformed your rival!';
} else {
lose = true;
loseMsg = 'Rival outperformed you after 30 rounds!';
}
}
if (win) {
gameOver = true;
LK.showYouWin();
return;
}
if (lose) {
gameOver = true;
LK.showGameOver();
return;
}
// 6. Show event popup, then advance round
showEventPopup(eventMsg, function () {
if (typeof eventEffect === 'function') eventEffect();
round += 1;
updateUI();
isActionPhase = true;
});
}
// --- Game Update Loop ---
game.update = function () {
// No per-frame logic needed for MVP
};
// --- Start Game ---
updateUI();
isActionPhase = true; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// ActionButton class
var ActionButton = Container.expand(function () {
var self = Container.call(this);
self.actionType = '';
self.label = '';
self.iconId = '';
self.onAction = null;
self.init = function (actionType, label, iconId, onAction) {
self.actionType = actionType;
self.label = label;
self.iconId = iconId;
self.onAction = onAction;
var icon = self.attachAsset(iconId, {
anchorX: 0.5,
anchorY: 0.5
});
self.icon = icon;
var txt = new Text2(label, {
size: 48,
fill: "#fff"
});
txt.anchor.set(0.5, 0);
txt.y = 50;
self.addChild(txt);
self.txt = txt;
};
// Touch/click event
self.down = function (x, y, obj) {
if (typeof self.onAction === 'function') {
self.onAction(self.actionType);
}
};
return self;
});
// EventPopup class
var EventPopup = Container.expand(function () {
var self = Container.call(this);
self.text = '';
self.onAcknowledge = null;
self.init = function (text, onAcknowledge) {
self.text = text;
self.onAcknowledge = onAcknowledge;
var bg = self.attachAsset('event', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.5,
scaleY: 1.5
});
self.bg = bg;
var txt = new Text2(text, {
size: 60,
fill: "#fff",
font: "Tahoma"
});
txt.anchor.set(0.5, 0.5);
txt.y = 0;
self.addChild(txt);
self.txt = txt;
};
self.down = function (x, y, obj) {
if (typeof self.onAcknowledge === 'function') {
self.onAcknowledge();
}
self.destroy();
};
return self;
});
// Office class (player or rival)
var Office = Container.expand(function () {
var self = Container.call(this);
self.level = 1;
self.employees = 1;
self.upgrades = 0;
self.marketing = 0;
self.cash = 1000;
self.revenue = 0;
self.expenses = 0;
self.isRival = false;
self.updateStats = function (stats) {
if (stats.level !== undefined) self.level = stats.level;
if (stats.employees !== undefined) self.employees = stats.employees;
if (stats.upgrades !== undefined) self.upgrades = stats.upgrades;
if (stats.marketing !== undefined) self.marketing = stats.marketing;
if (stats.cash !== undefined) self.cash = stats.cash;
};
self.getRevenue = function () {
// Revenue: base + employees + upgrades + marketing
return 200 * self.level + 120 * self.employees + 180 * self.upgrades + 100 * self.marketing;
};
self.getExpenses = function () {
// Expenses: base + employees + upgrades + marketing
return 100 * self.level + 80 * self.employees + 60 * self.upgrades + 40 * self.marketing;
};
self.getScore = function () {
// Score: cash + revenue - expenses
return self.cash + self.getRevenue() - self.getExpenses();
};
self.attachVisuals = function () {
var assetId = self.isRival ? 'rivalOffice' : 'office';
var officeAsset = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
self.officeAsset = officeAsset;
};
self.flash = function (color) {
LK.effects.flashObject(self, color, 600);
};
self.attachVisuals();
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0xf4f6fa
});
/****
* Game Code
****/
// Event icon
// Expand icon
// Marketing icon
// Upgrade icon
// Employee icon
// Rival office
// Office (main player asset)
// --- Game State ---
var round = 1;
var maxRounds = 30;
var milestoneCash = 10000;
var milestoneEmployees = 15;
var milestoneLevel = 5;
var player, rival;
var actionButtons = [];
var infoTexts = {};
var eventPopup = null;
var isActionPhase = true;
var lastEvent = null;
var gameOver = false;
// --- UI Setup ---
// Info text for round
var roundTxt = new Text2('Round 1', {
size: 80,
fill: "#222"
});
roundTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(roundTxt);
// Player cash
var cashTxt = new Text2('$1000', {
size: 60,
fill: 0x2ECC71
});
cashTxt.anchor.set(0.5, 0);
cashTxt.y = 90;
LK.gui.top.addChild(cashTxt);
// Rival progress
var rivalTxt = new Text2('Rival: $1000', {
size: 48,
fill: 0xE74C3C
});
rivalTxt.anchor.set(0.5, 0);
rivalTxt.y = 160;
LK.gui.top.addChild(rivalTxt);
// --- Offices ---
player = new Office();
player.x = 2048 / 2 - 400;
player.y = 1100;
game.addChild(player);
rival = new Office();
rival.isRival = true;
rival.x = 2048 / 2 + 400;
rival.y = 1100;
game.addChild(rival);
// --- Action Buttons ---
var actions = [{
type: 'hire',
label: 'Hire',
icon: 'employee'
}, {
type: 'upgrade',
label: 'Upgrade',
icon: 'upgrade'
}, {
type: 'marketing',
label: 'Marketing',
icon: 'marketing'
}, {
type: 'expand',
label: 'Expand',
icon: 'expand'
}];
for (var i = 0; i < actions.length; i++) {
var ab = new ActionButton();
ab.init(actions[i].type, actions[i].label, actions[i].icon, handleAction);
ab.x = 2048 / 2 - 300 + i * 200;
ab.y = 1800;
game.addChild(ab);
actionButtons.push(ab);
}
// --- Info Texts (player stats) ---
var statsTxt = new Text2('', {
size: 48,
fill: 0x34495E
});
statsTxt.anchor.set(0.5, 0);
statsTxt.x = 2048 / 2 - 400;
statsTxt.y = 1350;
game.addChild(statsTxt);
var rivalStatsTxt = new Text2('', {
size: 48,
fill: 0xC0392B
});
rivalStatsTxt.anchor.set(0.5, 0);
rivalStatsTxt.x = 2048 / 2 + 400;
rivalStatsTxt.y = 1350;
game.addChild(rivalStatsTxt);
// --- Event Popup (hidden by default) ---
function showEventPopup(text, onAcknowledge) {
if (eventPopup) eventPopup.destroy();
eventPopup = new EventPopup();
eventPopup.init(text, onAcknowledge);
eventPopup.x = 2048 / 2;
eventPopup.y = 900;
game.addChild(eventPopup);
}
// --- Game Logic ---
function updateUI() {
roundTxt.setText('Round ' + round);
cashTxt.setText('$' + player.cash);
rivalTxt.setText('Rival: $' + rival.cash);
statsTxt.setText('Lvl: ' + player.level + ' Emp: ' + player.employees + ' Upg: ' + player.upgrades + ' Mkt: ' + player.marketing + '\nRevenue: $' + player.getRevenue() + ' Expenses: $' + player.getExpenses());
rivalStatsTxt.setText('Lvl: ' + rival.level + ' Emp: ' + rival.employees + ' Upg: ' + rival.upgrades + ' Mkt: ' + rival.marketing + '\nRevenue: $' + rival.getRevenue() + ' Expenses: $' + rival.getExpenses());
}
function handleAction(actionType) {
if (!isActionPhase || gameOver) return;
var cost = 0;
var msg = '';
if (actionType === 'hire') {
cost = 300 + 50 * player.employees;
if (player.cash >= cost) {
player.employees += 1;
player.cash -= cost;
msg = 'Hired 1 employee for $' + cost + '!';
} else {
msg = 'Not enough cash to hire!';
}
} else if (actionType === 'upgrade') {
cost = 500 + 100 * player.upgrades;
if (player.cash >= cost) {
player.upgrades += 1;
player.cash -= cost;
msg = 'Upgraded efficiency for $' + cost + '!';
} else {
msg = 'Not enough cash to upgrade!';
}
} else if (actionType === 'marketing') {
cost = 400 + 80 * player.marketing;
if (player.cash >= cost) {
player.marketing += 1;
player.cash -= cost;
msg = 'Launched marketing for $' + cost + '!';
} else {
msg = 'Not enough cash for marketing!';
}
} else if (actionType === 'expand') {
cost = 1000 + 200 * player.level;
if (player.cash >= cost) {
player.level += 1;
player.cash -= cost;
msg = 'Expanded office for $' + cost + '!';
} else {
msg = 'Not enough cash to expand!';
}
}
updateUI();
if (msg) {
player.flash(0x2ecc71);
showEventPopup(msg, function () {
isActionPhase = false;
nextPhase();
});
}
}
function nextPhase() {
// After action, process round: revenue, expenses, events, rival
if (gameOver) return;
// 1. Player revenue/expenses
var revenue = player.getRevenue();
var expenses = player.getExpenses();
player.cash += revenue - expenses;
// 2. Rival AI: simple catch-up logic
var rivalAction = Math.floor(Math.random() * 4);
if (rivalAction === 0) {
rival.employees += 1;
} else if (rivalAction === 1) {
rival.upgrades += 1;
} else if (rivalAction === 2) {
rival.marketing += 1;
} else if (rivalAction === 3) {
rival.level += 1;
}
rival.cash += rival.getRevenue() - rival.getExpenses();
// 3. Random event
var eventRoll = Math.random();
var eventMsg = '';
var eventEffect = null;
if (eventRoll < 0.18) {
// Good event
var bonus = 400 + Math.floor(Math.random() * 200);
eventMsg = 'Viral Success! You gain $' + bonus;
eventEffect = function eventEffect() {
player.cash += bonus;
};
} else if (eventRoll < 0.36) {
// Bad event
var loss = 300 + Math.floor(Math.random() * 200);
eventMsg = 'Unexpected Expense! Lose $' + loss;
eventEffect = function eventEffect() {
player.cash -= loss;
};
} else if (eventRoll < 0.48) {
// Neutral event
eventMsg = 'Market is stable. No major events this round.';
eventEffect = function eventEffect() {};
} else if (eventRoll < 0.60) {
// Rival gets boost
var rivalBonus = 400 + Math.floor(Math.random() * 200);
eventMsg = 'Rival gets a boost! Rival gains $' + rivalBonus;
eventEffect = function eventEffect() {
rival.cash += rivalBonus;
};
} else if (eventRoll < 0.70) {
// Employee leaves
if (player.employees > 1) {
eventMsg = 'An employee left! -1 employee';
eventEffect = function eventEffect() {
player.employees -= 1;
};
}
} else if (eventRoll < 0.80) {
// Free upgrade
eventMsg = 'Efficiency breakthrough! Free upgrade!';
eventEffect = function eventEffect() {
player.upgrades += 1;
};
} else if (eventRoll < 0.90) {
// Rival loses cash
var rivalLoss = 300 + Math.floor(Math.random() * 200);
eventMsg = 'Rival faces setback! Rival loses $' + rivalLoss;
eventEffect = function eventEffect() {
rival.cash -= rivalLoss;
};
} else {
// Nothing
eventMsg = 'Quiet round. Focus on your strategy!';
eventEffect = function eventEffect() {};
}
// 4. Update UI and show event
updateUI();
// 5. Check for win/lose
var win = false,
lose = false,
winMsg = '',
loseMsg = '';
if (player.cash >= milestoneCash || player.employees >= milestoneEmployees || player.level >= milestoneLevel) {
win = true;
winMsg = 'Congratulations! You built a market leader startup!';
} else if (player.cash < 0) {
lose = true;
loseMsg = 'You went bankrupt! Game Over.';
} else if (rival.cash >= milestoneCash || rival.employees >= milestoneEmployees || rival.level >= milestoneLevel) {
lose = true;
loseMsg = 'Rival overtook you! Game Over.';
} else if (round >= maxRounds) {
if (player.cash > rival.cash) {
win = true;
winMsg = 'You survived 30 rounds and outperformed your rival!';
} else {
lose = true;
loseMsg = 'Rival outperformed you after 30 rounds!';
}
}
if (win) {
gameOver = true;
LK.showYouWin();
return;
}
if (lose) {
gameOver = true;
LK.showGameOver();
return;
}
// 6. Show event popup, then advance round
showEventPopup(eventMsg, function () {
if (typeof eventEffect === 'function') eventEffect();
round += 1;
updateUI();
isActionPhase = true;
});
}
// --- Game Update Loop ---
game.update = function () {
// No per-frame logic needed for MVP
};
// --- Start Game ---
updateUI();
isActionPhase = true;