/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { playerHP: 20, monstersFought: 0, monstersSpared: 0, currentArea: "ruins", gameProgress: 0 }); /**** * Classes ****/ var ActionButton = Container.expand(function (type, text) { var self = Container.call(this); var assetId = type + 'Button'; var buttonGraphics = self.attachAsset(assetId, { anchorX: 0.5, anchorY: 0.5 }); self.text = new Text2(text, { size: 40, fill: 0xFFFFFF }); self.text.anchor.set(0.5, 0.5); self.addChild(self.text); self.setPosition = function (x, y) { self.x = x; self.y = y; self.text.x = 0; self.text.y = 0; }; self.down = function (x, y, obj) { tween(buttonGraphics, { scaleX: 0.9, scaleY: 0.9 }, { duration: 100 }); }; self.up = function (x, y, obj) { tween(buttonGraphics, { scaleX: 1.0, scaleY: 1.0 }, { duration: 100 }); if (self.onClick) { self.onClick(); } }; return self; }); var Bullet = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('bullet', { anchorX: 0.5, anchorY: 0.5 }); self.speedX = 0; self.speedY = 0; self.damage = 2; self.update = function () { self.x += self.speedX; self.y += self.speedY; // Check if out of bounds if (self.x < battleArea.x || self.x > battleArea.x + battleArea.width || self.y < battleArea.y || self.y > battleArea.y + battleArea.height) { self.shouldRemove = true; } }; self.setVelocity = function (speedX, speedY) { self.speedX = speedX; self.speedY = speedY; }; return self; }); var DialogBox = Container.expand(function () { var self = Container.call(this); var box = self.attachAsset('dialogBox', { anchorX: 0.5, anchorY: 0.5 }); self.text = new Text2("", { size: 48, fill: 0xFFFFFF }); self.text.anchor.set(0.5, 0.5); self.addChild(self.text); self.setMessage = function (message) { self.text.setText(message); }; self.setPosition = function (x, y) { self.x = x; self.y = y; self.text.x = 0; self.text.y = 0; }; self.show = function () { self.visible = true; }; self.hide = function () { self.visible = false; }; return self; }); var Monster = Container.expand(function () { var self = Container.call(this); var monsterSprite = self.attachAsset('monster', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.5, scaleY: 1.5 }); self.hp = 30; self.maxHP = 30; self.name = "Froggit"; self.mercy = 0; self.mercyThreshold = 100; self.spared = false; self.defeated = false; // Attacks available to this monster self.attacks = ['basic', 'circle', 'random']; self.setPosition = function (x, y) { self.x = x; self.y = y; }; self.takeDamage = function (amount) { self.hp = Math.max(0, self.hp - amount); // Flash the sprite white tween(monsterSprite, { tint: 0xffffff }, { duration: 100, onFinish: function onFinish() { tween(monsterSprite, { tint: 0xffffff }, { duration: 100, onFinish: function onFinish() { monsterSprite.tint = 0xffffff; } }); } }); if (self.hp <= 0) { self.defeated = true; storage.monstersFought++; monsterSprite.alpha = 0; LK.getSound('hit').play(); } }; self.increaseMercy = function (amount) { self.mercy = Math.min(self.mercyThreshold, self.mercy + amount); if (self.mercy >= self.mercyThreshold) { self.spared = true; storage.monstersSpared++; tween(monsterSprite, { alpha: 0 }, { duration: 1000 }); LK.getSound('spare').play(); } }; self.getRandomAttack = function () { var index = Math.floor(Math.random() * self.attacks.length); return self.attacks[index]; }; return self; }); var Player = Container.expand(function () { var self = Container.call(this); self.hp = storage.playerHP || 20; self.maxHP = 20; self.name = "You"; self.level = 1; var playerSprite = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); self.resetPosition = function () { self.x = 2048 / 2; self.y = 2732 / 2; }; self.takeDamage = function (amount) { self.hp = Math.max(0, self.hp - amount); storage.playerHP = self.hp; LK.getSound('damage').play(); // Flash the sprite red tween(playerSprite, { alpha: 0.5 }, { duration: 100, onFinish: function onFinish() { tween(playerSprite, { alpha: 1 }, { duration: 100 }); } }); if (self.hp <= 0) { LK.showGameOver(); } }; self.heal = function (amount) { self.hp = Math.min(self.maxHP, self.hp + amount); storage.playerHP = self.hp; }; return self; }); var Soul = Container.expand(function () { var self = Container.call(this); var heart = self.attachAsset('heart', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 10; self.targetX = 0; self.targetY = 0; self.update = function () { if (self.moving) { // Move toward target position self.x += (self.targetX - self.x) * 0.2; self.y += (self.targetY - self.y) * 0.2; } }; self.moveTo = function (x, y) { self.targetX = x; self.targetY = y; self.moving = true; }; self.stopMoving = function () { self.moving = false; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ game.setBackgroundColor(0x111111); // Game state variables var gameState = 'exploration'; // exploration, battle, dialog var battlePhase = 'start'; // start, playerTurn, monsterTurn, end var dialogQueue = []; var bullets = []; var attackTimer = 0; var turnCounter = 0; // Create our main gameplay objects var player = new Player(); var currentMonster = null; var soul = new Soul(); var dialogBox = new DialogBox(); var battleArea = null; // Action buttons var fightButton = new ActionButton('fight', 'FIGHT'); var actButton = new ActionButton('act', 'ACT'); var mercyButton = new ActionButton('mercy', 'MERCY'); // Set up dialog box dialogBox.setPosition(2048 / 2, 2732 - 300); dialogBox.hide(); game.addChild(dialogBox); // Add UI elements var hpText = new Text2("HP: " + player.hp + "/" + player.maxHP, { size: 48, fill: 0xFFFFFF }); hpText.anchor.set(0, 0); hpText.x = 50; hpText.y = 50; LK.gui.topLeft.addChild(hpText); // Initialize player player.resetPosition(); game.addChild(player); // Set up button actions fightButton.onClick = function () { if (gameState === 'battle' && battlePhase === 'playerTurn') { // Player chooses to attack dialogBox.setMessage("You attack!"); battlePhase = 'playerAttack'; // Simple damage calculation var damage = 5 + Math.floor(Math.random() * 3); currentMonster.takeDamage(damage); LK.setTimeout(function () { if (currentMonster.defeated) { endBattle(true); } else { startMonsterTurn(); } }, 1000); } }; actButton.onClick = function () { if (gameState === 'battle' && battlePhase === 'playerTurn') { // Player chooses to interact dialogBox.setMessage("* You try to talk to " + currentMonster.name); battlePhase = 'playerAct'; // Increase mercy meter currentMonster.increaseMercy(25); LK.setTimeout(function () { if (currentMonster.spared) { endBattle(false); } else { startMonsterTurn(); } }, 1500); } }; mercyButton.onClick = function () { if (gameState === 'battle' && battlePhase === 'playerTurn') { // Player chooses mercy dialogBox.setMessage("* You spare " + currentMonster.name); battlePhase = 'playerMercy'; // Increase mercy meter significantly currentMonster.increaseMercy(50); LK.setTimeout(function () { if (currentMonster.spared) { endBattle(false); } else { startMonsterTurn(); } }, 1500); } }; // Helper functions function startBattle() { gameState = 'battle'; battlePhase = 'start'; // Create a new monster for this battle currentMonster = new Monster(); currentMonster.setPosition(2048 / 2, 800); game.addChild(currentMonster); // Create battle area (where bullets and the soul interact) battleArea = LK.getAsset('battleArea', { anchorX: 0.5, anchorY: 0.5 }); battleArea.x = 2048 / 2; battleArea.y = 1600; battleArea.width = 1000; battleArea.height = 500; game.addChild(battleArea); // Initialize soul in battle area soul.x = battleArea.x; soul.y = battleArea.y + battleArea.height / 2; game.addChild(soul); // Add buttons fightButton.setPosition(2048 / 4, 2200); actButton.setPosition(2048 / 2, 2200); mercyButton.setPosition(2048 * 3 / 4, 2200); game.addChild(fightButton); game.addChild(actButton); game.addChild(mercyButton); // Hide player during battle player.visible = false; // Show dialog to start dialogBox.setMessage("* A " + currentMonster.name + " appears!"); dialogBox.show(); LK.setTimeout(function () { startPlayerTurn(); }, 1500); } function startPlayerTurn() { battlePhase = 'playerTurn'; dialogBox.setMessage("* What will you do?"); turnCounter++; } function startMonsterTurn() { battlePhase = 'monsterTurn'; dialogBox.setMessage("* " + currentMonster.name + " prepares an attack!"); // Start a timer for this attack sequence attackTimer = 0; // Select attack pattern based on monster currentAttack = currentMonster.getRandomAttack(); // Allow soul movement during monster turn soul.moving = true; } function endBattle(won) { battlePhase = 'end'; if (won) { dialogBox.setMessage("* You defeated " + currentMonster.name + "!"); LK.setScore(LK.getScore() + 100); } else { dialogBox.setMessage("* You spared " + currentMonster.name + "!"); LK.setScore(LK.getScore() + 150); } // Clean up battle area LK.setTimeout(function () { // Remove all battle elements if (battleArea) { battleArea.destroy(); battleArea = null; } if (currentMonster) { currentMonster.destroy(); currentMonster = null; } soul.destroy(); fightButton.destroy(); actButton.destroy(); mercyButton.destroy(); bullets.forEach(function (bullet) { bullet.destroy(); }); bullets = []; player.visible = true; dialogBox.hide(); gameState = 'exploration'; // Check if game should be won if (storage.monstersFought + storage.monstersSpared >= 5) { LK.showYouWin(); } }, 2000); } function createBullet(x, y, speedX, speedY) { var bullet = new Bullet(); bullet.x = x; bullet.y = y; bullet.setVelocity(speedX, speedY); bullets.push(bullet); game.addChild(bullet); return bullet; } function basicAttack() { // Create bullets that move horizontally from left to right if (attackTimer % 15 === 0 && attackTimer < 90) { createBullet(battleArea.x - battleArea.width / 2, battleArea.y - battleArea.height / 3 + Math.random() * battleArea.height * 2 / 3, 5 + Math.random() * 3, 0); } } function circleAttack() { // Create bullets in a circular pattern if (attackTimer % 10 === 0 && attackTimer < 100) { var angle = attackTimer / 5; var speed = 4; createBullet(battleArea.x, battleArea.y, Math.cos(angle) * speed, Math.sin(angle) * speed); createBullet(battleArea.x, battleArea.y, Math.cos(angle + Math.PI) * speed, Math.sin(angle + Math.PI) * speed); } } function randomAttack() { // Create bullets at random positions with random velocities if (attackTimer % 20 === 0 && attackTimer < 100) { for (var i = 0; i < 3; i++) { var startX = battleArea.x - battleArea.width / 2 + Math.random() * battleArea.width; var startY = battleArea.y - battleArea.height / 2; createBullet(startX, startY, -2 + Math.random() * 4, 2 + Math.random() * 3); } } } // Game update loop game.update = function () { // Update HP text hpText.setText("HP: " + player.hp + "/" + player.maxHP); // Handle exploration state if (gameState === 'exploration') { // In a real game, we'd handle movement, exploration, etc. here // For this demo, we'll just randomly trigger battles if (LK.ticks % 180 === 0 && Math.random() < 0.3) { startBattle(); } } // Handle battle state if (gameState === 'battle') { // Monster turn attack logic if (battlePhase === 'monsterTurn') { attackTimer++; // Run current attack pattern if (currentAttack === 'basic') { basicAttack(); } else if (currentAttack === 'circle') { circleAttack(); } else if (currentAttack === 'random') { randomAttack(); } // End turn after a certain time if (attackTimer >= 120) { battlePhase = 'playerTurn'; soul.moving = false; dialogBox.setMessage("* What will you do?"); } } // Update all bullets for (var i = bullets.length - 1; i >= 0; i--) { var bullet = bullets[i]; // Check collision with soul if (soul.intersects(bullet)) { player.takeDamage(bullet.damage); bullet.destroy(); bullets.splice(i, 1); continue; } // Remove bullets that are flagged for removal if (bullet.shouldRemove) { bullet.destroy(); bullets.splice(i, 1); } } } }; // Handle input events var dragTarget = null; game.down = function (x, y, obj) { if (gameState === 'battle' && battlePhase === 'monsterTurn') { // During monster turn, control the soul soul.targetX = x; soul.targetY = y; } }; game.move = function (x, y, obj) { if (gameState === 'battle' && battlePhase === 'monsterTurn') { // During monster turn, control the soul soul.targetX = x; soul.targetY = y; } else if (gameState === 'exploration') { // During exploration, move the player player.x = x; player.y = y; } }; game.up = function (x, y, obj) { // Nothing special on release }; // Start the game with a welcome message dialogBox.setMessage("* Welcome to Monster Tales! Touch to move."); dialogBox.show(); LK.setTimeout(function () { dialogBox.hide(); }, 3000); // Play background music LK.playMusic('bgm');
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
playerHP: 20,
monstersFought: 0,
monstersSpared: 0,
currentArea: "ruins",
gameProgress: 0
});
/****
* Classes
****/
var ActionButton = Container.expand(function (type, text) {
var self = Container.call(this);
var assetId = type + 'Button';
var buttonGraphics = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
self.text = new Text2(text, {
size: 40,
fill: 0xFFFFFF
});
self.text.anchor.set(0.5, 0.5);
self.addChild(self.text);
self.setPosition = function (x, y) {
self.x = x;
self.y = y;
self.text.x = 0;
self.text.y = 0;
};
self.down = function (x, y, obj) {
tween(buttonGraphics, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100
});
};
self.up = function (x, y, obj) {
tween(buttonGraphics, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 100
});
if (self.onClick) {
self.onClick();
}
};
return self;
});
var Bullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speedX = 0;
self.speedY = 0;
self.damage = 2;
self.update = function () {
self.x += self.speedX;
self.y += self.speedY;
// Check if out of bounds
if (self.x < battleArea.x || self.x > battleArea.x + battleArea.width || self.y < battleArea.y || self.y > battleArea.y + battleArea.height) {
self.shouldRemove = true;
}
};
self.setVelocity = function (speedX, speedY) {
self.speedX = speedX;
self.speedY = speedY;
};
return self;
});
var DialogBox = Container.expand(function () {
var self = Container.call(this);
var box = self.attachAsset('dialogBox', {
anchorX: 0.5,
anchorY: 0.5
});
self.text = new Text2("", {
size: 48,
fill: 0xFFFFFF
});
self.text.anchor.set(0.5, 0.5);
self.addChild(self.text);
self.setMessage = function (message) {
self.text.setText(message);
};
self.setPosition = function (x, y) {
self.x = x;
self.y = y;
self.text.x = 0;
self.text.y = 0;
};
self.show = function () {
self.visible = true;
};
self.hide = function () {
self.visible = false;
};
return self;
});
var Monster = Container.expand(function () {
var self = Container.call(this);
var monsterSprite = self.attachAsset('monster', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
self.hp = 30;
self.maxHP = 30;
self.name = "Froggit";
self.mercy = 0;
self.mercyThreshold = 100;
self.spared = false;
self.defeated = false;
// Attacks available to this monster
self.attacks = ['basic', 'circle', 'random'];
self.setPosition = function (x, y) {
self.x = x;
self.y = y;
};
self.takeDamage = function (amount) {
self.hp = Math.max(0, self.hp - amount);
// Flash the sprite white
tween(monsterSprite, {
tint: 0xffffff
}, {
duration: 100,
onFinish: function onFinish() {
tween(monsterSprite, {
tint: 0xffffff
}, {
duration: 100,
onFinish: function onFinish() {
monsterSprite.tint = 0xffffff;
}
});
}
});
if (self.hp <= 0) {
self.defeated = true;
storage.monstersFought++;
monsterSprite.alpha = 0;
LK.getSound('hit').play();
}
};
self.increaseMercy = function (amount) {
self.mercy = Math.min(self.mercyThreshold, self.mercy + amount);
if (self.mercy >= self.mercyThreshold) {
self.spared = true;
storage.monstersSpared++;
tween(monsterSprite, {
alpha: 0
}, {
duration: 1000
});
LK.getSound('spare').play();
}
};
self.getRandomAttack = function () {
var index = Math.floor(Math.random() * self.attacks.length);
return self.attacks[index];
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
self.hp = storage.playerHP || 20;
self.maxHP = 20;
self.name = "You";
self.level = 1;
var playerSprite = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.resetPosition = function () {
self.x = 2048 / 2;
self.y = 2732 / 2;
};
self.takeDamage = function (amount) {
self.hp = Math.max(0, self.hp - amount);
storage.playerHP = self.hp;
LK.getSound('damage').play();
// Flash the sprite red
tween(playerSprite, {
alpha: 0.5
}, {
duration: 100,
onFinish: function onFinish() {
tween(playerSprite, {
alpha: 1
}, {
duration: 100
});
}
});
if (self.hp <= 0) {
LK.showGameOver();
}
};
self.heal = function (amount) {
self.hp = Math.min(self.maxHP, self.hp + amount);
storage.playerHP = self.hp;
};
return self;
});
var Soul = Container.expand(function () {
var self = Container.call(this);
var heart = self.attachAsset('heart', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 10;
self.targetX = 0;
self.targetY = 0;
self.update = function () {
if (self.moving) {
// Move toward target position
self.x += (self.targetX - self.x) * 0.2;
self.y += (self.targetY - self.y) * 0.2;
}
};
self.moveTo = function (x, y) {
self.targetX = x;
self.targetY = y;
self.moving = true;
};
self.stopMoving = function () {
self.moving = false;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
game.setBackgroundColor(0x111111);
// Game state variables
var gameState = 'exploration'; // exploration, battle, dialog
var battlePhase = 'start'; // start, playerTurn, monsterTurn, end
var dialogQueue = [];
var bullets = [];
var attackTimer = 0;
var turnCounter = 0;
// Create our main gameplay objects
var player = new Player();
var currentMonster = null;
var soul = new Soul();
var dialogBox = new DialogBox();
var battleArea = null;
// Action buttons
var fightButton = new ActionButton('fight', 'FIGHT');
var actButton = new ActionButton('act', 'ACT');
var mercyButton = new ActionButton('mercy', 'MERCY');
// Set up dialog box
dialogBox.setPosition(2048 / 2, 2732 - 300);
dialogBox.hide();
game.addChild(dialogBox);
// Add UI elements
var hpText = new Text2("HP: " + player.hp + "/" + player.maxHP, {
size: 48,
fill: 0xFFFFFF
});
hpText.anchor.set(0, 0);
hpText.x = 50;
hpText.y = 50;
LK.gui.topLeft.addChild(hpText);
// Initialize player
player.resetPosition();
game.addChild(player);
// Set up button actions
fightButton.onClick = function () {
if (gameState === 'battle' && battlePhase === 'playerTurn') {
// Player chooses to attack
dialogBox.setMessage("You attack!");
battlePhase = 'playerAttack';
// Simple damage calculation
var damage = 5 + Math.floor(Math.random() * 3);
currentMonster.takeDamage(damage);
LK.setTimeout(function () {
if (currentMonster.defeated) {
endBattle(true);
} else {
startMonsterTurn();
}
}, 1000);
}
};
actButton.onClick = function () {
if (gameState === 'battle' && battlePhase === 'playerTurn') {
// Player chooses to interact
dialogBox.setMessage("* You try to talk to " + currentMonster.name);
battlePhase = 'playerAct';
// Increase mercy meter
currentMonster.increaseMercy(25);
LK.setTimeout(function () {
if (currentMonster.spared) {
endBattle(false);
} else {
startMonsterTurn();
}
}, 1500);
}
};
mercyButton.onClick = function () {
if (gameState === 'battle' && battlePhase === 'playerTurn') {
// Player chooses mercy
dialogBox.setMessage("* You spare " + currentMonster.name);
battlePhase = 'playerMercy';
// Increase mercy meter significantly
currentMonster.increaseMercy(50);
LK.setTimeout(function () {
if (currentMonster.spared) {
endBattle(false);
} else {
startMonsterTurn();
}
}, 1500);
}
};
// Helper functions
function startBattle() {
gameState = 'battle';
battlePhase = 'start';
// Create a new monster for this battle
currentMonster = new Monster();
currentMonster.setPosition(2048 / 2, 800);
game.addChild(currentMonster);
// Create battle area (where bullets and the soul interact)
battleArea = LK.getAsset('battleArea', {
anchorX: 0.5,
anchorY: 0.5
});
battleArea.x = 2048 / 2;
battleArea.y = 1600;
battleArea.width = 1000;
battleArea.height = 500;
game.addChild(battleArea);
// Initialize soul in battle area
soul.x = battleArea.x;
soul.y = battleArea.y + battleArea.height / 2;
game.addChild(soul);
// Add buttons
fightButton.setPosition(2048 / 4, 2200);
actButton.setPosition(2048 / 2, 2200);
mercyButton.setPosition(2048 * 3 / 4, 2200);
game.addChild(fightButton);
game.addChild(actButton);
game.addChild(mercyButton);
// Hide player during battle
player.visible = false;
// Show dialog to start
dialogBox.setMessage("* A " + currentMonster.name + " appears!");
dialogBox.show();
LK.setTimeout(function () {
startPlayerTurn();
}, 1500);
}
function startPlayerTurn() {
battlePhase = 'playerTurn';
dialogBox.setMessage("* What will you do?");
turnCounter++;
}
function startMonsterTurn() {
battlePhase = 'monsterTurn';
dialogBox.setMessage("* " + currentMonster.name + " prepares an attack!");
// Start a timer for this attack sequence
attackTimer = 0;
// Select attack pattern based on monster
currentAttack = currentMonster.getRandomAttack();
// Allow soul movement during monster turn
soul.moving = true;
}
function endBattle(won) {
battlePhase = 'end';
if (won) {
dialogBox.setMessage("* You defeated " + currentMonster.name + "!");
LK.setScore(LK.getScore() + 100);
} else {
dialogBox.setMessage("* You spared " + currentMonster.name + "!");
LK.setScore(LK.getScore() + 150);
}
// Clean up battle area
LK.setTimeout(function () {
// Remove all battle elements
if (battleArea) {
battleArea.destroy();
battleArea = null;
}
if (currentMonster) {
currentMonster.destroy();
currentMonster = null;
}
soul.destroy();
fightButton.destroy();
actButton.destroy();
mercyButton.destroy();
bullets.forEach(function (bullet) {
bullet.destroy();
});
bullets = [];
player.visible = true;
dialogBox.hide();
gameState = 'exploration';
// Check if game should be won
if (storage.monstersFought + storage.monstersSpared >= 5) {
LK.showYouWin();
}
}, 2000);
}
function createBullet(x, y, speedX, speedY) {
var bullet = new Bullet();
bullet.x = x;
bullet.y = y;
bullet.setVelocity(speedX, speedY);
bullets.push(bullet);
game.addChild(bullet);
return bullet;
}
function basicAttack() {
// Create bullets that move horizontally from left to right
if (attackTimer % 15 === 0 && attackTimer < 90) {
createBullet(battleArea.x - battleArea.width / 2, battleArea.y - battleArea.height / 3 + Math.random() * battleArea.height * 2 / 3, 5 + Math.random() * 3, 0);
}
}
function circleAttack() {
// Create bullets in a circular pattern
if (attackTimer % 10 === 0 && attackTimer < 100) {
var angle = attackTimer / 5;
var speed = 4;
createBullet(battleArea.x, battleArea.y, Math.cos(angle) * speed, Math.sin(angle) * speed);
createBullet(battleArea.x, battleArea.y, Math.cos(angle + Math.PI) * speed, Math.sin(angle + Math.PI) * speed);
}
}
function randomAttack() {
// Create bullets at random positions with random velocities
if (attackTimer % 20 === 0 && attackTimer < 100) {
for (var i = 0; i < 3; i++) {
var startX = battleArea.x - battleArea.width / 2 + Math.random() * battleArea.width;
var startY = battleArea.y - battleArea.height / 2;
createBullet(startX, startY, -2 + Math.random() * 4, 2 + Math.random() * 3);
}
}
}
// Game update loop
game.update = function () {
// Update HP text
hpText.setText("HP: " + player.hp + "/" + player.maxHP);
// Handle exploration state
if (gameState === 'exploration') {
// In a real game, we'd handle movement, exploration, etc. here
// For this demo, we'll just randomly trigger battles
if (LK.ticks % 180 === 0 && Math.random() < 0.3) {
startBattle();
}
}
// Handle battle state
if (gameState === 'battle') {
// Monster turn attack logic
if (battlePhase === 'monsterTurn') {
attackTimer++;
// Run current attack pattern
if (currentAttack === 'basic') {
basicAttack();
} else if (currentAttack === 'circle') {
circleAttack();
} else if (currentAttack === 'random') {
randomAttack();
}
// End turn after a certain time
if (attackTimer >= 120) {
battlePhase = 'playerTurn';
soul.moving = false;
dialogBox.setMessage("* What will you do?");
}
}
// Update all bullets
for (var i = bullets.length - 1; i >= 0; i--) {
var bullet = bullets[i];
// Check collision with soul
if (soul.intersects(bullet)) {
player.takeDamage(bullet.damage);
bullet.destroy();
bullets.splice(i, 1);
continue;
}
// Remove bullets that are flagged for removal
if (bullet.shouldRemove) {
bullet.destroy();
bullets.splice(i, 1);
}
}
}
};
// Handle input events
var dragTarget = null;
game.down = function (x, y, obj) {
if (gameState === 'battle' && battlePhase === 'monsterTurn') {
// During monster turn, control the soul
soul.targetX = x;
soul.targetY = y;
}
};
game.move = function (x, y, obj) {
if (gameState === 'battle' && battlePhase === 'monsterTurn') {
// During monster turn, control the soul
soul.targetX = x;
soul.targetY = y;
} else if (gameState === 'exploration') {
// During exploration, move the player
player.x = x;
player.y = y;
}
};
game.up = function (x, y, obj) {
// Nothing special on release
};
// Start the game with a welcome message
dialogBox.setMessage("* Welcome to Monster Tales! Touch to move.");
dialogBox.show();
LK.setTimeout(function () {
dialogBox.hide();
}, 3000);
// Play background music
LK.playMusic('bgm');