User prompt
If monsters hp goes down 5 from smite damage player lost, above that player wins
User prompt
Game dont end with 1 loss, let player play 10 round
User prompt
If player click smite value above 10 he win
User prompt
If go down from smite value make round lose for player
User prompt
Each round give random hp value and damage value
User prompt
Make one target, not three but give me a number for hp of monster. And give damage to smite and let me see it
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'flash')' in or related to this line: 'monster.flash(0xffcc00, 600);' Line Number: 337
User prompt
Please add numerous hp bar and, smite damage
User prompt
Make large not tall
User prompt
Make bar bigger please
User prompt
Please add hp bar and smite damage
User prompt
Please fix the bug: 'Uncaught TypeError: resultTxt.setFill is not a function' in or related to this line: 'resultTxt.setFill("#ffcc00");' Line Number: 246
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot set properties of undefined (setting 'fill')' in or related to this line: 'resultTxt.style.fill = "#ffcc00";' Line Number: 246
Code edit (1 edits merged)
Please save this source code
User prompt
Smite Timing Trainer
Initial prompt
Make me a League Of Legends "smite" practice tool game
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Monster class: handles monster sprite and health bar
var Monster = Container.expand(function () {
var self = Container.call(this);
// Monster sprite
var monsterSprite = self.attachAsset('monster', {
anchorX: 0.5,
anchorY: 0.5
});
monsterSprite.y = 0;
// Health bar background
var hpbarBg = self.attachAsset('hpbar_bg', {
anchorX: 0.5,
anchorY: 0.5,
y: 260
});
// Health bar foreground
var hpbarFg = self.attachAsset('hpbar_fg', {
anchorX: 0.5,
anchorY: 0.5,
y: 260
});
// Health bar value (0-1)
self.hp = 1;
self.maxHp = 1;
// Set health (0-1)
self.setHp = function (value) {
self.hp = Math.max(0, Math.min(1, value));
// Scale health bar foreground
hpbarFg.scaleX = self.hp;
// Anchor stays at left edge
hpbarFg.x = hpbarBg.x - 1600 * (1 - self.hp) / 2;
};
// Flash monster on smite
self.flash = function (color, duration) {
tween(monsterSprite, {
tint: color
}, {
duration: duration / 2,
easing: tween.linear,
onFinish: function onFinish() {
tween(monsterSprite, {
tint: 0x3cb371
}, {
duration: duration / 2,
easing: tween.linear
});
}
});
};
// Reset health bar
self.reset = function () {
self.setHp(1);
};
// Initialize
self.setHp(1);
return self;
});
// Smite effect (player or enemy)
var SmiteFX = Container.expand(function () {
var self = Container.call(this);
var fx = self.attachAsset('smite_fx', {
anchorX: 0.5,
anchorY: 0.5
});
self.play = function (x, y, isEnemy) {
self.x = x;
self.y = y;
fx.alpha = 1;
fx.scaleX = fx.scaleY = 1;
if (isEnemy) {
fx.tint = 0xff3333;
} else {
fx.tint = 0x3399ff;
}
tween(fx, {
alpha: 0,
scaleX: 2,
scaleY: 2
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
self.visible = false;
}
});
self.visible = true;
};
self.visible = false;
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x181c24
});
/****
* Game Code
****/
// Game constants
// Monster: Big ellipse, green
// Health bar background: gray
// Health bar foreground: yellow-green
// Smite effect: blue ellipse
// Enemy smite: red ellipse
// Sound for smite
var MONSTER_CENTER_X = 2048 / 2;
var MONSTER_CENTER_Y = 1100;
var HPBAR_Y_OFFSET = 250;
var SMITE_WINDOW = 0.12; // Smite is successful if HP <= this fraction
var ENEMY_SMITE_WINDOW = 0.10; // Enemy can smite if HP <= this
var ROUNDS_TOTAL = 10;
// Game state
var round = 1;
var score = 0;
var smiteUsed = false;
var enemySmiteUsed = false;
var monsterHp = 1;
var monsterHpSpeed = 0.003; // per tick
var monsterHpMinSpeed = 0.002;
var monsterHpMaxSpeed = 0.006;
var smiteFx, enemySmiteFx;
var monster;
var resultTxt, roundTxt, scoreTxt, infoTxt;
var lastTickTime = 0;
var smiteTime = 0;
var enemySmiteTime = 0;
var smiteAccuracy = [];
var smiteReaction = [];
var smiteSuccess = [];
var smiteAllowed = true;
var enemySmiteScheduled = false;
var enemySmiteTick = 0;
var enemySmiteActive = false;
// UI: Score, round, info
scoreTxt = new Text2('Score: 0', {
size: 90,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
roundTxt = new Text2('Round 1/10', {
size: 70,
fill: "#fff"
});
roundTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(roundTxt);
roundTxt.y = 110;
infoTxt = new Text2('Tap the monster to Smite!', {
size: 70,
fill: 0xB8E62E
});
infoTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(infoTxt);
infoTxt.y = 220;
// Result text (centered, hidden by default)
resultTxt = new Text2('', {
size: 120,
fill: "#fff"
});
resultTxt.anchor.set(0.5, 0.5);
resultTxt.visible = false;
LK.gui.center.addChild(resultTxt);
// Single monster support
var NUM_MONSTERS = 1;
var monsters = [];
var monsterHps = [];
var monsterHpSpeeds = [];
var monsterHpMinSpeeds = [];
var monsterHpMaxSpeeds = [];
var monsterSmitesUsed = [];
var monsterEnemySmitesUsed = [];
var monsterSmiteMarkers = [];
var monsterSmiteFxs = [];
var monsterEnemySmiteFxs = [];
var monsterCenters = [];
var SMITE_DAMAGE = 0.12;
// Create the single monster, centered
var m = new Monster();
game.addChild(m);
m.x = MONSTER_CENTER_X;
m.y = MONSTER_CENTER_Y;
monsters.push(m);
m.maxHp = 100; // Default, will be randomized in startRound
monsterCenters.push({
x: m.x,
y: m.y
});
monsterHps.push(1);
monsterHpSpeeds.push(monsterHpMinSpeed + Math.random() * (monsterHpMaxSpeed - monsterHpMinSpeed));
monsterHpMinSpeeds.push(monsterHpMinSpeed);
monsterHpMaxSpeeds.push(monsterHpMaxSpeed);
monsterSmitesUsed.push(false);
monsterEnemySmitesUsed.push(false);
// Smite marker for this monster
var smiteMarker = LK.getAsset('hpbar_fg', {
anchorX: 0.5,
anchorY: 0.5,
width: 10,
height: 70,
tint: 0x3399ff
});
game.addChild(smiteMarker);
monsterSmiteMarkers.push(smiteMarker);
// Smite FX for this monster
var smiteFx1 = new SmiteFX();
game.addChild(smiteFx1);
smiteFx1.x = m.x;
smiteFx1.y = m.y;
monsterSmiteFxs.push(smiteFx1);
// Enemy Smite FX for this monster
var enemySmiteFx1 = new SmiteFX();
game.addChild(enemySmiteFx1);
enemySmiteFx1.x = m.x;
enemySmiteFx1.y = m.y;
monsterEnemySmiteFxs.push(enemySmiteFx1);
// Smite damage text (shows the value)
var smiteDmgTxt = new Text2('Smite: ' + Math.round(SMITE_DAMAGE * 100) + '%', {
size: 70,
fill: 0x3399FF
});
smiteDmgTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(smiteDmgTxt);
smiteDmgTxt.y = 320;
// Monster HP number text
var monsterHpTxt = new Text2('HP: 100', {
size: 90,
fill: "#fff"
});
monsterHpTxt.anchor.set(0.5, 0.5);
monsterHpTxt.x = m.x;
monsterHpTxt.y = m.y - 180;
game.addChild(monsterHpTxt);
// Helper to update smite marker position for the monster
function updateSmiteMarkers() {
var m = monsters[0];
var smiteMarker = monsterSmiteMarkers[0];
// HP bar is at m.x, m.y + HPBAR_Y_OFFSET
// HP bar width is 1600, anchorX = 0.5 (centered)
var barWidth = 1600;
var barY = m.y + HPBAR_Y_OFFSET;
var barX = m.x;
// Smite marker should be at the position where HP = SMITE_DAMAGE
var markerFrac = 1 - SMITE_DAMAGE;
var markerX = barX - barWidth / 2 + barWidth * markerFrac;
smiteMarker.x = markerX;
smiteMarker.y = barY;
smiteMarker.width = 24;
smiteMarker.height = 80;
smiteMarker.visible = true;
}
updateSmiteMarkers();
// Smite FX
smiteFx = new SmiteFX();
game.addChild(smiteFx);
smiteFx.x = MONSTER_CENTER_X;
smiteFx.y = MONSTER_CENTER_Y;
enemySmiteFx = new SmiteFX();
game.addChild(enemySmiteFx);
enemySmiteFx.x = MONSTER_CENTER_X;
enemySmiteFx.y = MONSTER_CENTER_Y;
// Helper: Start a new round
function startRound() {
// Randomize monster HP and Smite damage for this round
var minHp = 80;
var maxHp = 300;
var minSmite = 0.10;
var maxSmite = 0.25;
var thisHp = minHp + Math.floor(Math.random() * (maxHp - minHp + 1));
var thisSmite = minSmite + Math.random() * (maxSmite - minSmite);
SMITE_DAMAGE = thisSmite;
// Reset state for all monsters
for (var i = 0; i < NUM_MONSTERS; ++i) {
monsterHps[i] = 1;
monsters[i].reset();
monsterSmitesUsed[i] = false;
monsterEnemySmitesUsed[i] = false;
monsterSmiteFxs[i].visible = false;
monsterEnemySmiteFxs[i].visible = false;
// Randomize HP speed for this round
monsterHpSpeeds[i] = monsterHpMinSpeeds[i] + Math.random() * (monsterHpMaxSpeeds[i] - monsterHpMinSpeeds[i]);
// Store the randomized max HP for this round
monsters[i].maxHp = thisHp;
}
// If the smite value is above 10, player wins instantly
if (SMITE_DAMAGE * thisHp > 10) {
// Set score to max, show summary, and skip round
score = ROUNDS_TOTAL;
showSummary();
return;
}
smiteAllowed = true;
enemySmiteActive = false;
enemySmiteScheduled = false;
resultTxt.visible = false;
// (Optional: You can add per-monster enemy smite logic here if you want enemy smite for each monster. For now, keep global enemy smite for simplicity.)
// Update UI
roundTxt.setText('Round ' + round + '/' + ROUNDS_TOTAL);
scoreTxt.setText('Score: ' + score);
infoTxt.setText('Tap the monster to Smite!');
lastTickTime = LK.ticks;
updateSmiteMarkers();
// Reset monster HP number and Smite damage text
monsterHpTxt.setText('HP: ' + thisHp);
smiteDmgTxt.setText('Smite: ' + Math.round(SMITE_DAMAGE * 100) + '% (' + Math.round(SMITE_DAMAGE * thisHp) + ' HP)');
}
// Helper: End round, show result, schedule next
function endRound(success, isEnemy) {
smiteAllowed = false;
smiteSuccess.push(success ? 1 : 0);
// Show result
if (isEnemy) {
resultTxt.setText('Enemy Stole It!');
resultTxt.setStyle({
fill: 0xFF3333
});
LK.getSound('enemy').play();
} else if (success) {
resultTxt.setText('Smite Success!');
resultTxt.setStyle({
fill: 0x3399FF
});
LK.getSound('smite').play();
} else {
resultTxt.setText('Missed!');
resultTxt.setStyle({
fill: 0xFFCC00
});
LK.getSound('fail').play();
}
resultTxt.visible = true;
// Animate monster
// Find which monster to flash: if called from player smite, flash the tapped monster; if enemy, flash the first unsmitten monster
var flashIndex = 0;
for (var i = 0; i < NUM_MONSTERS; ++i) {
if (!monsterSmitesUsed[i] && !monsterEnemySmitesUsed[i]) {
flashIndex = i;
break;
}
}
if (isEnemy) {
monsters[flashIndex].flash(0xff3333, 600);
} else if (success) {
monsters[flashIndex].flash(0x3399ff, 600);
} else {
monsters[flashIndex].flash(0xffcc00, 600);
}
// Next round or finish
LK.setTimeout(function () {
resultTxt.visible = false;
if (round < ROUNDS_TOTAL) {
round++;
startRound();
} else {
showSummary();
}
}, 1100);
}
// Helper: Show summary at end
function showSummary() {
// Calculate stats
var acc = 0,
react = 0,
hits = 0;
for (var i = 0; i < smiteAccuracy.length; ++i) {
acc += smiteAccuracy[i];
react += smiteReaction[i];
if (smiteSuccess[i]) hits++;
}
var avgAcc = smiteAccuracy.length ? acc / smiteAccuracy.length : 0;
var avgReact = smiteReaction.length ? react / smiteReaction.length : 0;
var summary = 'Game Over\n\n' + 'Score: ' + score + '/' + ROUNDS_TOTAL + '\n' + 'Avg. Accuracy: ' + (avgAcc * 100).toFixed(1) + '%\n' + 'Avg. Reaction: ' + (avgReact * 1000).toFixed(0) + 'ms';
resultTxt.setText(summary);
resultTxt.setStyle({
fill: 0xB8E62E
});
resultTxt.visible = true;
infoTxt.setText('Tap to play again!');
// Reset on tap
game.down = function (x, y, obj) {
// Reset state
round = 1;
score = 0;
smiteAccuracy = [];
smiteReaction = [];
smiteSuccess = [];
startRound();
game.down = handleDown;
};
}
// Handle player smite
function handleDown(x, y, obj) {
// Only allow if round is active
if (!smiteAllowed) return;
// Check which monster was tapped
var tappedMonster = -1;
for (var i = 0; i < NUM_MONSTERS; ++i) {
var m = monsters[i];
var dx = x - m.x;
var dy = y - m.y;
var rx = m.width / 2;
var ry = m.height / 2;
if (dx * dx / (rx * rx) + dy * dy / (ry * ry) <= 1) {
tappedMonster = i;
break;
}
}
if (tappedMonster === -1) return; // No monster tapped
// Only allow if not already smited for this monster
if (monsterSmitesUsed[tappedMonster]) return;
monsterSmitesUsed[tappedMonster] = true;
smiteTime = LK.ticks - lastTickTime;
// Smite effect
monsterSmiteFxs[tappedMonster].play(monsters[tappedMonster].x, monsters[tappedMonster].y, false);
// Check if successful
var maxHp = monsters[tappedMonster].maxHp || 100;
var hpValue = monsterHps[tappedMonster] * maxHp;
var smiteThreshold = SMITE_DAMAGE * maxHp;
var success = hpValue <= smiteThreshold && !enemySmiteActive;
if (success) {
score++;
}
// Record accuracy (how close to 0)
var acc = hpValue <= maxHp ? 1 - hpValue / smiteThreshold : 0;
acc = Math.max(0, Math.min(1, acc));
smiteAccuracy.push(1 - hpValue / maxHp);
smiteReaction.push(smiteTime / 60);
endRound(success, false);
}
// Attach event
game.down = handleDown;
// Main update loop
game.update = function () {
// If round is active
if (smiteAllowed) {
var allSmitten = true;
for (var i = 0; i < NUM_MONSTERS; ++i) {
// Decrease HP for each monster
if (!monsterSmitesUsed[i]) {
monsterHps[i] -= monsterHpSpeeds[i];
if (monsterHps[i] < 0) monsterHps[i] = 0;
monsters[i].setHp(monsterHps[i]);
allSmitten = false;
}
// If player missed (HP reaches 0)
if (monsterHps[i] <= 0 && !monsterEnemySmitesUsed[i] && !monsterSmitesUsed[i]) {
monsterSmitesUsed[i] = true;
smiteAccuracy.push(0);
smiteReaction.push(1);
endRound(false, false);
return;
}
// If player missed (HP drops below Smite threshold)
var maxHp = monsters[i].maxHp || 100;
var smiteThreshold = SMITE_DAMAGE * maxHp;
if (monsterHps[i] * maxHp < smiteThreshold && !monsterEnemySmitesUsed[i] && !monsterSmitesUsed[i]) {
monsterSmitesUsed[i] = true;
smiteAccuracy.push(0);
smiteReaction.push(1);
endRound(false, false);
return;
}
}
// Update monster HP number and Smite damage value
var maxHp = monsters[0].maxHp || 100;
var hpValue = Math.round(monsterHps[0] * maxHp);
monsterHpTxt.setText('HP: ' + hpValue);
smiteDmgTxt.setText('Smite: ' + Math.round(SMITE_DAMAGE * 100) + '% (' + Math.round(SMITE_DAMAGE * maxHp) + ' HP)');
// If all monsters have been smitten, end round
if (allSmitten) {
// For now, treat as success if all monsters smitten
endRound(true, false);
return;
}
}
};
// Start first round
startRound(); ===================================================================
--- original.js
+++ change.js