/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Happiness Bar Class
var HappinessBar = Container.expand(function () {
var self = Container.call(this);
// Attach background
self.bg = self.attachAsset('happyBarBg', {
anchorX: 0,
anchorY: 0.5
});
// Attach fill
self.fill = self.attachAsset('happyBarFill', {
anchorX: 0,
anchorY: 0.5
});
// Set value (0-100)
self.setValue = function (val) {
if (val < 0) val = 0;
if (val > 100) val = 100;
self.value = val;
self.fill.width = 8 * val;
};
// Set initial value
self.setValue(100);
return self;
});
/****
* Game Data
****/
// Each scenario: { text: String, options: [ { text: String, happiness: Number, next: Number|null, ending: String|null } ] }
// If next is null and ending is not null, it's an ending.
// Option Button Class
var OptionButton = Container.expand(function () {
var self = Container.call(this);
// Default state
self.selected = false;
self.disabled = false;
// Attach background
self.bg = self.attachAsset('optionBtn', {
anchorX: 0.5,
anchorY: 0.5
});
// Attach text
self.label = new Text2('', {
size: 70,
fill: 0x222222,
wordWrap: true,
wordWrapWidth: 1100
});
self.label.anchor.set(0.5, 0.5);
self.addChild(self.label);
// Set label text
self.setText = function (txt) {
self.label.setText(txt);
};
// Set selected state
self.setSelected = function (selected) {
self.selected = selected;
if (self.selected) {
self.bg.assetId = 'optionBtnSelected';
self.bg.setAsset('optionBtnSelected');
} else {
self.bg.assetId = 'optionBtn';
self.bg.setAsset('optionBtn');
}
};
// Set disabled state
self.setDisabled = function (disabled) {
self.disabled = disabled;
if (self.disabled) {
self.bg.assetId = 'optionBtnDisabled';
self.bg.setAsset('optionBtnDisabled');
} else {
self.setSelected(self.selected);
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0xfafafa
});
/****
* Game Code
****/
// Background music (loops)
// Sound for scenario transition
// Sound for incorrect choice
// Sound for correct choice
// If next is null and ending is not null, it's an ending.
// Each scenario: { text: String, options: [ { text: String, happiness: Number, next: Number|null, ending: String|null } ] }
/****
* Game Data
****/
// Happiness bar fill
// Happiness bar background
// Option button (disabled)
// Option button (selected)
// Option button
// Character: The girl
// Game state
var scenarios = [{
text: "It's the first day of high school. The girl feels nervous and alone. What should she do?",
options: [{
text: "Try to talk to a classmate and make a friend.",
happiness: +10,
next: 1
}, {
text: "Stay quiet and hope someone approaches her.",
happiness: -5,
next: 2
}, {
text: "Skip class and go home.",
happiness: -20,
next: null,
ending: "She misses important introductions and feels even more isolated. Her happiness drops."
}]
}, {
text: "She made a new friend! But now she has a lot of homework and her friend invites her out.",
options: [{
text: "Go out with her friend and do homework later.",
happiness: +5,
next: 3
}, {
text: "Politely decline and focus on homework.",
happiness: +0,
next: 4
}, {
text: "Lie to her parents and sneak out.",
happiness: -10,
next: null,
ending: "Her parents find out and she loses their trust. She feels guilty."
}]
}, {
text: "She waits, but no one talks to her. She feels sad. What should she do next?",
options: [{
text: "Try to join a club after school.",
happiness: +10,
next: 5
}, {
text: "Go home and cry.",
happiness: -10,
next: null,
ending: "She feels alone and her confidence drops."
}]
}, {
text: "She had fun with her friend, but now it's late and homework isn't done.",
options: [{
text: "Stay up late to finish homework.",
happiness: -5,
next: 6
}, {
text: "Go to bed and hope for the best.",
happiness: -10,
next: null,
ending: "She gets in trouble at school for not doing homework."
}]
}, {
text: "She finishes her homework and feels accomplished, but her friend is upset.",
options: [{
text: "Explain to her friend why homework was important.",
happiness: +5,
next: 7
}, {
text: "Ignore her friend's feelings.",
happiness: -10,
next: null,
ending: "Her friend feels hurt and distances herself."
}]
}, {
text: "She joins a club and meets new people. She feels happier.",
options: [{
text: "Continue attending the club.",
happiness: +10,
next: 7
}, {
text: "Quit after one day.",
happiness: -10,
next: null,
ending: "She misses out on new friendships."
}]
}, {
text: "She is tired the next day and can't focus in class.",
options: [{
text: "Ask the teacher for help.",
happiness: +5,
next: 7
}, {
text: "Try to get through the day alone.",
happiness: -5,
next: null,
ending: "She struggles and feels overwhelmed."
}]
}, {
text: "Her parents notice she's stressed. They ask if she's okay.",
options: [{
text: "Open up to her parents.",
happiness: +10,
next: null,
ending: "Her parents support her and she feels loved. She is happy!"
}, {
text: "Keep her feelings to herself.",
happiness: -10,
next: null,
ending: "She feels alone, but hopes things will get better."
}]
}];
var currentScenario = 0;
var happiness = 100;
var optionButtons = [];
var scenarioText = null;
var girlSprite = null;
var happinessBar = null;
var endingText = null;
var canSelect = true;
// Add girl sprite (centered horizontally, upper part of screen)
girlSprite = LK.getAsset('girl', {
anchorX: 0.5,
anchorY: 0,
x: 2048 / 2,
y: 180
});
game.addChild(girlSprite);
// Add scenario text (centered, below girl)
scenarioText = new Text2('', {
size: 80,
fill: 0x333333,
wordWrap: true,
wordWrapWidth: 1800
});
scenarioText.anchor.set(0.5, 0);
scenarioText.x = 2048 / 2;
scenarioText.y = 180 + girlSprite.height + 60;
game.addChild(scenarioText);
// Add happiness bar (centered, above girl)
happinessBar = new HappinessBar();
happinessBar.x = (2048 - 800) / 2;
happinessBar.y = 120;
game.addChild(happinessBar);
// Add happiness label
var happyLabel = new Text2('Happiness', {
size: 48,
fill: 0x666666
});
happyLabel.anchor.set(0.5, 1);
happyLabel.x = 2048 / 2;
happyLabel.y = happinessBar.y - 10;
game.addChild(happyLabel);
// Add option buttons (max 3 per scenario)
for (var i = 0; i < 3; i++) {
var btn = new OptionButton();
btn.x = 2048 / 2;
btn.y = 1200 + i * 260;
btn.visible = false;
(function (idx) {
btn.down = function (x, y, obj) {
if (!canSelect || btn.disabled) return;
selectOption(idx);
};
})(i);
game.addChild(btn);
optionButtons.push(btn);
}
// Add ending text (hidden by default)
endingText = new Text2('', {
size: 90,
fill: 0xD32F2F,
wordWrap: true,
wordWrapWidth: 1800
});
endingText.anchor.set(0.5, 0.5);
endingText.x = 2048 / 2;
endingText.y = 2732 / 2;
endingText.visible = false;
game.addChild(endingText);
// Show scenario
function showScenario(idx) {
canSelect = true;
endingText.visible = false;
var sc = scenarios[idx];
scenarioText.setText(sc.text);
// Show options
for (var i = 0; i < optionButtons.length; i++) {
if (sc.options[i]) {
optionButtons[i].visible = true;
optionButtons[i].setText(sc.options[i].text);
optionButtons[i].setSelected(false);
optionButtons[i].setDisabled(false);
} else {
optionButtons[i].visible = false;
}
}
}
// Handle option selection
function selectOption(optIdx) {
canSelect = false;
var sc = scenarios[currentScenario];
var opt = sc.options[optIdx];
// Animate button selection
for (var i = 0; i < optionButtons.length; i++) {
optionButtons[i].setDisabled(true);
optionButtons[i].setSelected(i === optIdx);
}
// Play sound for correct/incorrect choice
if (opt.happiness >= 0) {
LK.getSound('choice_correct').play();
} else {
LK.getSound('choice_wrong').play();
}
// Animate happiness bar
var newHappiness = happiness + opt.happiness;
if (newHappiness > 100) newHappiness = 100;
if (newHappiness < 0) newHappiness = 0;
tween(happinessBar.fill, {
width: 8 * newHappiness
}, {
duration: 400,
easing: tween.cubicOut
});
happiness = newHappiness;
// Animate girl (flash color if happiness drops)
if (opt.happiness < 0) {
tween(girlSprite, {
tint: 0xd32f2f
}, {
duration: 200,
onFinish: function onFinish() {
tween(girlSprite, {
tint: 0xf7b6d2
}, {
duration: 400
});
}
});
} else if (opt.happiness > 0) {
tween(girlSprite, {
tint: 0x81c784
}, {
duration: 200,
onFinish: function onFinish() {
tween(girlSprite, {
tint: 0xf7b6d2
}, {
duration: 400
});
}
});
}
// After short delay, go to next scenario or ending
LK.setTimeout(function () {
// Play scenario transition sound if not ending
if (!opt.ending) {
LK.getSound('scenario_next').play();
}
if (opt.ending) {
showEnding(opt.ending);
} else if (opt.next !== undefined && opt.next !== null) {
currentScenario = opt.next;
showScenario(currentScenario);
} else {
// No next, no ending: treat as ending
showEnding("The story ends here.");
}
}, 700);
}
// Show ending
function showEnding(txt) {
for (var i = 0; i < optionButtons.length; i++) {
optionButtons[i].visible = false;
}
scenarioText.setText('');
endingText.setText(txt + "\n\nFinal Happiness: " + happiness);
endingText.visible = true;
// Stop background music
LK.stopMusic();
// If happiness is high, show win, else show game over
LK.setTimeout(function () {
if (happiness >= 60) {
LK.showYouWin();
} else {
LK.showGameOver();
}
}, 1800);
}
// Start game
function startGame() {
currentScenario = 0;
happiness = 100;
happinessBar.setValue(happiness);
girlSprite.tint = 0xf7b6d2;
showScenario(currentScenario);
// Play background music (looping)
LK.playMusic('bgm_story');
}
startGame();
// No dragging or move events needed for this game
// Update happiness bar value every frame (in case of tween)
game.update = function () {
// Clamp fill width
if (happinessBar.fill.width < 0) happinessBar.fill.width = 0;
if (happinessBar.fill.width > 800) happinessBar.fill.width = 800;
// Optionally, could animate other things here
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Happiness Bar Class
var HappinessBar = Container.expand(function () {
var self = Container.call(this);
// Attach background
self.bg = self.attachAsset('happyBarBg', {
anchorX: 0,
anchorY: 0.5
});
// Attach fill
self.fill = self.attachAsset('happyBarFill', {
anchorX: 0,
anchorY: 0.5
});
// Set value (0-100)
self.setValue = function (val) {
if (val < 0) val = 0;
if (val > 100) val = 100;
self.value = val;
self.fill.width = 8 * val;
};
// Set initial value
self.setValue(100);
return self;
});
/****
* Game Data
****/
// Each scenario: { text: String, options: [ { text: String, happiness: Number, next: Number|null, ending: String|null } ] }
// If next is null and ending is not null, it's an ending.
// Option Button Class
var OptionButton = Container.expand(function () {
var self = Container.call(this);
// Default state
self.selected = false;
self.disabled = false;
// Attach background
self.bg = self.attachAsset('optionBtn', {
anchorX: 0.5,
anchorY: 0.5
});
// Attach text
self.label = new Text2('', {
size: 70,
fill: 0x222222,
wordWrap: true,
wordWrapWidth: 1100
});
self.label.anchor.set(0.5, 0.5);
self.addChild(self.label);
// Set label text
self.setText = function (txt) {
self.label.setText(txt);
};
// Set selected state
self.setSelected = function (selected) {
self.selected = selected;
if (self.selected) {
self.bg.assetId = 'optionBtnSelected';
self.bg.setAsset('optionBtnSelected');
} else {
self.bg.assetId = 'optionBtn';
self.bg.setAsset('optionBtn');
}
};
// Set disabled state
self.setDisabled = function (disabled) {
self.disabled = disabled;
if (self.disabled) {
self.bg.assetId = 'optionBtnDisabled';
self.bg.setAsset('optionBtnDisabled');
} else {
self.setSelected(self.selected);
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0xfafafa
});
/****
* Game Code
****/
// Background music (loops)
// Sound for scenario transition
// Sound for incorrect choice
// Sound for correct choice
// If next is null and ending is not null, it's an ending.
// Each scenario: { text: String, options: [ { text: String, happiness: Number, next: Number|null, ending: String|null } ] }
/****
* Game Data
****/
// Happiness bar fill
// Happiness bar background
// Option button (disabled)
// Option button (selected)
// Option button
// Character: The girl
// Game state
var scenarios = [{
text: "It's the first day of high school. The girl feels nervous and alone. What should she do?",
options: [{
text: "Try to talk to a classmate and make a friend.",
happiness: +10,
next: 1
}, {
text: "Stay quiet and hope someone approaches her.",
happiness: -5,
next: 2
}, {
text: "Skip class and go home.",
happiness: -20,
next: null,
ending: "She misses important introductions and feels even more isolated. Her happiness drops."
}]
}, {
text: "She made a new friend! But now she has a lot of homework and her friend invites her out.",
options: [{
text: "Go out with her friend and do homework later.",
happiness: +5,
next: 3
}, {
text: "Politely decline and focus on homework.",
happiness: +0,
next: 4
}, {
text: "Lie to her parents and sneak out.",
happiness: -10,
next: null,
ending: "Her parents find out and she loses their trust. She feels guilty."
}]
}, {
text: "She waits, but no one talks to her. She feels sad. What should she do next?",
options: [{
text: "Try to join a club after school.",
happiness: +10,
next: 5
}, {
text: "Go home and cry.",
happiness: -10,
next: null,
ending: "She feels alone and her confidence drops."
}]
}, {
text: "She had fun with her friend, but now it's late and homework isn't done.",
options: [{
text: "Stay up late to finish homework.",
happiness: -5,
next: 6
}, {
text: "Go to bed and hope for the best.",
happiness: -10,
next: null,
ending: "She gets in trouble at school for not doing homework."
}]
}, {
text: "She finishes her homework and feels accomplished, but her friend is upset.",
options: [{
text: "Explain to her friend why homework was important.",
happiness: +5,
next: 7
}, {
text: "Ignore her friend's feelings.",
happiness: -10,
next: null,
ending: "Her friend feels hurt and distances herself."
}]
}, {
text: "She joins a club and meets new people. She feels happier.",
options: [{
text: "Continue attending the club.",
happiness: +10,
next: 7
}, {
text: "Quit after one day.",
happiness: -10,
next: null,
ending: "She misses out on new friendships."
}]
}, {
text: "She is tired the next day and can't focus in class.",
options: [{
text: "Ask the teacher for help.",
happiness: +5,
next: 7
}, {
text: "Try to get through the day alone.",
happiness: -5,
next: null,
ending: "She struggles and feels overwhelmed."
}]
}, {
text: "Her parents notice she's stressed. They ask if she's okay.",
options: [{
text: "Open up to her parents.",
happiness: +10,
next: null,
ending: "Her parents support her and she feels loved. She is happy!"
}, {
text: "Keep her feelings to herself.",
happiness: -10,
next: null,
ending: "She feels alone, but hopes things will get better."
}]
}];
var currentScenario = 0;
var happiness = 100;
var optionButtons = [];
var scenarioText = null;
var girlSprite = null;
var happinessBar = null;
var endingText = null;
var canSelect = true;
// Add girl sprite (centered horizontally, upper part of screen)
girlSprite = LK.getAsset('girl', {
anchorX: 0.5,
anchorY: 0,
x: 2048 / 2,
y: 180
});
game.addChild(girlSprite);
// Add scenario text (centered, below girl)
scenarioText = new Text2('', {
size: 80,
fill: 0x333333,
wordWrap: true,
wordWrapWidth: 1800
});
scenarioText.anchor.set(0.5, 0);
scenarioText.x = 2048 / 2;
scenarioText.y = 180 + girlSprite.height + 60;
game.addChild(scenarioText);
// Add happiness bar (centered, above girl)
happinessBar = new HappinessBar();
happinessBar.x = (2048 - 800) / 2;
happinessBar.y = 120;
game.addChild(happinessBar);
// Add happiness label
var happyLabel = new Text2('Happiness', {
size: 48,
fill: 0x666666
});
happyLabel.anchor.set(0.5, 1);
happyLabel.x = 2048 / 2;
happyLabel.y = happinessBar.y - 10;
game.addChild(happyLabel);
// Add option buttons (max 3 per scenario)
for (var i = 0; i < 3; i++) {
var btn = new OptionButton();
btn.x = 2048 / 2;
btn.y = 1200 + i * 260;
btn.visible = false;
(function (idx) {
btn.down = function (x, y, obj) {
if (!canSelect || btn.disabled) return;
selectOption(idx);
};
})(i);
game.addChild(btn);
optionButtons.push(btn);
}
// Add ending text (hidden by default)
endingText = new Text2('', {
size: 90,
fill: 0xD32F2F,
wordWrap: true,
wordWrapWidth: 1800
});
endingText.anchor.set(0.5, 0.5);
endingText.x = 2048 / 2;
endingText.y = 2732 / 2;
endingText.visible = false;
game.addChild(endingText);
// Show scenario
function showScenario(idx) {
canSelect = true;
endingText.visible = false;
var sc = scenarios[idx];
scenarioText.setText(sc.text);
// Show options
for (var i = 0; i < optionButtons.length; i++) {
if (sc.options[i]) {
optionButtons[i].visible = true;
optionButtons[i].setText(sc.options[i].text);
optionButtons[i].setSelected(false);
optionButtons[i].setDisabled(false);
} else {
optionButtons[i].visible = false;
}
}
}
// Handle option selection
function selectOption(optIdx) {
canSelect = false;
var sc = scenarios[currentScenario];
var opt = sc.options[optIdx];
// Animate button selection
for (var i = 0; i < optionButtons.length; i++) {
optionButtons[i].setDisabled(true);
optionButtons[i].setSelected(i === optIdx);
}
// Play sound for correct/incorrect choice
if (opt.happiness >= 0) {
LK.getSound('choice_correct').play();
} else {
LK.getSound('choice_wrong').play();
}
// Animate happiness bar
var newHappiness = happiness + opt.happiness;
if (newHappiness > 100) newHappiness = 100;
if (newHappiness < 0) newHappiness = 0;
tween(happinessBar.fill, {
width: 8 * newHappiness
}, {
duration: 400,
easing: tween.cubicOut
});
happiness = newHappiness;
// Animate girl (flash color if happiness drops)
if (opt.happiness < 0) {
tween(girlSprite, {
tint: 0xd32f2f
}, {
duration: 200,
onFinish: function onFinish() {
tween(girlSprite, {
tint: 0xf7b6d2
}, {
duration: 400
});
}
});
} else if (opt.happiness > 0) {
tween(girlSprite, {
tint: 0x81c784
}, {
duration: 200,
onFinish: function onFinish() {
tween(girlSprite, {
tint: 0xf7b6d2
}, {
duration: 400
});
}
});
}
// After short delay, go to next scenario or ending
LK.setTimeout(function () {
// Play scenario transition sound if not ending
if (!opt.ending) {
LK.getSound('scenario_next').play();
}
if (opt.ending) {
showEnding(opt.ending);
} else if (opt.next !== undefined && opt.next !== null) {
currentScenario = opt.next;
showScenario(currentScenario);
} else {
// No next, no ending: treat as ending
showEnding("The story ends here.");
}
}, 700);
}
// Show ending
function showEnding(txt) {
for (var i = 0; i < optionButtons.length; i++) {
optionButtons[i].visible = false;
}
scenarioText.setText('');
endingText.setText(txt + "\n\nFinal Happiness: " + happiness);
endingText.visible = true;
// Stop background music
LK.stopMusic();
// If happiness is high, show win, else show game over
LK.setTimeout(function () {
if (happiness >= 60) {
LK.showYouWin();
} else {
LK.showGameOver();
}
}, 1800);
}
// Start game
function startGame() {
currentScenario = 0;
happiness = 100;
happinessBar.setValue(happiness);
girlSprite.tint = 0xf7b6d2;
showScenario(currentScenario);
// Play background music (looping)
LK.playMusic('bgm_story');
}
startGame();
// No dragging or move events needed for this game
// Update happiness bar value every frame (in case of tween)
game.update = function () {
// Clamp fill width
if (happinessBar.fill.width < 0) happinessBar.fill.width = 0;
if (happinessBar.fill.width > 800) happinessBar.fill.width = 800;
// Optionally, could animate other things here
};