User prompt
Please fix the bug: 'The supplied index is out of bounds' in or related to this line: 'worldContainer.setChildIndex(cloud, 16 + i);' Line Number: 1449
User prompt
Please fix the bug: 'The supplied index is out of bounds' in or related to this line: 'worldContainer.setChildIndex(cloud, 16 + i);' Line Number: 1449
User prompt
Please fix the bug: 'The supplied index is out of bounds' in or related to this line: 'worldContainer.setChildIndex(cloud, 16 + i);' Line Number: 1449
User prompt
Please fix the bug: 'The supplied index is out of bounds' in or related to this line: 'worldContainer.setChildIndex(cloud, 16 + i);' Line Number: 1443
User prompt
Please try the city layout again, using nocturnecitylayout asset as a guide for placement of platforms and doors, making sure they’re layered in front of building and sign assets. nocturnecity as a background asset alongside the multiple other background assets, layering to avoid visible abrupt seams. Hunks still appearing multiple onscreen simultaneously. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Please fix the bug: 'The supplied index is out of bounds' in or related to this line: 'worldContainer.setChildIndex(cloud, 4 + i);' Line Number: 1414
User prompt
Please refer to nocturnecitylayout as primary guide and blueprint to the level layout and structure. Then, incorporate nocturnecity as a primary background asset, helping to expand the current level layout both vertically and a bit horizontally. Then, using nocturnecitylayout as a visual guide, place the corresponding foreground assets like the various platforms, placing door assets where doors are, and incorporating the shop overlay and floating sign at the bottom left door position. Place other door assets where they appear in the layout guide asset, maintaining the mechanic where tapping the doors when standing in front of them cause an animation transition to a placeholder interior asset overlay. Make sure these interior overlays have exit buttons. Then, populate hunk characters less densely, making sure only one is visible onscreen at a time. Use the various buildings, drifting clouds, and blinking neon sign assets to provide the continued visual intrigue for the scene. playerwalk9 - 12 assets still render way larger than the rest of the frames; either use the 700 height setting or just aim for size consistency while walking. Thanks! ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
The added walk animation frames are rendering as Godzilla-levels huge even after adjusting size manually. Please restore the previous shop layout, but restored. Only use placeholder + suggested spaces for the other doors. Only the shop should have the floating sign out front. The combat menu overlay doesn’t appear nor does the combat system when standing near+tapping on hunks. Please space them out more/reduce their frequency, especially avoiding multiple versions of the same hunk assets onscreen looking like clones simultaneously. Please use more of the upper and lower levels, as in more variety than the present two distinct levels. Design platforming city layout with visual intrigue to encourage exploration in all directions, creating steps leading up and down at logical and non-repetitive levels leading to multiple stories of spaces, doors that tapping on pulls up overlay of urban indoor spaces. Text assets still garbled in spacing and size. Thanks! ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Frames of player walk animation still appear distorted too skinny despite my efforts to change aspect ratio settings manually. Please ensure that building assets remain in layers behind platform assets. The combat menu + system no longer appear at all when standing on top of or around hunk characters, along with the experience system. Shop assets for text and merchandise along with platforms are overlapping incomprehensibly, the text warped and illegible. The mandroid shopkeeper character can also use the uploaded alphabet assets ideally, endeavoring to iterate and improve spacing, sizing, legibility to reader. You could also implement uploaded number assets 0-9. Please add more logical structure to the platform and building layout for a city, adding additional doors, which tapping can bring up suggested placeholder spaces and assets in the same vein as when tapping the shop door. Please incorporate the additional generated player walking frames. Thanks! ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Tapping on hunks when close to them isn’t initiating combat menu. Please resize and rearrange shop overlay assets, lettering, items, shelves, etc. they’re overlapping and nonsensical looking. Please make sure that background assets aren’t appearing in front of player character and hunk characters. Flesh out the opening map area using platform and background assets, giving it more structure and interest. Populate the space with hunk characters. You can use door and other environmental access to create new areas as well. Thanks! ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Player still falling through platform upon beginning hunk encounter. Let’s switch it up and instead of automatically triggering combat menu popup within a certain range, instead, similar to door asset player must be standing near, then tap hunk character. Player should remain in place, with combat overlay appearing. Tapping cast should play the cast animation sequence while spell2 asset is animated pulsing at the bottom of hunk asset with spell asset appearing behind hunk. Tapping speak initiates dialoguebox assets floating above each character’s head while they’re talking. Tapping enthrall = a capture attempt, which should trigger an animation of capturedevice being thrown at hunk and captureeffect expanding from capture device. Hunk should either be sucked into device, or appear to shrink into device before breaking free with effect asset occurring at his feet. Once hunk is captured or defeated, player is not returned to level beginning, remaining in place while xpmenu appears as an overlay and the experience menu calculates and tallies experience earned. Shop overlay upon tapping works, though! Within the shop overlay, please replace current text with uploaded alphabet assets a - z . Add platshelf asset to store overlay beneath products, stocking then with plush - plush3. Put displayplatform beneath crystalheart assets, and mandroid character. Thanks! ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Same issue, no change. Let’s try this: when player stands in front of door, then taps said door or sign area, shop assets unfold across screen. Thanks! ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Player character still falls through the platform and off the screen at the beginning of encounter with hunks. Door still doesn’t initiate shop. So... yeah, same thing as before but sure am stoked about this freshly implemented credit system to be able to try again and again sans progress. Hehe sorry and thanks for trying
User prompt
Please fix the bug: 'ReferenceError: Can't find variable: inBattle' in or related to this line: 'if (!inBattle) {' Line Number: 2777 ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Shop door functionality still not working. Player just casts spell when tapping the action button in front of door. Might that be overriding the shop overlay menu animation transition from occuring? Also, player still falls through the platform when beginning a hunk encounter. I’d like the player asset to remain in the same position, capable of moving, with the battle ui appearing when in range, disappearing when walking out of range. Battle ui doesn’t appear to function, simply flashing red when tapping different options. Cursor overlay is still not centered above a menu option, nor does it appear to relocate when tapping other options to indicate selection. Thanks for your help! ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Character falls through the platform through the void at the brig inning of a hunk interaction. When attempting to select an option from the combat menu, the screen just flashes red. Cursor asset is not correctly placed over menu options, drifting off to the side. The shop door still doesn’t open shop overlay when tapping action button while standing in front of it. The shop sign is still not floating above the door asset, instead is just hovering beneath the door.
User prompt
Combat menu still isn’t working correctly. Player still falls through the platform at the start of battle encounters. Text and dialogue boxes take up the whole screen, garbled. When pressing action button while standing in front of door, player character casts a spell instead of shop menu overlay opening. Hidesign asset I requested float above the door is still floating beneath/in front of it. Thanks! ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Please make the hidesign asset float above the door. Door still doesn’t appear to be interactive opening shop overlay. Please fix the issue when beginning a hunk encounter, the player falls through the platform into the abyss. Keep player asset present in same position, with the combat overlay appearing bottom center, between the trackpad and jump and action buttons, not overlapping. Resize as needed. The cursor mechanic doesn’t work properly, presumably because the touch options don’t seem calibrated to the menu asset well. The enthrall option serves as the “capture” function previously present. The speak option should initiate dialogue between the two characters. Party should bring up a list of hunks captured you can switch into. Leave should exit the encounter. Spells cast that impact the hunk before battle menu appears should still visibly reduce hunk’s resistance bar. Thanks’ ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Upon reaching the door, the game erupts into chaos. Simultaneously, we have the combat menu, dialogue bubbles, giant white text stretching across the whole screen, as well as the separate combat background and an additional hunk overlay. The combat menu is intended to replace the previous overlays that appeared, and please clean the overall visual experience up. The dialogue or text bubbles with dialogue shouldn’t appear unless selecting the speak option. Please make the combat menu overlay able to be selected, with the cursor asset used to indicate which option is selected. Thanks! ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Please make it so you don’t teleport back to the beginning of the level when completing a hunk encounter. Please implement dialoguebox asset as a floating overlay that appears over both player and hunk characters’ heads, fitting text capitalized and bolded in white within the borders of the asset. This function as speech/dialogue boxes. Populate these boxes with in-character speech. The hunk you’re referring to as a cyber guy is, in fact, meant to be a djinn or genie. There’s a mushroom man, fungi/ funguy pun, a Minotaur, and an iguana man. Make their names punny spicy innuendo. Use combatmenu and cursor overlay in place of current combat system. We don’t need the additional overlay currently in place where you tap on the combat button and the hunk spins around. Instead, integrate the features and options from the combatmenu asset, which should appear as an overlay when you get close enough to a hunk to interact, with cursor asset an overlay over the menu for visual aid in option selection. Please implement hidesign asset floating over door. Also, door interactions still don’t work. Thanks! ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Animation while jumping also looks warped skinny, and the door doesn’t respond to action button tapping, instead just casts a spell repeatedly. If standing in front of door, player should walk through door via the shop overlay animation transition ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Door asset still doesn’t respond to standing in front of it and pressing action button, which should cause an animated transition of the shop overlay menu expanding, visually signaling the player has walked through the door, into the shop environment. Thanks! ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
The shop asset shouldn’t be at the top of the screen overlapping the brostiary icon. The animation effect that occurs when tapping that erroneously placed shop asset should instead Door asset still doesn’t respond to standing in front of it and pressing action button, which should cause an animated transition of the shop overlay menu expanding, visually signaling the player has walked through the door, into the shop environment. The shop appears chaotic with every overlapping, both text and assets, to a near incomprehensible degree. Player character’s walking animation frames appear warped and comically skinny despite my repeated attempts to adjust their aspect ratios. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Please place door asset within sidescrolling mode foreground environment, accessible via platform, that walking in front of and pressing action button causes player to enter, which triggers a transition animation of shop assets expanding from doorway. Please considerably increase font size by a lot, make primarily white with hot pink glow, capitalize and bold. Remove text Hide and Bone top center, as that’s included in the visual assets. Use x asset in upper left corner to return to overworld/sidescrolling screen. Thanks! ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Please use door & shop & shop2 & hidesign as background overlay assets to create a shop experience, with mandroid in the foreground, with the dialoguebox asset serving as the robot customer service agent ai with dialogue options and a shop item ui selling various unused object assets. mandroid character should have a punny robot-themed name embedded with an innuendo, as his personality is that of a highly flirtatious robot butler operating Hide & Bone, a futuristic fashion boutique that doubles as a secret dealer of occult artifacts and powerful magic-tech objects. Thanks!!
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var BattleUI = Container.expand(function () {
var self = Container.call(this);
var bg = self.attachAsset('battleBg', {
anchorX: 0.5,
anchorY: 0.5
});
bg.alpha = 0.9;
self.hunkDisplay = null;
self.resistanceBar = null;
self.resistanceFill = null;
self.spellButtons = [];
self.setup = function (hunk) {
self.hunkDisplay = self.addChild(new Container());
var hunkAssets = ['hunk', 'hunk2', 'hunk3', 'hunk4'];
// For animated hunks, we need to create an animated display
if (hunk.hunkType === 0) {
// Create animation frames for battle display - mushroom hunk
self.hunkIdleFrames = [];
self.currentBattleFrame = 0;
var frameAssets = ['hunk', 'hunka', 'hunkb', 'hunkc', 'hunkd', 'hunke'];
for (var i = 0; i < frameAssets.length; i++) {
var frame = self.hunkDisplay.attachAsset(frameAssets[i], {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2,
scaleY: 2,
alpha: i === 0 ? 1 : 0
});
self.hunkIdleFrames.push(frame);
}
// Start battle idle animation
self.startBattleIdleAnimation();
} else if (hunk.hunkType === 1) {
// Create animation frames for battle display - hunk2
self.hunkIdleFrames = [];
self.currentBattleFrame = 0;
var frameAssets = ['hunk2', 'hunk2a', 'hunk2b', 'hunk2c', 'hunk2d'];
for (var i = 0; i < frameAssets.length; i++) {
var frame = self.hunkDisplay.attachAsset(frameAssets[i], {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2,
scaleY: 2,
alpha: i === 0 ? 1 : 0
});
self.hunkIdleFrames.push(frame);
}
// Start battle idle animation
self.startBattleIdleAnimation();
} else if (hunk.hunkType === 2) {
// Create animation frames for battle display - hunk3
self.hunkIdleFrames = [];
self.currentBattleFrame = 0;
var frameAssets = ['hunk3', 'hunk3a', 'hunk3b', 'hunk3c', 'hunk3d'];
for (var i = 0; i < frameAssets.length; i++) {
var frame = self.hunkDisplay.attachAsset(frameAssets[i], {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2,
scaleY: 2,
alpha: i === 0 ? 1 : 0
});
self.hunkIdleFrames.push(frame);
}
// Start battle idle animation
self.startBattleIdleAnimation();
} else if (hunk.hunkType === 3) {
// Create animation frames for battle display - hunk4
self.hunkIdleFrames = [];
self.currentBattleFrame = 0;
var frameAssets = ['hunk4', 'hunk4a', 'hunk4b', 'hunk4c', 'hunk4d'];
for (var i = 0; i < frameAssets.length; i++) {
var frame = self.hunkDisplay.attachAsset(frameAssets[i], {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2,
scaleY: 2,
alpha: i === 0 ? 1 : 0
});
self.hunkIdleFrames.push(frame);
}
// Start battle idle animation
self.startBattleIdleAnimation();
} else {
// Normal static display for other hunks
var hunkGraphic = self.hunkDisplay.attachAsset(hunkAssets[hunk.hunkType], {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2,
scaleY: 2
});
}
self.hunkDisplay.y = -200;
var barBg = self.attachAsset('resistanceBar', {
anchorX: 0.5,
anchorY: 0.5,
y: 50
});
self.resistanceFill = self.attachAsset('resistanceFill', {
anchorX: 0,
anchorY: 0.5,
x: -150,
y: 50
});
self.updateResistance(hunk.resistance, hunk.maxResistance);
var spell1 = self.attachAsset('spellButton', {
anchorX: 0.5,
anchorY: 0.5,
x: -200,
y: 200
});
spell1.interactive = true;
self.spellButtons.push(spell1);
var spell1Text = new Text2('Hypnotize', {
size: 40,
fill: 0xFFFFFF
});
spell1Text.anchor.set(0.5, 0.5);
spell1.addChild(spell1Text);
var spell2 = self.attachAsset('spellButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 200,
y: 200
});
spell2.interactive = true;
self.spellButtons.push(spell2);
var spell2Text = new Text2('Charm', {
size: 40,
fill: 0xFFFFFF
});
spell2Text.anchor.set(0.5, 0.5);
spell2.addChild(spell2Text);
var captureBtn = self.attachAsset('crystal', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 350,
scaleX: 1.5,
scaleY: 1.5
});
captureBtn.interactive = true;
self.captureButton = captureBtn;
var captureText = new Text2('Capture', {
size: 30,
fill: 0xFFFFFF
});
captureText.anchor.set(0.5, 0.5);
captureBtn.addChild(captureText);
};
self.updateResistance = function (current, max) {
if (self.resistanceFill) {
self.resistanceFill.scale.x = current / max;
}
};
self.animationDirection = 1; // 1 for forward, -1 for reverse
self.startBattleIdleAnimation = function () {
if (!self.hunkIdleFrames || self.hunkIdleFrames.length === 0) return;
var currentFrame = self.hunkIdleFrames[self.currentBattleFrame];
// Calculate next frame with direction
var nextFrameIndex = self.currentBattleFrame + self.animationDirection;
// Check if we need to reverse direction
if (nextFrameIndex >= self.hunkIdleFrames.length - 1) {
nextFrameIndex = self.hunkIdleFrames.length - 1;
self.animationDirection = -1;
} else if (nextFrameIndex <= 0) {
nextFrameIndex = 0;
self.animationDirection = 1;
}
var nextFrame = self.hunkIdleFrames[nextFrameIndex];
tween(currentFrame, {
alpha: 0
}, {
duration: 150,
easing: tween.easeInOut
});
tween(nextFrame, {
alpha: 1
}, {
duration: 150,
easing: tween.easeInOut
});
self.currentBattleFrame = nextFrameIndex;
self.battleAnimationTimer = LK.setTimeout(function () {
self.startBattleIdleAnimation();
}, 200);
};
self.cleanup = function () {
if (self.battleAnimationTimer) {
LK.clearTimeout(self.battleAnimationTimer);
}
// Clean up dialogue boxes if they exist
if (self.playerDialogueBox) {
self.playerDialogueBox.destroy();
}
if (self.hunkDialogueBox) {
self.hunkDialogueBox.destroy();
}
// Clean up combat menu elements
if (self.combatMenu) {
self.combatMenu.destroy();
}
if (self.cursor) {
self.cursor.destroy();
}
self.destroy();
};
return self;
});
var Bloodmage = Container.expand(function () {
var self = Container.call(this);
var body = self.attachAsset('bloodmage', {
anchorX: 0.5,
anchorY: 1.0
});
self.velocityX = 0;
self.velocityY = 0;
self.grounded = false;
self.doubleJumpAvailable = true;
self.speed = 8;
self.jumpPower = 25;
self.gravity = 1.2;
self.isMoving = false;
self.idleFrames = [];
self.walkFrames = [];
self.currentIdleFrame = 0;
self.currentWalkFrame = 0;
self.idleAnimationTimer = 0;
self.walkAnimationTimer = 0;
self.jumpFrames = [];
self.currentJumpFrame = 0;
self.jumpAnimationTimer = 0;
self.isJumping = false;
self.facingDirection = -1; // -1 for right (assets face left), 1 for left
self.lastJumpTime = 0;
self.jumpCount = 0;
// Create idle animation frames with consistent scaling
var baseIdleScale = 1.0; // Standard scale for idle frames
self.idleFrames.push(self.attachAsset('playeridle', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0,
scaleX: baseIdleScale,
scaleY: baseIdleScale
}));
self.idleFrames.push(self.attachAsset('playeridle2', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0,
scaleX: baseIdleScale * 1.21,
// Adjust for narrower asset
scaleY: baseIdleScale
}));
self.idleFrames.push(self.attachAsset('playeridle3', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0,
scaleX: baseIdleScale * 1.04,
// Adjust for slightly narrower asset
scaleY: baseIdleScale
}));
self.idleFrames.push(self.attachAsset('playeridle4', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0,
scaleX: baseIdleScale * 0.96,
// Adjust for wider asset
scaleY: baseIdleScale
}));
self.idleFrames.push(self.attachAsset('playeridle5', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0,
scaleX: baseIdleScale * 1.05,
// Adjust for narrower asset
scaleY: baseIdleScale
}));
// Create walking animation frames with consistent scaling
var baseWalkScale = 1.0; // Standard scale for walk frames
self.walkFrames.push(self.attachAsset('playerwalk', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0,
scaleX: baseWalkScale * 0.70,
scaleY: baseWalkScale
}));
self.walkFrames.push(self.attachAsset('playerwalk2', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0,
scaleX: baseWalkScale * 1.05,
scaleY: baseWalkScale
}));
self.walkFrames.push(self.attachAsset('playerwalk3', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0,
scaleX: baseWalkScale * 0.85,
scaleY: baseWalkScale
}));
self.walkFrames.push(self.attachAsset('playerwalk4', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0,
scaleX: baseWalkScale * 0.60,
scaleY: baseWalkScale
}));
self.walkFrames.push(self.attachAsset('playerwalk5', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0,
scaleX: baseWalkScale * 0.60,
scaleY: baseWalkScale
}));
self.walkFrames.push(self.attachAsset('playerwalk6', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0,
scaleX: baseWalkScale * 0.58,
scaleY: baseWalkScale
}));
self.walkFrames.push(self.attachAsset('playerwalk7', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0,
scaleX: baseWalkScale * 1.20,
scaleY: baseWalkScale
}));
self.walkFrames.push(self.attachAsset('playerwalk8', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0,
scaleX: baseWalkScale * 0.60,
scaleY: baseWalkScale
}));
// Create jump animation frames with consistent scaling
var baseJumpScale = 1.0; // Standard scale for jump frames
self.jumpFrames.push(self.attachAsset('playerjump', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0,
scaleX: baseJumpScale * 0.60,
// Adjust for much wider asset
scaleY: baseJumpScale
}));
self.jumpFrames.push(self.attachAsset('playerjump2', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0,
scaleX: baseJumpScale * 0.55,
// Adjust for much wider asset
scaleY: baseJumpScale
}));
self.jumpFrames.push(self.attachAsset('playerjump3', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0,
scaleX: baseJumpScale * 0.52,
// Adjust for much wider asset
scaleY: baseJumpScale
}));
self.jumpFrames.push(self.attachAsset('playerjump4', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0,
scaleX: baseJumpScale * 0.58,
// Adjust for much wider asset
scaleY: baseJumpScale
}));
self.jumpFrames.push(self.attachAsset('playerjump5', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0,
scaleX: baseJumpScale * 0.56,
// Adjust for much wider asset
scaleY: baseJumpScale
}));
self.jumpFrames.push(self.attachAsset('playerjump6', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0,
scaleX: baseJumpScale * 0.57,
// Adjust for much wider asset
scaleY: baseJumpScale
}));
self.idleAnimationDirection = 1; // 1 for forward, -1 for reverse
self.startIdleAnimation = function () {
if (self.isMoving) return;
// Hide main body and walking frames, show current idle frame
body.alpha = 0;
for (var i = 0; i < self.walkFrames.length; i++) {
self.walkFrames[i].alpha = 0;
}
for (var i = 0; i < self.idleFrames.length; i++) {
self.idleFrames[i].alpha = i === self.currentIdleFrame ? 1 : 0;
}
// Smoothly fade out current frame and fade in next frame
var currentFrame = self.idleFrames[self.currentIdleFrame];
// Calculate next frame with direction
var nextFrameIndex = self.currentIdleFrame + self.idleAnimationDirection;
// Check if we need to reverse direction
if (nextFrameIndex >= self.idleFrames.length - 1) {
nextFrameIndex = self.idleFrames.length - 1;
self.idleAnimationDirection = -1;
} else if (nextFrameIndex <= 0) {
nextFrameIndex = 0;
self.idleAnimationDirection = 1;
}
var nextFrame = self.idleFrames[nextFrameIndex];
tween(currentFrame, {
alpha: 0
}, {
duration: 100,
easing: tween.easeInOut
});
tween(nextFrame, {
alpha: 1
}, {
duration: 100,
easing: tween.easeInOut
});
self.currentIdleFrame = nextFrameIndex;
// Schedule next frame change
self.idleAnimationTimer = LK.setTimeout(function () {
if (!self.isMoving) {
self.startIdleAnimation();
}
}, 150);
};
self.stopIdleAnimation = function () {
LK.clearTimeout(self.idleAnimationTimer);
// Hide main body and idle frames
body.alpha = 0;
for (var i = 0; i < self.idleFrames.length; i++) {
self.idleFrames[i].alpha = 0;
}
// Only start walking if we're actually moving
if (self.isMoving) {
self.startWalkingAnimation();
}
};
self.walkAnimationDirection = 1; // 1 for forward, -1 for reverse
self.startWalkingAnimation = function () {
if (!self.isMoving) return;
// Hide idle frames and show current walk frame
for (var i = 0; i < self.idleFrames.length; i++) {
self.idleFrames[i].alpha = 0;
}
for (var i = 0; i < self.walkFrames.length; i++) {
self.walkFrames[i].alpha = i === self.currentWalkFrame ? 1 : 0;
}
// Update facing direction based on velocity
if (self.velocityX > 0) self.facingDirection = -1; // Moving right, but assets face left by default
else if (self.velocityX < 0) self.facingDirection = 1; // Moving left, matches asset default
// Apply direction to all frames
for (var i = 0; i < self.walkFrames.length; i++) {
self.walkFrames[i].scale.x = Math.abs(self.walkFrames[i].scale.x) * self.facingDirection;
}
// Smoothly fade out current frame and fade in next frame
var currentFrame = self.walkFrames[self.currentWalkFrame];
// Calculate next frame with direction
var nextFrameIndex = self.currentWalkFrame + self.walkAnimationDirection;
// Check if we need to reverse direction
if (nextFrameIndex >= self.walkFrames.length - 1) {
nextFrameIndex = self.walkFrames.length - 1;
self.walkAnimationDirection = -1;
} else if (nextFrameIndex <= 0) {
nextFrameIndex = 0;
self.walkAnimationDirection = 1;
}
var nextFrame = self.walkFrames[nextFrameIndex];
tween(currentFrame, {
alpha: 0
}, {
duration: 50,
easing: tween.easeInOut
});
tween(nextFrame, {
alpha: 1
}, {
duration: 50,
easing: tween.easeInOut
});
self.currentWalkFrame = nextFrameIndex;
// Schedule next frame change
self.walkAnimationTimer = LK.setTimeout(function () {
if (self.isMoving) {
self.startWalkingAnimation();
}
}, 100);
};
self.stopWalkingAnimation = function () {
LK.clearTimeout(self.walkAnimationTimer);
// Hide walking frames
for (var i = 0; i < self.walkFrames.length; i++) {
self.walkFrames[i].alpha = 0;
}
};
self.startJumpAnimation = function () {
// Hide all other frames
body.alpha = 0;
for (var i = 0; i < self.idleFrames.length; i++) {
self.idleFrames[i].alpha = 0;
}
for (var i = 0; i < self.walkFrames.length; i++) {
self.walkFrames[i].alpha = 0;
}
// Apply direction to jump frames
for (var i = 0; i < self.jumpFrames.length; i++) {
self.jumpFrames[i].scale.x = Math.abs(self.jumpFrames[i].scale.x) * self.facingDirection;
}
// Calculate which frame to show based on jump progress
var jumpProgress = 0;
if (self.velocityY < -15) {
jumpProgress = 0; // Start of jump
} else if (self.velocityY < -5) {
jumpProgress = 1; // Rising
} else if (self.velocityY < 5) {
jumpProgress = 2; // Peak
} else if (self.velocityY < 15) {
jumpProgress = 3; // Falling
} else {
jumpProgress = 4; // Landing
}
// Ensure we don't go past available frames
var frameIndex = Math.min(jumpProgress, self.jumpFrames.length - 1);
// Show appropriate jump frame
for (var i = 0; i < self.jumpFrames.length; i++) {
self.jumpFrames[i].alpha = i === frameIndex ? 1 : 0;
}
};
self.stopJumpAnimation = function () {
// Hide all jump frames
for (var i = 0; i < self.jumpFrames.length; i++) {
self.jumpFrames[i].alpha = 0;
}
};
self.update = function () {
self.velocityY += self.gravity;
self.x += self.velocityX;
self.y += self.velocityY;
// Check if jumping
var wasJumping = self.isJumping;
self.isJumping = !self.grounded || Math.abs(self.velocityY) > 2;
// Handle animation state
var wasMoving = self.isMoving;
self.isMoving = Math.abs(self.velocityX) > 0.1;
if (self.isJumping) {
// Handle jump animation
if (!wasJumping) {
// Just started jumping
self.stopWalkingAnimation();
self.stopIdleAnimation();
}
self.startJumpAnimation();
} else {
// Not jumping
if (wasJumping) {
// Just landed
self.stopJumpAnimation();
if (self.isMoving) {
self.startWalkingAnimation();
} else {
self.startIdleAnimation();
}
} else {
// Ground movement
if (wasMoving && !self.isMoving) {
// Just stopped moving
self.stopWalkingAnimation();
self.startIdleAnimation();
} else if (!wasMoving && self.isMoving) {
// Just started moving
self.stopIdleAnimation();
}
}
}
};
self.jump = function () {
var jumpExecuted = false;
if (self.grounded) {
// First jump from ground
self.velocityY = -self.jumpPower;
self.grounded = false;
self.doubleJumpAvailable = true; // Reset double jump availability when leaving ground
LK.getSound('jump').play();
jumpExecuted = true;
} else if (self.doubleJumpAvailable && !self.grounded) {
// Double jump in air - always use higher power
self.velocityY = -self.jumpPower * 1.3;
self.doubleJumpAvailable = false;
LK.getSound('jump').play();
jumpExecuted = true;
// Create spell2 effect at the base of the character
var spellEffect = worldContainer.attachAsset('spell2', {
anchorX: 0.5,
anchorY: 0.5,
x: self.x,
y: self.y - 10,
// Position at base of character (shoes level)
alpha: 0.8
});
// Animate the spell effect - fade in and out quickly
tween(spellEffect, {
alpha: 0,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
spellEffect.destroy();
}
});
}
return jumpExecuted;
};
return self;
});
var Building = Container.expand(function () {
var self = Container.call(this);
// Randomly choose between building assets
var buildingAsset = Math.random() > 0.5 ? 'building' : 'Building2';
var building = self.attachAsset(buildingAsset, {
anchorX: 0.5,
anchorY: 0.95
});
building.tint = 0x2a2a2a + Math.floor(Math.random() * 0x222222);
// Randomly choose between neon sign assets
var neonAsset = Math.random() > 0.5 ? 'neonSign' : 'neonsign2';
var neonSign = self.attachAsset(neonAsset, {
anchorX: 0.5,
anchorY: 0.5,
x: Math.random() * 200 - 100,
y: -building.height * 0.5 + Math.random() * 100
});
neonSign.alpha = 0.8;
// Apply random tint to neon signs for variety
neonSign.tint = [0xFF00FF, 0x00FFFF, 0xFFFF00, 0xFF0088, 0x88FF00][Math.floor(Math.random() * 5)];
// Animate neon sign with smooth pulsing
var animDuration = 1500 + Math.random() * 1000;
var _animateNeonSign = function animateNeonSign() {
tween(neonSign, {
alpha: 0.3
}, {
duration: animDuration,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(neonSign, {
alpha: 0.8
}, {
duration: animDuration,
easing: tween.easeInOut,
onFinish: _animateNeonSign
});
}
});
};
_animateNeonSign();
return self;
});
var Hunk = Container.expand(function () {
var self = Container.call(this);
// Randomly select one of the 4 hunk types
var hunkAssets = ['hunk', 'hunk2', 'hunk3', 'hunk4'];
self.hunkType = Math.floor(Math.random() * hunkAssets.length);
var body = self.attachAsset(hunkAssets[self.hunkType], {
anchorX: 0.5,
anchorY: 1.0
});
// Different resistance values for different hunk types
self.resistance = [100, 120, 150, 80][self.hunkType];
self.maxResistance = self.resistance;
self.captured = false;
self.idleFrames = [];
self.currentIdleFrame = 0;
self.idleAnimationTimer = 0;
self.idleAnimationDirection = 1; // 1 for forward, -1 for reverse
self.startIdleAnimation = function () {
if (self.hunkType !== 0 && self.hunkType !== 1 && self.hunkType !== 2 && self.hunkType !== 3 || self.captured) return;
// Get current and next frame
var currentFrame = self.idleFrames[self.currentIdleFrame];
// Calculate next frame with direction
var nextFrameIndex = self.currentIdleFrame + self.idleAnimationDirection;
// Check if we need to reverse direction
if (nextFrameIndex >= self.idleFrames.length - 1) {
nextFrameIndex = self.idleFrames.length - 1;
self.idleAnimationDirection = -1;
} else if (nextFrameIndex <= 0) {
nextFrameIndex = 0;
self.idleAnimationDirection = 1;
}
var nextFrame = self.idleFrames[nextFrameIndex];
// Smoothly fade between frames
tween(currentFrame, {
alpha: 0
}, {
duration: 150,
easing: tween.easeInOut
});
tween(nextFrame, {
alpha: 1
}, {
duration: 150,
easing: tween.easeInOut
});
self.currentIdleFrame = nextFrameIndex;
// Schedule next frame change
self.idleAnimationTime = LK.setTimeout(function () {
if (!self.captured && (self.hunkType === 0 || self.hunkType === 1 || self.hunkType === 2 || self.hunkType === 3)) {
self.startIdleAnimation();
}
}, 200);
};
// If this is hunk (index 0), set up idle animation with hunk and hunka-e
if (self.hunkType === 0) {
// Hide main body for animated hunk as we'll use animation frames
body.alpha = 0;
// Create idle animation frames for mushroom hunk with consistent scaling
var baseHunkScale = 1.0;
self.idleFrames.push(self.attachAsset('hunk', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 1,
scaleX: baseHunkScale,
scaleY: baseHunkScale
}));
self.idleFrames.push(self.attachAsset('hunka', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0,
scaleX: baseHunkScale * 1.21,
// Adjust for narrower asset
scaleY: baseHunkScale
}));
self.idleFrames.push(self.attachAsset('hunkb', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0,
scaleX: baseHunkScale * 1.21,
// Adjust for narrower asset
scaleY: baseHunkScale
}));
self.idleFrames.push(self.attachAsset('hunkc', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0,
scaleX: baseHunkScale * 1.37,
// Adjust for much narrower asset
scaleY: baseHunkScale
}));
self.idleFrames.push(self.attachAsset('hunkd', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0,
scaleX: baseHunkScale * 0.63,
// Adjust for wider asset
scaleY: baseHunkScale
}));
self.idleFrames.push(self.attachAsset('hunke', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0,
scaleX: baseHunkScale * 1.07,
// Adjust for narrower asset
scaleY: baseHunkScale
}));
// Start idle animation
self.startIdleAnimation();
} else if (self.hunkType === 1) {
// Hide main body for animated hunk2 as we'll use animation frames
body.alpha = 0;
// Create idle animation frames for hunk2 with consistent scaling
var baseHunk2Scale = 1.0;
self.idleFrames.push(self.attachAsset('hunk2', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 1,
scaleX: baseHunk2Scale,
scaleY: baseHunk2Scale
}));
self.idleFrames.push(self.attachAsset('hunk2a', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0,
scaleX: baseHunk2Scale * 1.03,
// Adjust for slightly narrower asset
scaleY: baseHunk2Scale
}));
self.idleFrames.push(self.attachAsset('hunk2b', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0,
scaleX: baseHunk2Scale * 1.10,
// Adjust for narrower asset
scaleY: baseHunk2Scale
}));
self.idleFrames.push(self.attachAsset('hunk2c', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0,
scaleX: baseHunk2Scale * 1.35,
// Adjust for much narrower asset
scaleY: baseHunk2Scale
}));
self.idleFrames.push(self.attachAsset('hunk2d', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0,
scaleX: baseHunk2Scale * 0.98,
// Adjust for slightly wider asset
scaleY: baseHunk2Scale
}));
// Start idle animation
self.startIdleAnimation();
} else if (self.hunkType === 2) {
// Hide main body for animated hunk3 as we'll use animation frames
body.alpha = 0;
// Create idle animation frames for hunk3 with consistent scaling
var baseHunk3Scale = 1.0;
self.idleFrames.push(self.attachAsset('hunk3', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 1,
scaleX: baseHunk3Scale,
scaleY: baseHunk3Scale * 0.99
}));
self.idleFrames.push(self.attachAsset('hunk3a', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0,
//{7B}
scaleX: baseHunk3Scale * 1.04,
// Adjust for narrower asset
scaleY: baseHunk3Scale
}));
self.idleFrames.push(self.attachAsset('hunk3b', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0,
scaleX: baseHunk3Scale * 1.07,
// Adjust for narrower asset
scaleY: baseHunk3Scale
}));
self.idleFrames.push(self.attachAsset('hunk3c', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0,
scaleX: baseHunk3Scale * 1.04,
// Adjust for narrower asset
scaleY: baseHunk3Scale
}));
self.idleFrames.push(self.attachAsset('hunk3d', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0,
scaleX: baseHunk3Scale * 0.99,
// Adjust for slightly wider asset
scaleY: baseHunk3Scale
}));
// Start idle animation
self.startIdleAnimation();
} else if (self.hunkType === 3) {
// Hide main body for animated hunk4 as we'll use animation frames
body.alpha = 0;
// Create idle animation frames for hunk4 with consistent scaling
var baseHunk4Scale = 1.0;
self.idleFrames.push(self.attachAsset('hunk4', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 1,
scaleX: baseHunk4Scale,
scaleY: baseHunk4Scale
}));
self.idleFrames.push(self.attachAsset('hunk4a', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0,
scaleX: baseHunk4Scale * 1.26,
// Adjust for narrower asset
scaleY: baseHunk4Scale
}));
self.idleFrames.push(self.attachAsset('hunk4b', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0,
scaleX: baseHunk4Scale * 1.12,
// Adjust for narrower asset
scaleY: baseHunk4Scale
}));
self.idleFrames.push(self.attachAsset('hunk4c', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0,
scaleX: baseHunk4Scale * 1.18,
// Adjust for narrower asset
scaleY: baseHunk4Scale
}));
self.idleFrames.push(self.attachAsset('hunk4d', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0,
scaleX: baseHunk4Scale * 1.21,
// Adjust for narrower asset
scaleY: baseHunk4Scale
}));
// Start idle animation
self.startIdleAnimation();
}
self.stopIdleAnimation = function () {
if (self.idleAnimationTimer) {
LK.clearTimeout(self.idleAnimationTimer);
self.idleAnimationTimer = 0;
}
// Hide all idle frames
for (var i = 0; i < self.idleFrames.length; i++) {
self.idleFrames[i].alpha = 0;
}
};
// Override destroy to clean up animation
var originalDestroy = self.destroy;
self.destroy = function () {
self.stopIdleAnimation();
originalDestroy.call(self);
};
return self;
});
var Platform = Container.expand(function () {
var self = Container.call(this);
// Randomly select one of the 4 platform types
var platformAssets = ['platform', 'platform2', 'platform3', 'platform4'];
var selectedPlatform = platformAssets[Math.floor(Math.random() * platformAssets.length)];
var platform = self.attachAsset(selectedPlatform, {
anchorX: 0.5,
anchorY: 0.5
});
// Store platform type for reference
self.platformType = selectedPlatform;
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x0a0a0a
});
/****
* Game Code
****/
game.setBackgroundColor(0x0a0a0a);
var bloodmage = null;
var platforms = [];
var buildings = [];
var hunks = [];
var clouds = [];
var currentHunk = null;
var battleUI = null;
// Removed inBattle - using proximity-based battle UI instead
var cameraX = 0;
var worldContainer = null;
var trackpadPressed = false;
var trackpadAngle = 0;
var capturedHunks = storage.capturedHunks || [];
var brostiary = storage.brostiary || {};
var bropageOverlay = null;
var bropageShowing = false;
var currentBropageIndex = 0;
var lastJumpTime = 0;
var doubleTapThreshold = 300; // milliseconds for double tap detection
var lastGeneratedX = 0; // Track the rightmost generated position
var backgroundElements = []; // Track all background elements for cleanup
var spellProjectiles = []; // Track active spell projectiles
var isCasting = false; // Track if player is casting
worldContainer = game.addChild(new Container());
function generateLevelChunk(startX) {
// Generate background elements
var bgAssets = ['bg2', 'bg3', 'bg4'];
// Add layered backgrounds
for (var layer = 0; layer < 3; layer++) {
var bgAsset = bgAssets[layer];
var bg = worldContainer.attachAsset(bgAsset, {
anchorX: 0.5,
anchorY: 1.0,
x: startX + 2048,
y: 2732,
scaleX: 2.0 - layer * 0.3,
scaleY: 2.0 - layer * 0.3
});
bg.alpha = 0.3 + layer * 0.2;
backgroundElements.push(bg);
worldContainer.setChildIndex(bg, layer);
}
// Add statue as decoration
if (Math.random() > 0.7) {
var statue = worldContainer.attachAsset('statue', {
anchorX: 0.5,
anchorY: 1.0,
x: startX + Math.random() * 2000,
y: 2000,
scaleX: 0.8,
scaleY: 0.8
});
statue.tint = 0x666666;
backgroundElements.push(statue);
// Ensure statue stays behind platforms
var statueIndex = worldContainer.getChildIndex(statue);
worldContainer.setChildIndex(statue, Math.max(0, statueIndex - 10));
}
// Generate buildings
for (var i = 0; i < 4; i++) {
var building = new Building();
building.x = startX + 200 + i * 600;
building.y = 2000;
building.scale.x = 0.8 + Math.random() * 0.4;
building.scale.y = 0.8 + Math.random() * 0.4;
buildings.push(building);
worldContainer.addChild(building);
// Ensure buildings stay behind platforms
var buildingIndex = worldContainer.getChildIndex(building);
worldContainer.setChildIndex(building, Math.max(0, buildingIndex - 10));
}
// Generate lower clouds (beneath platforms)
for (var i = 0; i < 6; i++) {
var cloudAssets = ['cloud1', 'cloud2', 'cloud3'];
var cloudType = cloudAssets[Math.floor(Math.random() * cloudAssets.length)];
var cloud = worldContainer.attachAsset(cloudType, {
anchorX: 0.5,
anchorY: 0.5,
x: startX + Math.random() * 3000,
y: 2100 + Math.random() * 400 // Lower clouds
});
// Vary cloud sizes for depth
var cloudScale = 0.5 + Math.random() * 1.0;
cloud.scale.x = cloudScale;
cloud.scale.y = cloudScale;
// Make clouds semi-translucent with varying opacity
cloud.alpha = 0.3 + Math.random() * 0.4;
// Store drift speed for animation
cloud.driftSpeed = 0.5 + Math.random() * 1.5;
clouds.push(cloud);
// Ensure clouds stay behind platforms but in front of backgrounds
var cloudIndex = worldContainer.getChildIndex(cloud);
worldContainer.setChildIndex(cloud, Math.max(4, cloudIndex - 5));
}
// Generate upper clouds (among tall buildings)
for (var i = 0; i < 4; i++) {
var cloudAssets = ['cloud1', 'cloud2', 'cloud3'];
var cloudType = cloudAssets[Math.floor(Math.random() * cloudAssets.length)];
var cloud = worldContainer.attachAsset(cloudType, {
anchorX: 0.5,
anchorY: 0.5,
x: startX + Math.random() * 3000,
y: 800 + Math.random() * 600 // Upper clouds among buildings
});
// Make upper clouds larger and more translucent
var cloudScale = 0.8 + Math.random() * 1.5;
cloud.scale.x = cloudScale;
cloud.scale.y = cloudScale;
// More translucent for upper clouds
cloud.alpha = 0.2 + Math.random() * 0.3;
// Slower drift for upper clouds
cloud.driftSpeed = 0.3 + Math.random() * 0.8;
clouds.push(cloud);
// Ensure clouds stay behind platforms but in front of backgrounds
var cloudIndex = worldContainer.getChildIndex(cloud);
worldContainer.setChildIndex(cloud, Math.max(4, cloudIndex - 5));
}
// Generate platforms AFTER backgrounds and clouds to ensure they're in foreground
for (var i = 0; i < 6; i++) {
var platform = new Platform();
platform.x = startX + 300 + i * 500;
platform.y = 1600 - i % 3 * 200;
platforms.push(platform);
worldContainer.addChild(platform);
// Add hunks on some platforms
if (i % 2 === 1 && Math.random() > 0.3) {
var hunk = new Hunk();
hunk.x = platform.x;
hunk.y = platform.y - 20;
hunks.push(hunk);
worldContainer.addChild(hunk);
}
}
// Update last generated position
lastGeneratedX = startX + 3000;
}
function cleanupOldElements() {
var cleanupThreshold = cameraX - 3000;
// Cleanup old background elements
for (var i = backgroundElements.length - 1; i >= 0; i--) {
if (backgroundElements[i].x < cleanupThreshold) {
backgroundElements[i].destroy();
backgroundElements.splice(i, 1);
}
}
// Cleanup old buildings
for (var i = buildings.length - 1; i >= 0; i--) {
if (buildings[i].x < cleanupThreshold) {
buildings[i].destroy();
buildings.splice(i, 1);
}
}
// Cleanup old platforms
for (var i = platforms.length - 1; i >= 0; i--) {
if (platforms[i].x < cleanupThreshold) {
platforms[i].destroy();
platforms.splice(i, 1);
}
}
// Cleanup old hunks
for (var i = hunks.length - 1; i >= 0; i--) {
if (hunks[i].x < cleanupThreshold && hunks[i].captured) {
hunks[i].destroy();
hunks.splice(i, 1);
}
}
// Cleanup old clouds
for (var i = clouds.length - 1; i >= 0; i--) {
if (clouds[i].x < cleanupThreshold - 2000) {
clouds[i].destroy();
clouds.splice(i, 1);
}
}
}
function createLevel() {
// Add bg2 as the furthest background layer to fill empty spaces
var background2 = worldContainer.attachAsset('bg2', {
anchorX: 0.5,
anchorY: 1.0,
x: 2048,
y: 2732,
scaleX: 2.0,
scaleY: 2.0
});
// Add main background layer on top
var background = worldContainer.attachAsset('bg', {
anchorX: 0.5,
anchorY: 1.0,
x: 2048,
y: 2732,
scaleX: 0.8,
scaleY: 0.8
});
// Add additional colored background shapes to fill gaps
var bg3 = worldContainer.attachAsset('bg3', {
anchorX: 0.5,
anchorY: 1.0,
x: 2048,
y: 2732,
scaleX: 30,
scaleY: 15
});
bg3.alpha = 0.3;
worldContainer.setChildIndex(bg3, 0); // Put behind other backgrounds
var bg4 = worldContainer.attachAsset('bg4', {
anchorX: 0.5,
anchorY: 1.0,
x: 2048,
y: 2732,
scaleX: 25,
scaleY: 12
});
bg4.alpha = 0.2;
worldContainer.setChildIndex(bg4, 1); // Put behind main backgrounds
// Create clouds drifting beneath the starting platform
for (var i = 0; i < 12; i++) {
var cloudAssets = ['cloud1', 'cloud2', 'cloud3'];
var cloudType = cloudAssets[Math.floor(Math.random() * cloudAssets.length)];
var cloud = worldContainer.attachAsset(cloudType, {
anchorX: 0.5,
anchorY: 0.5,
x: Math.random() * 4096 - 1024,
// Spread across wider area
y: 2100 + Math.random() * 400 // Position below starting platform (1800-2000)
});
// Vary cloud sizes for depth
var cloudScale = 0.5 + Math.random() * 1.0;
cloud.scale.x = cloudScale;
cloud.scale.y = cloudScale;
// Make clouds semi-translucent with varying opacity
cloud.alpha = 0.3 + Math.random() * 0.4;
// Store initial position and drift speed for animation
cloud.initialX = cloud.x;
cloud.driftSpeed = 0.5 + Math.random() * 1.5;
clouds.push(cloud);
// Put clouds behind platforms but in front of backgrounds
worldContainer.setChildIndex(cloud, 4 + i);
}
// Create more buildings with varied positioning to fill the midground
for (var i = 0; i < 8; i++) {
var building = new Building();
building.x = 200 + i * 600;
building.y = 2000; // Position at ground level so buildings meet platforms
building.scale.x = 0.8 + Math.random() * 0.4; // Vary building sizes
building.scale.y = 0.8 + Math.random() * 0.4;
buildings.push(building);
worldContainer.addChild(building);
}
var ground = new Platform();
ground.x = 1024;
ground.y = 2000;
ground.scale.x = 10;
platforms.push(ground);
worldContainer.addChild(ground);
for (var i = 0; i < 8; i++) {
var platform = new Platform();
platform.x = 300 + i * 500;
platform.y = 1600 - i % 3 * 200;
platforms.push(platform);
worldContainer.addChild(platform);
// Add door on the third platform
if (i === 2) {
var door = worldContainer.attachAsset('door', {
anchorX: 0.5,
anchorY: 1.0,
x: platform.x,
y: platform.y - 20,
scaleX: 0.8,
scaleY: 0.8
});
door.interactive = true;
door.platformIndex = i; // Store platform reference
doorAsset = door; // Store global reference for interaction detection
// Add hidesign floating over door with proper layering
var hideSign = worldContainer.attachAsset('hidesign', {
anchorX: 0.5,
anchorY: 1.0,
x: platform.x,
y: platform.y - 600,
// Position higher above door
scaleX: 4,
scaleY: 4
});
// Make hidesign interactive for direct shop access
hideSign.interactive = true;
hideSign.down = function (x, y, obj) {
enterShop();
};
// Ensure hidesign appears above door and other elements
worldContainer.setChildIndex(hideSign, worldContainer.children.length - 1);
// Animate sign floating
var _animateSign = function animateSign() {
tween(hideSign, {
y: platform.y - 330
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(hideSign, {
y: platform.y - 370
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: _animateSign
});
}
});
};
_animateSign();
}
// Only spawn hunks on platforms that are far enough from starting position
if (i % 2 === 1 && i > 1 && i !== 2) {
// Skip first potential hunk spawn (i=1) and door platform (i=2)
var hunk = new Hunk();
hunk.x = platform.x;
hunk.y = platform.y - 20;
hunks.push(hunk);
worldContainer.addChild(hunk);
}
}
bloodmage = new Bloodmage();
bloodmage.x = 150;
bloodmage.y = 1800;
worldContainer.addChild(bloodmage);
// Start idle animation initially
bloodmage.startIdleAnimation();
// Track initial generation position
lastGeneratedX = 4000;
}
createLevel();
var trackpadBg = LK.gui.bottomLeft.attachAsset('trackpadBg', {
anchorX: 0.5,
anchorY: 0.5,
x: 200,
y: -200
});
trackpadBg.interactive = true;
var trackpadThumb = LK.gui.bottomLeft.attachAsset('trackpadThumb', {
anchorX: 0.5,
anchorY: 0.5,
x: 200,
y: -200
});
var jumpBtn = LK.gui.bottomRight.attachAsset('jumpButton', {
anchorX: 0.5,
anchorY: 0.5,
x: -200,
y: -200
});
jumpBtn.interactive = true;
var actionBtn = LK.gui.bottomRight.attachAsset('actionbutton', {
anchorX: 0.5,
anchorY: 0.5,
x: -200,
y: -450
});
actionBtn.interactive = true;
// Direct event handlers for better responsiveness
trackpadBg.down = function (x, y, obj) {
if (battleMenuVisible || bropageShowing || shopShowing) return;
trackpadPressed = true;
updateTrackpad(x, y);
};
trackpadBg.move = function (x, y, obj) {
if (!trackpadPressed || battleMenuVisible || bropageShowing || shopShowing) return;
updateTrackpad(x, y);
};
trackpadBg.up = function () {
trackpadPressed = false;
if (bloodmage) {
bloodmage.velocityX = 0;
}
trackpadThumb.x = 200;
trackpadThumb.y = -200;
};
jumpBtn.down = function () {
if (bloodmage && !battleMenuVisible && !bropageShowing && !shopShowing) {
var _animateButtonBlink = function animateButtonBlink() {
if (currentBlinkFrame < blinkFrames.length) {
// Get the current frame asset and apply it to the button
var frameAsset = LK.getAsset(blinkFrames[currentBlinkFrame], {
anchorX: 0.5,
anchorY: 0.5
});
// Replace button content temporarily
// Keep jump button visible - just layer blink on top
// Add blink frame to GUI
var blinkFrame = LK.gui.bottomRight.addChild(frameAsset);
blinkFrame.x = -200;
blinkFrame.y = -200;
blinkFrame.alpha = 0;
blinkFrame.scale.x = 0.8;
blinkFrame.scale.y = 0.8;
// Animate the blink frame with smooth scaling
tween(blinkFrame, {
alpha: 0.8,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 60,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(blinkFrame, {
alpha: 0,
scaleX: 1.4,
scaleY: 1.4
}, {
duration: 60,
easing: tween.easeIn,
onFinish: function onFinish() {
blinkFrame.destroy();
currentBlinkFrame++;
if (currentBlinkFrame < blinkFrames.length) {
_animateButtonBlink();
}
}
});
}
});
}
};
// Start button blink animation
var blinkFrames = ['buttonblink', 'buttonblink2', 'buttonblink3', 'buttonblink4'];
var currentBlinkFrame = 0;
_animateButtonBlink();
var currentTime = Date.now();
var timeSinceLastJump = currentTime - bloodmage.lastJumpTime;
// Check for double tap timing
if (timeSinceLastJump < doubleTapThreshold && bloodmage.jumpCount === 1 && bloodmage.grounded) {
// Double tap detected - perform higher jump
bloodmage.velocityY = -bloodmage.jumpPower * 1.5;
bloodmage.grounded = false;
bloodmage.doubleJumpAvailable = true;
LK.getSound('jump').play();
bloodmage.jumpCount = 0; // Reset for next sequence
} else {
// Normal jump attempt
var jumpSuccess = bloodmage.jump();
if (jumpSuccess) {
bloodmage.lastJumpTime = currentTime;
bloodmage.jumpCount = bloodmage.grounded ? 1 : 0; // Track if this was first jump
}
}
}
};
var jumpText = new Text2('JUMP', {
size: 40,
fill: 0xFFFFFF
});
jumpText.anchor.set(0.5, 0.5);
jumpBtn.addChild(jumpText);
var actionText = new Text2('CAST', {
size: 40,
fill: 0xFFFFFF
});
actionText.anchor.set(0.5, 0.5);
actionBtn.addChild(actionText);
actionBtn.down = function () {
if (bloodmage && !battleMenuVisible && !bropageShowing && !shopShowing && !isCasting) {
// Check if player is near door using the stored door reference
var nearDoor = false;
if (doorAsset) {
var dx = Math.abs(bloodmage.x - doorAsset.x);
var dy = Math.abs(bloodmage.y - doorAsset.y);
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 300) {
// Increased detection range further
nearDoor = true;
enterShop();
return; // Exit early to prevent casting
}
}
// Only cast spell if explicitly not near door
if (!nearDoor) {
castPlayerSpell();
}
}
};
var scoreText = new Text2('Hunks: ' + capturedHunks.length, {
size: 60,
fill: 0xFF00FF
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
// Add brostiary icon to top right corner
var brostiaryIcon = LK.gui.topRight.attachAsset('brostiary', {
anchorX: 0.5,
anchorY: 0.5,
x: -150,
y: 150,
scaleX: 1.5,
scaleY: 1.5
});
brostiaryIcon.interactive = true;
brostiaryIcon.down = function () {
showBropage();
};
// Updated shop items with plush varieties and crystal hearts
var shopOverlay = null;
var shopShowing = false;
var currentShopPage = 0;
var shopItems = [{
name: 'crystalheart',
asset: 'crystalheart',
price: 50,
description: 'MYSTICAL CRYSTAL WITH ARCANE PROPERTIES',
useDisplay: true
}, {
name: 'plush',
asset: 'plush',
price: 30,
description: 'ADORABLE COMPANION FOR LONELY NIGHTS',
useShelf: true
}, {
name: 'plush2',
asset: 'plush2',
price: 35,
description: 'CUTE CUDDLY FRIEND',
useShelf: true
}, {
name: 'plush3',
asset: 'plush3',
price: 40,
description: 'PREMIUM PLUSH COMPANION',
useShelf: true
}, {
name: 'crystalheart',
asset: 'crystalheart',
price: 75,
description: 'RARE MYSTICAL HEART CRYSTAL',
useDisplay: true
}, {
name: 'crystalheart',
asset: 'crystalheart',
price: 100,
description: 'LEGENDARY HEART OF POWER',
useDisplay: true
}];
function showBropage() {
if (bropageShowing || battleMenuVisible) return;
bropageShowing = true;
currentBropageIndex = 0;
// Create overlay container
bropageOverlay = game.addChild(new Container());
// Add bropage background
var bgOverlay = bropageOverlay.attachAsset('bropage', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1366,
scaleX: 2,
scaleY: 2.5
});
bgOverlay.alpha = 0.95;
// Add exit button (X) in upper right corner
var exitButton = bropageOverlay.attachAsset('x', {
anchorX: 0.5,
anchorY: 0.5,
x: 1800,
y: 400,
scaleX: 1.2,
scaleY: 1.2
});
exitButton.interactive = true;
exitButton.down = function () {
closeBropage();
};
// Create function to display current hunk entry
var _displayHunkEntry = function displayHunkEntry() {
// Clear previous content (except background and exit button)
for (var i = bropageOverlay.children.length - 1; i >= 2; i--) {
bropageOverlay.children[i].destroy();
}
var hunkAssets = ['hunk', 'hunk2', 'hunk3', 'hunk4'];
var hunkNames = ['MUSHROOM HUNK', 'CYBER HUNK', 'MEGA HUNK', 'MINOTAUR HUNK'];
var hunkDescriptions = ['A MYSTERIOUS FUNGAL BEING WITH HYPNOTIC SPORES THAT CAN ENTRANCE ENEMIES.', 'A DIGITAL WARRIOR FROM THE CYBER REALM WITH ELECTROMAGNETIC POWERS.', 'AN ENORMOUS POWERHOUSE WITH INCREDIBLE STRENGTH AND ENDURANCE.', 'A POWERFUL BULL-HEADED WARRIOR WITH ANCIENT COMBAT TECHNIQUES AND BERSERKER RAGE.'];
var hunkAttacks = [['SPORE BURST', 'MIND MELD', 'FUNGAL SHIELD'], ['DATA DRAIN', 'FIREWALL', 'SYSTEM CRASH'], ['GROUND POUND', 'BULK UP', 'RAMPAGE'], ['HORN CHARGE', 'BERSERKER RAGE', 'BULL RUSH']];
var hunkStats = [{
hp: 100,
power: 25,
defense: 20,
speed: 15
}, {
hp: 120,
power: 30,
defense: 25,
speed: 20
}, {
hp: 150,
power: 40,
defense: 35,
speed: 10
}, {
hp: 80,
power: 35,
defense: 15,
speed: 30
}];
// Hunk image in upper left frame (positioned to fit within the frame outline)
if (brostiary[currentBropageIndex]) {
var hunkImage = bropageOverlay.attachAsset(hunkAssets[currentBropageIndex], {
anchorX: 0.5,
anchorY: 0.5,
x: 600,
y: 800,
scaleX: 1.0,
scaleY: 1.0
});
} else {
// Show silhouette or placeholder for uncaptured hunks
var placeholder = new Text2('?', {
size: 150,
fill: 0x666666
});
placeholder.anchor.set(0.5, 0.5);
placeholder.x = 600;
placeholder.y = 800;
bropageOverlay.addChild(placeholder);
}
// Hunk name (positioned in top left name field)
var nameText = new Text2(hunkNames[currentBropageIndex], {
size: 80,
fill: brostiary[currentBropageIndex] ? 0x00FFFF : 0x666666
});
nameText.anchor.set(0, 0.5);
nameText.x = 350;
nameText.y = 550;
bropageOverlay.addChild(nameText);
// Bio section (bottom right boxed area - positioned within asset's bio box)
if (brostiary[currentBropageIndex]) {
var descText = new Text2(hunkDescriptions[currentBropageIndex], {
size: 36,
fill: 0xFFFFFF,
wordWrap: true,
wordWrapWidth: 550
});
descText.anchor.set(0, 0);
descText.x = 1150;
descText.y = 1700;
bropageOverlay.addChild(descText);
// Attacks section (lower left side - positioned within asset's attacks box)
var attacks = hunkAttacks[currentBropageIndex];
for (var i = 0; i < attacks.length; i++) {
var attackText = new Text2(attacks[i], {
size: 42,
fill: 0xFFFF00
});
attackText.anchor.set(0, 0);
attackText.x = 380;
attackText.y = 1720 + i * 70;
bropageOverlay.addChild(attackText);
}
// Stats section (positioned within asset's stats area)
var stats = hunkStats[currentBropageIndex];
var statLabels = ['HP: ', 'POWER: ', 'DEFENSE: ', 'SPEED: '];
var statValues = [stats.hp, stats.power, stats.defense, stats.speed];
for (var i = 0; i < statLabels.length; i++) {
var statText = new Text2(statLabels[i] + statValues[i], {
size: 48,
fill: 0x00FF00
});
statText.anchor.set(0, 0);
statText.x = 1200;
statText.y = 1050 + i * 70;
bropageOverlay.addChild(statText);
}
} else {
var lockedText = new Text2('⚠ DATA ENCRYPTED ⚠', {
size: 80,
fill: 0xFF0000
});
lockedText.anchor.set(0.5, 0.5);
lockedText.x = 1024;
lockedText.y = 1400;
bropageOverlay.addChild(lockedText);
var sublockText = new Text2('CAPTURE HUNK TO UNLOCK', {
size: 50,
fill: 0x888888
});
sublockText.anchor.set(0.5, 0.5);
sublockText.x = 1024;
sublockText.y = 1500;
bropageOverlay.addChild(sublockText);
}
// Navigation arrows
// Previous arrow
if (currentBropageIndex > 0) {
var prevArrow = new Text2('◄', {
size: 120,
fill: 0xFFFF00
});
prevArrow.anchor.set(0.5, 0.5);
prevArrow.x = 250;
prevArrow.y = 1366;
prevArrow.interactive = true;
prevArrow.down = function () {
currentBropageIndex--;
_displayHunkEntry();
};
bropageOverlay.addChild(prevArrow);
}
// Next arrow
if (currentBropageIndex < 3) {
var nextArrow = new Text2('►', {
size: 120,
fill: 0xFFFF00
});
nextArrow.anchor.set(0.5, 0.5);
nextArrow.x = 1774;
nextArrow.y = 1366;
nextArrow.interactive = true;
nextArrow.down = function () {
currentBropageIndex++;
_displayHunkEntry();
};
bropageOverlay.addChild(nextArrow);
}
// Page indicator
var pageText = new Text2('[ ' + (currentBropageIndex + 1) + ' / 4 ]', {
size: 60,
fill: 0xFFFFFF
});
pageText.anchor.set(0.5, 0.5);
pageText.x = 1024;
pageText.y = 1750;
bropageOverlay.addChild(pageText);
};
// Display first entry
_displayHunkEntry();
}
function closeBropage() {
if (!bropageShowing || !bropageOverlay) return;
bropageShowing = false;
bropageOverlay.destroy();
bropageOverlay = null;
}
var doorAsset = null;
var hideSignAsset = null;
for (var i = 0; i < worldContainer.children.length; i++) {
var child = worldContainer.children[i];
if (child.texture && child.texture.baseTexture && child.texture.baseTexture.resource && child.texture.baseTexture.resource.url && child.texture.baseTexture.resource.url.includes('door')) {
doorAsset = child;
// Add direct door interaction
doorAsset.down = function (x, y, obj) {
enterShop();
};
} else if (child.texture && child.texture.baseTexture && child.texture.baseTexture.resource && child.texture.baseTexture.resource.url && child.texture.baseTexture.resource.url.includes('hidesign')) {
hideSignAsset = child;
// Add direct sign interaction
hideSignAsset.interactive = true;
hideSignAsset.down = function (x, y, obj) {
enterShop();
};
}
}
function enterShop() {
if (shopShowing || battleMenuVisible) return;
shopShowing = true;
currentShopPage = 0;
// Create transition overlay
var transitionOverlay = game.addChild(new Container());
// Start with door asset that expands
var expandingDoor = transitionOverlay.attachAsset('door', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1366,
scaleX: 0.1,
scaleY: 0.1,
alpha: 0.8
});
// Animate door expanding with enhanced transition
tween(expandingDoor, {
scaleX: 6.0,
scaleY: 6.0,
alpha: 0.9
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
// Create the actual shop overlay
shopOverlay = game.addChild(new Container());
// Add shop background - single main asset properly sized
var shopBg = shopOverlay.attachAsset('shop', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1366,
scaleX: 0.1,
scaleY: 0.1,
alpha: 0
});
tween(shopBg, {
scaleX: 2.0,
scaleY: 2.7,
alpha: 0.95
}, {
duration: 600,
easing: tween.easeOut
});
// Add shop2 as overlay detail
var shopDetail = shopOverlay.attachAsset('shop2', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1366,
scaleX: 0.1,
scaleY: 0.1,
alpha: 0
});
tween(shopDetail, {
scaleX: 2.0,
scaleY: 2.7,
alpha: 0.6
}, {
duration: 700,
easing: tween.easeOut
});
// Add Mandroid character with entrance animation
var mandroid = shopOverlay.attachAsset('mandroid', {
anchorX: 0.5,
anchorY: 1.0,
x: 350,
y: 1800,
scaleX: 0.1,
scaleY: 0.1,
alpha: 0
});
tween(mandroid, {
scaleX: 2.5,
scaleY: 2.5,
alpha: 1
}, {
duration: 700,
easing: tween.bounceOut
});
// Add dialogue box
var dialogueBox = shopOverlay.attachAsset('dialoguebox', {
anchorX: 0.5,
anchorY: 0.5,
x: 1400,
y: 1000,
scaleX: 12,
scaleY: 8,
alpha: 0
});
tween(dialogueBox, {
alpha: 1
}, {
duration: 500,
easing: tween.easeOut
});
// Add Mandroid's name with innuendo
var mandroidName = new Text2('HARD-WARE', {
size: 180,
fill: 0xFFFFFF,
fontWeight: 'bold'
});
mandroidName.anchor.set(0.5, 0.5);
mandroidName.x = 350;
mandroidName.y = 1200;
mandroidName.alpha = 0;
// Add hot pink glow effect
mandroidName.style = {
fontSize: 180,
fill: 0xFFFFFF,
fontWeight: 'bold',
dropShadow: true,
dropShadowColor: 0xFF1493,
dropShadowBlur: 25,
dropShadowDistance: 0
};
shopOverlay.addChild(mandroidName);
tween(mandroidName, {
alpha: 1
}, {
duration: 600,
easing: tween.easeOut
});
// Flirtatious dialogue options
var dialogueOptions = ["WELCOME TO MY BOUTIQUE, GORGEOUS~ *MECHANICAL PURR*", "FANCY SOME PREMIUM HARDWARE? I'VE GOT WHAT YOU NEED~", "MY CIRCUITS ARE OVERHEATING JUST LOOKING AT YOU, SUGAR", "CARE TO BROWSE MY... EXTENSIVE COLLECTION? *WINK*", "I SPECIALIZE IN BOTH FASHION AND... HARDER TO FIND ITEMS~"];
var currentDialogue = dialogueOptions[Math.floor(Math.random() * dialogueOptions.length)];
var dialogueText = new Text2(currentDialogue, {
size: 96,
fill: 0xFFFFFF,
fontWeight: 'bold',
wordWrap: true,
wordWrapWidth: 800
});
dialogueText.anchor.set(0.5, 0.5);
dialogueText.x = 1450;
dialogueText.y = 1000;
dialogueText.alpha = 0;
// Add hot pink glow
dialogueText.style = {
fontSize: 96,
fill: 0xFFFFFF,
fontWeight: 'bold',
dropShadow: true,
dropShadowColor: 0xFF1493,
dropShadowBlur: 20,
dropShadowDistance: 0,
wordWrap: true,
wordWrapWidth: 800
};
shopOverlay.addChild(dialogueText);
tween(dialogueText, {
alpha: 1
}, {
duration: 800,
easing: tween.easeOut
});
// Add exit button (X) in upper left corner
var exitButton = shopOverlay.attachAsset('x', {
anchorX: 0.5,
anchorY: 0.5,
x: 200,
y: 200,
scaleX: 2.0,
scaleY: 2.0,
alpha: 0
});
exitButton.interactive = true;
exitButton.down = function () {
closeShop();
};
tween(exitButton, {
alpha: 1
}, {
duration: 500,
easing: tween.easeOut
});
// Display shop items with delay
LK.setTimeout(function () {
displayShopItems();
}, 1000);
// Add navigation buttons
var prevButton = new Text2('◄ PREV', {
size: 100,
fill: 0xFFFFFF,
fontWeight: 'bold'
});
prevButton.anchor.set(0.5, 0.5);
prevButton.x = 200;
prevButton.y = 2400;
prevButton.interactive = true;
prevButton.alpha = 0;
// Add hot pink glow
prevButton.style = {
fontSize: 100,
fill: 0xFFFFFF,
fontWeight: 'bold',
dropShadow: true,
dropShadowColor: 0xFF1493,
dropShadowBlur: 15,
dropShadowDistance: 0
};
prevButton.down = function () {
if (currentShopPage > 0) {
currentShopPage--;
displayShopItems();
}
};
shopOverlay.addChild(prevButton);
tween(prevButton, {
alpha: 1
}, {
duration: 600,
easing: tween.easeOut
});
var nextButton = new Text2('NEXT ►', {
size: 100,
fill: 0xFFFFFF,
fontWeight: 'bold'
});
nextButton.anchor.set(0.5, 0.5);
nextButton.x = 1800;
nextButton.y = 2400;
nextButton.interactive = true;
nextButton.alpha = 0;
// Add hot pink glow
nextButton.style = {
fontSize: 100,
fill: 0xFFFFFF,
fontWeight: 'bold',
dropShadow: true,
dropShadowColor: 0xFF1493,
dropShadowBlur: 15,
dropShadowDistance: 0
};
nextButton.down = function () {
var maxPages = Math.ceil(shopItems.length / 3) - 1;
if (currentShopPage < maxPages) {
currentShopPage++;
displayShopItems();
}
};
shopOverlay.addChild(nextButton);
tween(nextButton, {
alpha: 1
}, {
duration: 600,
easing: tween.easeOut
});
// Add currency display
var currencyText = new Text2('HUNKS: ' + capturedHunks.length, {
size: 100,
fill: 0x00FF00,
fontWeight: 'bold'
});
currencyText.anchor.set(0.5, 0.5);
currencyText.x = 1024;
currencyText.y = 2500;
currencyText.alpha = 0;
// Add hot pink glow
currencyText.style = {
fontSize: 100,
fill: 0x00FF00,
fontWeight: 'bold',
dropShadow: true,
dropShadowColor: 0xFF1493,
dropShadowBlur: 15,
dropShadowDistance: 0
};
shopOverlay.addChild(currencyText);
tween(currencyText, {
alpha: 1
}, {
duration: 600,
easing: tween.easeOut
});
function displayShopItems() {
// Clear previous items (keep first 10 children which are backgrounds and UI)
while (shopOverlay.children.length > 10) {
shopOverlay.children[shopOverlay.children.length - 1].destroy();
}
var itemsPerPage = 3;
var startIndex = currentShopPage * itemsPerPage;
var endIndex = Math.min(startIndex + itemsPerPage, shopItems.length);
for (var i = startIndex; i < endIndex; i++) {
var item = shopItems[i];
var localIndex = i - startIndex;
var itemX = 600 + localIndex * 400;
var itemY = 1800;
// Add appropriate display platform
if (item.useDisplay) {
// Display platform for crystal hearts
var displayPlatform = shopOverlay.attachAsset('displayplatform', {
anchorX: 0.5,
anchorY: 0.5,
x: itemX,
y: itemY + 20,
scaleX: 3,
scaleY: 3
});
} else if (item.useShelf) {
// Shelf for plush items
var platShelf = shopOverlay.attachAsset('platshelf', {
anchorX: 0.5,
anchorY: 0.5,
x: itemX,
y: itemY + 30,
scaleX: 4,
scaleY: 4
});
}
// Item asset
var itemAsset = shopOverlay.attachAsset(item.asset, {
anchorX: 0.5,
anchorY: 0.5,
x: itemX,
y: itemY - 50,
scaleX: 2,
scaleY: 2
});
// Create item name using alphabet assets
var nameLetters = item.name.toLowerCase();
var letterSpacing = 25;
var startX = itemX - nameLetters.length * letterSpacing / 2;
for (var j = 0; j < nameLetters.length; j++) {
var letter = nameLetters[j];
if (letter !== ' ') {
var letterAsset = shopOverlay.attachAsset(letter, {
anchorX: 0.5,
anchorY: 0.5,
x: startX + j * letterSpacing,
y: itemY + 80,
scaleX: 0.8,
scaleY: 0.8
});
}
}
// Item price
var itemPrice = new Text2('PRICE: ' + item.price, {
size: 56,
fill: 0xFFFF00,
fontWeight: 'bold'
});
itemPrice.anchor.set(0.5, 0.5);
itemPrice.x = itemX;
itemPrice.y = itemY + 120;
// Add hot pink glow
itemPrice.style = {
fontSize: 56,
fill: 0xFFFF00,
fontWeight: 'bold',
dropShadow: true,
dropShadowColor: 0xFF1493,
dropShadowBlur: 15,
dropShadowDistance: 0
};
shopOverlay.addChild(itemPrice);
// Item description
var itemDesc = new Text2(item.description, {
size: 40,
fill: 0xFFFFFF,
fontWeight: 'bold',
wordWrap: true,
wordWrapWidth: 300
});
itemDesc.anchor.set(0.5, 0.5);
itemDesc.x = itemX;
itemDesc.y = itemY + 180;
// Add hot pink glow
itemDesc.style = {
fontSize: 40,
fill: 0xFFFFFF,
fontWeight: 'bold',
dropShadow: true,
dropShadowColor: 0xFF1493,
dropShadowBlur: 15,
dropShadowDistance: 0,
wordWrap: true,
wordWrapWidth: 300
};
shopOverlay.addChild(itemDesc);
// Buy button
var buyButton = new Text2('BUY', {
size: 80,
fill: capturedHunks.length >= item.price ? 0x00FF00 : 0xFF0000,
fontWeight: 'bold'
});
buyButton.anchor.set(0.5, 0.5);
buyButton.x = itemX;
buyButton.y = itemY + 240;
buyButton.interactive = true;
// Add hot pink glow
buyButton.style = {
fontSize: 80,
fill: capturedHunks.length >= item.price ? 0x00FF00 : 0xFF0000,
fontWeight: 'bold',
dropShadow: true,
dropShadowColor: 0xFF1493,
dropShadowBlur: 15,
dropShadowDistance: 0
};
buyButton.down = function (itemIndex) {
return function () {
purchaseItem(itemIndex);
};
}(i);
shopOverlay.addChild(buyButton);
}
// Update navigation buttons
prevButton.alpha = currentShopPage > 0 ? 1 : 0.3;
var maxPages = Math.ceil(shopItems.length / 3) - 1;
nextButton.alpha = currentShopPage < maxPages ? 1 : 0.3;
// Update currency display
currencyText.setText('HUNKS: ' + capturedHunks.length);
}
// Clean up transition
transitionOverlay.destroy();
}
});
}
function showShop() {
enterShop();
}
function purchaseItem(itemIndex) {
var item = shopItems[itemIndex];
if (capturedHunks.length >= item.price) {
// Remove hunks as currency
for (var i = 0; i < item.price; i++) {
capturedHunks.pop();
}
storage.capturedHunks = capturedHunks;
scoreText.setText('Hunks: ' + capturedHunks.length);
// Show purchase success
LK.effects.flashScreen(0x00FF00, 500);
// Update Mandroid's dialogue
var successDialogues = ["EXCELLENT CHOICE, DARLING~ *MECHANICAL SATISFACTION*", "PLEASURE DOING BUSINESS WITH SUCH A STUNNING CUSTOMER~", "YOUR TASTE IS AS EXQUISITE AS YOUR APPEARANCE, SWEETIE", "COME BACK ANYTIME, BEAUTIFUL~ I'LL BE WAITING~"];
var dialogueText = shopOverlay.children.find(function (child) {
return child instanceof Text2 && child.x === 1400 && child.y === 1000;
});
if (dialogueText) {
dialogueText.setText(successDialogues[Math.floor(Math.random() * successDialogues.length)]);
}
displayShopItems();
} else {
// Not enough currency
LK.effects.flashScreen(0xFF0000, 500);
var dialogueText = shopOverlay.children.find(function (child) {
return child instanceof Text2 && child.x === 1400 && child.y === 1000;
});
if (dialogueText) {
dialogueText.setText("NOT ENOUGH HUNKS, SUGAR~ COME BACK WHEN YOU'RE RICHER");
}
}
}
function closeShop() {
if (!shopShowing || !shopOverlay) return;
shopShowing = false;
shopOverlay.destroy();
shopOverlay = null;
}
function castPlayerSpell() {
if (!bloodmage || isCasting) return;
isCasting = true;
LK.getSound('spell').play();
// Stop all animations first
bloodmage.stopIdleAnimation();
bloodmage.stopWalkingAnimation();
bloodmage.stopJumpAnimation();
// Hide ALL assets in bloodmage to ensure nothing remains visible
for (var i = 0; i < bloodmage.children.length; i++) {
bloodmage.children[i].alpha = 0;
}
// Hide all other frames
for (var i = 0; i < bloodmage.idleFrames.length; i++) {
bloodmage.idleFrames[i].alpha = 0;
}
for (var i = 0; i < bloodmage.walkFrames.length; i++) {
bloodmage.walkFrames[i].alpha = 0;
}
for (var i = 0; i < bloodmage.jumpFrames.length; i++) {
bloodmage.jumpFrames[i].alpha = 0;
}
// Create cast animation frames
var castFrames = ['cast', 'cast2', 'cast3', 'cast4', 'cast5', 'cast6', 'cast7', 'cast8', 'cast9'];
var castAnimFrames = [];
for (var i = 0; i < castFrames.length; i++) {
var frame = worldContainer.attachAsset(castFrames[i], {
anchorX: 0.5,
anchorY: 1.0,
x: bloodmage.x,
y: bloodmage.y,
alpha: 0
});
frame.scale.x = bloodmage.facingDirection;
castAnimFrames.push(frame);
}
// Animate through cast frames with smooth transitions
var currentCastFrame = 0;
function animateCast() {
if (currentCastFrame < castAnimFrames.length) {
// Fade out previous frame smoothly
if (currentCastFrame > 0) {
tween(castAnimFrames[currentCastFrame - 1], {
alpha: 0
}, {
duration: 100,
easing: tween.easeInOut
});
}
// Fade in current frame smoothly
var currentFrame = castAnimFrames[currentCastFrame];
tween(currentFrame, {
alpha: 1
}, {
duration: 100,
easing: tween.easeInOut
});
// Launch projectile when reaching spell8 frame (frame 7)
if (currentCastFrame === 7) {
var projectile = worldContainer.attachAsset('spell4', {
anchorX: 0.5,
anchorY: 0.5,
x: bloodmage.x + bloodmage.facingDirection * -80,
y: bloodmage.y - 350
});
projectile.velocity = bloodmage.facingDirection * -15;
projectile.scale.x = bloodmage.facingDirection;
// Add smooth fade-in for projectile
projectile.alpha = 0;
tween(projectile, {
alpha: 1
}, {
duration: 200,
easing: tween.easeOut
});
spellProjectiles.push(projectile);
}
currentCastFrame++;
// Slower frame rate for smoother animation
LK.setTimeout(animateCast, 120);
} else {
// Smooth fade out of last frame
tween(castAnimFrames[castAnimFrames.length - 1], {
alpha: 0
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
// Clean up cast animation
for (var i = 0; i < castAnimFrames.length; i++) {
castAnimFrames[i].destroy();
}
isCasting = false;
// Resume idle animation
if (!bloodmage.isMoving && bloodmage.grounded) {
bloodmage.startIdleAnimation();
}
}
});
}
}
animateCast();
}
function updateCamera() {
if (bloodmage) {
var targetX = -bloodmage.x + 1024;
cameraX += (targetX - cameraX) * 0.1;
worldContainer.x = cameraX;
}
}
function checkCollisions() {
if (!bloodmage) return;
bloodmage.grounded = false;
for (var i = 0; i < platforms.length; i++) {
var platform = platforms[i];
var platLeft = platform.x - platform.width * platform.scale.x / 2;
var platRight = platform.x + platform.width * platform.scale.x / 2;
var platTop = platform.y - platform.height / 2;
var platBottom = platform.y + platform.height / 2;
var mageLeft = bloodmage.x - 40;
var mageRight = bloodmage.x + 40;
var mageTop = bloodmage.y - 120;
var mageBottom = bloodmage.y;
if (mageRight > platLeft && mageLeft < platRight && mageBottom > platTop && mageTop < platBottom) {
if (bloodmage.velocityY >= 0 && mageBottom - bloodmage.velocityY <= platTop) {
bloodmage.y = platTop;
bloodmage.velocityY = 0;
bloodmage.grounded = true;
bloodmage.jumpCount = 0; // Reset jump count when landing
}
}
}
if (bloodmage.y > 2500) {
bloodmage.x = 200;
bloodmage.y = 1800;
bloodmage.velocityX = 0;
bloodmage.velocityY = 0;
}
// Remove automatic proximity battle UI - now using tap-to-interact
}
// Global variables for battle UI management
var battleHunk = null;
var battleMenuVisible = false;
var combatMenuUI = null;
var cursorUI = null;
function showBattleUI() {
if (battleMenuVisible || !currentHunk) return;
battleMenuVisible = true;
// Create combat menu system positioned between trackpad and buttons
combatMenuUI = game.attachAsset('combatmenu', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 2200,
scaleX: 4,
scaleY: 4
});
combatMenuUI.interactive = true;
cursorUI = game.attachAsset('cursor', {
anchorX: 0.5,
anchorY: 0.5,
x: 724,
y: 2200,
scaleX: 0.3,
scaleY: 0.3
});
window.currentSelectedOption = 0;
// Store global references for cleanup
window.currentCombatMenu = combatMenuUI;
window.currentCursor = cursorUI;
}
function hideBattleUI() {
if (!battleMenuVisible) return;
battleMenuVisible = false;
if (combatMenuUI) {
combatMenuUI.destroy();
combatMenuUI = null;
}
if (cursorUI) {
cursorUI.destroy();
cursorUI = null;
}
window.currentCombatMenu = null;
window.currentCursor = null;
}
function startBattle(hunk) {
// Don't lock player in battle mode, just set current hunk for proximity detection
currentHunk = hunk;
battleHunk = hunk;
}
function castSpell(damage) {
if (!currentHunk) return;
currentHunk.resistance = Math.max(0, currentHunk.resistance - damage);
LK.getSound('spell').play();
// Flash the hunk to show damage
LK.effects.flashObject(currentHunk, 0xFF00FF, 500);
// Create spell effect
var spellEffect = worldContainer.attachAsset('spell2', {
anchorX: 0.5,
anchorY: 0.5,
x: currentHunk.x,
y: currentHunk.y - 50,
alpha: 0.8
});
// Animate the spell effect
tween(spellEffect, {
alpha: 0,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
spellEffect.destroy();
}
});
}
function attemptCapture() {
if (!currentHunk) return;
if (currentHunk.resistance < 30) {
LK.getSound('capture').play();
currentHunk.captured = true;
currentHunk.visible = false;
// Stop idle animation for animated hunk
if (currentHunk.hunkType === 0 || currentHunk.hunkType === 1 || currentHunk.hunkType === 2 || currentHunk.hunkType === 3) {
currentHunk.stopIdleAnimation();
}
capturedHunks.push(currentHunk.hunkType);
storage.capturedHunks = capturedHunks;
if (!brostiary[currentHunk.hunkType]) {
brostiary[currentHunk.hunkType] = true;
storage.brostiary = brostiary;
}
scoreText.setText('Hunks: ' + capturedHunks.length);
// Hide battle UI after capture
hideBattleUI();
currentHunk = null;
// Don't teleport player - they stay at current position
if (capturedHunks.length >= 10) {
LK.showYouWin();
}
} else {
// Flash screen red for failed capture
LK.effects.flashScreen(0xFF0000, 500);
}
}
game.down = function (x, y, obj) {
// Handle combat menu interaction when battle UI is visible
if (battleMenuVisible && window.currentCombatMenu) {
// Check if clicking within combat menu bounds (centered at 1024, 2200 with scale 4)
var menuLeft = 1024 - 400; // Full width of scaled menu (200 * 4 scale)
var menuRight = 1024 + 400;
var menuTop = 2200 - 360; // Full height of scaled menu (180 * 4 scale)
var menuBottom = 2200 + 360;
if (x >= menuLeft && x <= menuRight && y >= menuTop && y <= menuBottom) {
// Determine which option based on x position within menu
var relativeX = (x - menuLeft) / (menuRight - menuLeft);
var newOption = Math.floor(relativeX * 4);
newOption = Math.max(0, Math.min(3, newOption));
// Update cursor position with correct positions for 4 options
var positions = [{
x: 724,
y: 2200
}, {
x: 874,
y: 2200
}, {
x: 1174,
y: 2200
}, {
x: 1324,
y: 2200
}];
if (newOption === window.currentSelectedOption) {
// Same option clicked - select it
selectCurrentOption();
} else {
// Different option - move cursor there
window.currentSelectedOption = newOption;
if (window.currentCursor && positions[window.currentSelectedOption]) {
tween(window.currentCursor, positions[window.currentSelectedOption], {
duration: 200,
easing: tween.easeOut
});
}
}
return;
}
return;
}
if (bropageShowing || shopShowing) return;
// Check if tapping directly on door or sign area in world coordinates
var worldPos = worldContainer.toLocal({
x: x,
y: y
});
if (doorAsset) {
var doorDistance = Math.sqrt(Math.pow(worldPos.x - doorAsset.x, 2) + Math.pow(worldPos.y - doorAsset.y, 2));
if (doorDistance < 200) {
enterShop();
return;
}
}
if (hideSignAsset) {
var signDistance = Math.sqrt(Math.pow(worldPos.x - hideSignAsset.x, 2) + Math.pow(worldPos.y - hideSignAsset.y, 2));
if (signDistance < 150) {
enterShop();
return;
}
}
// Check if tapping on a hunk to start battle
for (var i = 0; i < hunks.length; i++) {
var hunk = hunks[i];
if (!hunk.captured) {
var hunkDistance = Math.sqrt(Math.pow(worldPos.x - hunk.x, 2) + Math.pow(worldPos.y - hunk.y, 2));
if (hunkDistance < 150) {
currentHunk = hunk;
showBattleUI();
return;
}
}
}
// Check if near door for action button press
var nearDoor = false;
if (bloodmage && doorAsset) {
var distance = Math.abs(bloodmage.x - doorAsset.x) + Math.abs(bloodmage.y - doorAsset.y);
if (distance < 200) {
nearDoor = true;
}
}
// Convert game coordinates to local GUI coordinates for trackpad
var localPos = LK.gui.bottomLeft.toLocal({
x: x,
y: y
});
var dx = localPos.x - 200;
var dy = localPos.y - -200;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < 150) {
// Increased hit area
trackpadPressed = true;
trackpadAngle = Math.atan2(dy, dx);
updateTrackpad(x, y);
return; // Exit early to prevent overlap
}
// Convert game coordinates to local GUI coordinates for jump button
localPos = LK.gui.bottomRight.toLocal({
x: x,
y: y
});
dx = localPos.x - -200;
dy = localPos.y - -200;
dist = Math.sqrt(dx * dx + dy * dy);
if (dist < 150 && bloodmage) {
var _animateButtonBlink2 = function animateButtonBlink() {
if (currentBlinkFrame < blinkFrames.length) {
// Get the current frame asset and apply it to the button
var frameAsset = LK.getAsset(blinkFrames[currentBlinkFrame], {
anchorX: 0.5,
anchorY: 0.5
});
// Replace button content temporarily
// Keep jump button visible - just layer blink on top
// Add blink frame to GUI
var blinkFrame = LK.gui.bottomRight.addChild(frameAsset);
blinkFrame.x = -200;
blinkFrame.y = -200;
// Animate the blink frame
tween(blinkFrame, {
alpha: 0.8
}, {
duration: 50,
onFinish: function onFinish() {
tween(blinkFrame, {
alpha: 0
}, {
duration: 50,
onFinish: function onFinish() {
blinkFrame.destroy();
currentBlinkFrame++;
if (currentBlinkFrame < blinkFrames.length) {
_animateButtonBlink2();
}
}
});
}
});
}
};
// Increased hit area
// Start button blink animation
var blinkFrames = ['buttonblink', 'buttonblink2', 'buttonblink3', 'buttonblink4'];
var currentBlinkFrame = 0;
_animateButtonBlink2();
var currentTime = Date.now();
var timeSinceLastJump = currentTime - bloodmage.lastJumpTime;
// Check for double tap timing
if (timeSinceLastJump < doubleTapThreshold && bloodmage.jumpCount === 1 && bloodmage.grounded) {
// Double tap detected - perform higher jump
bloodmage.velocityY = -bloodmage.jumpPower * 1.5;
bloodmage.grounded = false;
bloodmage.doubleJumpAvailable = true;
LK.getSound('jump').play();
bloodmage.jumpCount = 0; // Reset for next sequence
} else {
// Normal jump attempt
var jumpSuccess = bloodmage.jump();
if (jumpSuccess) {
bloodmage.lastJumpTime = currentTime;
bloodmage.jumpCount = bloodmage.grounded ? 1 : 0; // Track if this was first jump
}
}
}
// Check action button
localPos = LK.gui.bottomRight.toLocal({
x: x,
y: y
});
dx = localPos.x - -200;
dy = localPos.y - -450;
dist = Math.sqrt(dx * dx + dy * dy);
if (dist < 150 && bloodmage && !isCasting) {
// Double-check door proximity with improved calculation
var doorDistance = doorAsset ? Math.sqrt(Math.pow(bloodmage.x - doorAsset.x, 2) + Math.pow(bloodmage.y - doorAsset.y, 2)) : 999;
if (doorDistance < 300) {
enterShop();
return; // Exit early to prevent casting
} else {
castPlayerSpell();
}
}
// Check shop icon
localPos = LK.gui.topRight.toLocal({
x: x,
y: y
});
dx = localPos.x - -300;
dy = localPos.y - 150;
dist = Math.sqrt(dx * dx + dy * dy);
if (dist < 75) {
showShop();
}
};
game.move = function (x, y, obj) {
if (!trackpadPressed || battleMenuVisible || bropageShowing || shopShowing) return;
updateTrackpad(x, y);
};
game.up = function () {
trackpadPressed = false;
if (bloodmage) {
bloodmage.velocityX = 0;
}
trackpadThumb.x = 200;
trackpadThumb.y = -200;
};
function updateTrackpad(x, y) {
// x and y are already in local coordinates for GUI elements
var dx = x - 200;
var dy = y - -200;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 80) {
dx = dx / dist * 80;
dy = dy / dist * 80;
}
trackpadThumb.x = 200 + dx;
trackpadThumb.y = -200 + dy;
if (bloodmage && dist > 5) {
// Lower dead zone
// More responsive movement
bloodmage.velocityX = dx / 80 * bloodmage.speed * 1.5; // Increased responsiveness
}
}
game.update = function () {
if (!battleMenuVisible) {
checkCollisions();
updateCamera();
// Update action button text based on door proximity
if (bloodmage && actionText && doorAsset) {
var dx = Math.abs(bloodmage.x - doorAsset.x);
var dy = Math.abs(bloodmage.y - doorAsset.y);
var distance = Math.sqrt(dx * dx + dy * dy);
var nearDoor = distance < 300;
actionText.setText(nearDoor ? 'ENTER' : 'CAST');
}
// Check if we need to generate more level
if (bloodmage && bloodmage.x > lastGeneratedX - 2000) {
generateLevelChunk(lastGeneratedX);
cleanupOldElements();
}
}
// Animate clouds drifting
for (var i = 0; i < clouds.length; i++) {
var cloud = clouds[i];
cloud.x += cloud.driftSpeed;
// For procedurally generated clouds, wrap them based on current view
var rightEdge = -cameraX + 3072;
var leftEdge = -cameraX - 1024;
if (cloud.x > rightEdge) {
cloud.x = leftEdge;
}
}
// Update spell projectiles
for (var i = spellProjectiles.length - 1; i >= 0; i--) {
var projectile = spellProjectiles[i];
projectile.x += projectile.velocity;
// Check if projectile is off screen
var screenLeft = -cameraX - 500;
var screenRight = -cameraX + 2548;
if (projectile.x < screenLeft || projectile.x > screenRight) {
projectile.destroy();
spellProjectiles.splice(i, 1);
continue;
}
// Check collision with hunks
for (var j = 0; j < hunks.length; j++) {
var hunk = hunks[j];
if (!hunk.captured && projectile.intersects(hunk)) {
// Reduce hunk resistance
hunk.resistance = Math.max(0, hunk.resistance - 25);
// Create visual effect
var effect = worldContainer.attachAsset('spell2', {
anchorX: 0.5,
anchorY: 0.5,
x: hunk.x,
y: hunk.y - 50,
alpha: 1
});
// Animate effect
tween(effect, {
alpha: 0,
scaleX: 2,
scaleY: 2,
rotation: Math.PI * 2
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
effect.destroy();
}
});
// Flash the hunk
LK.effects.flashObject(hunk, 0xFF00FF, 300);
// Show resistance bar above hunk temporarily
var resistanceText = new Text2('RESISTANCE: ' + hunk.resistance + '/' + hunk.maxResistance, {
size: 60,
fill: hunk.resistance < 30 ? 0x00FF00 : 0xFF0000
});
resistanceText.anchor.set(0.5, 0.5);
resistanceText.x = hunk.x;
resistanceText.y = hunk.y - 150;
worldContainer.addChild(resistanceText);
// Auto-hide resistance text after 2 seconds
tween(resistanceText, {
alpha: 0
}, {
duration: 2000,
onFinish: function onFinish() {
resistanceText.destroy();
}
});
// Destroy projectile
projectile.destroy();
spellProjectiles.splice(i, 1);
break;
}
}
}
};
// Combat menu navigation functions removed - using direct touch interaction
function selectCurrentOption() {
if (!battleMenuVisible || !currentHunk) return;
var selectedOption = window.currentSelectedOption;
if (selectedOption === 0) {
// Enthrall (capture function) with enhanced animations
performCaptureAnimation();
} else if (selectedOption === 1) {
// Speak - show dialogue with player response
showDualDialogue();
} else if (selectedOption === 2) {
// Cast - perform casting animation
performBattleCast();
} else if (selectedOption === 3) {
// Leave - exit battle UI
hideBattleUI();
currentHunk = null;
}
}
function performCaptureAnimation() {
if (!currentHunk) return;
// Throw capture device animation
var captureDevice = worldContainer.attachAsset('capturedevice', {
anchorX: 0.5,
anchorY: 0.5,
x: bloodmage.x,
y: bloodmage.y - 100,
scaleX: 1.5,
scaleY: 1.5
});
// Animate device flying toward hunk
tween(captureDevice, {
x: currentHunk.x,
y: currentHunk.y - 50,
rotation: Math.PI * 2
}, {
duration: 600,
easing: tween.easeOut,
onFinish: function onFinish() {
// Create capture effect
var captureEffect = worldContainer.attachAsset('captureeffect', {
anchorX: 0.5,
anchorY: 0.5,
x: currentHunk.x,
y: currentHunk.y - 50,
scaleX: 0.1,
scaleY: 0.1
});
// Animate effect expanding
tween(captureEffect, {
scaleX: 3,
scaleY: 3,
alpha: 0.8
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
if (currentHunk.resistance < 30) {
// Success - shrink hunk into device
tween(currentHunk, {
scaleX: 0.1,
scaleY: 0.1,
x: captureDevice.x,
y: captureDevice.y
}, {
duration: 400,
easing: tween.easeIn,
onFinish: function onFinish() {
attemptCapture();
showXPMenu(true);
captureDevice.destroy();
captureEffect.destroy();
}
});
} else {
// Failed - break free animation
var breakEffect = worldContainer.attachAsset('effect', {
anchorX: 0.5,
anchorY: 0.5,
x: currentHunk.x,
y: currentHunk.y,
scaleX: 2,
scaleY: 2
});
LK.effects.flashScreen(0xFF0000, 500);
tween(breakEffect, {
alpha: 0,
scaleX: 4,
scaleY: 4
}, {
duration: 600,
onFinish: function onFinish() {
breakEffect.destroy();
captureDevice.destroy();
captureEffect.destroy();
}
});
}
}
});
}
});
}
function performBattleCast() {
if (!currentHunk) return;
// Cast spell animation with spell behind hunk
var spellBehind = worldContainer.attachAsset('spell', {
anchorX: 0.5,
anchorY: 0.5,
x: currentHunk.x,
y: currentHunk.y,
scaleX: 5,
scaleY: 5,
alpha: 0.8
});
worldContainer.setChildIndex(spellBehind, worldContainer.getChildIndex(currentHunk) - 1);
// Pulsing spell2 at bottom of hunk
var spellPulse = worldContainer.attachAsset('spell2', {
anchorX: 0.5,
anchorY: 0.5,
x: currentHunk.x,
y: currentHunk.y + 50,
scaleX: 0.5,
scaleY: 0.5
});
// Animate pulsing
function pulseSpell() {
tween(spellPulse, {
scaleX: 1.2,
scaleY: 1.2,
alpha: 1
}, {
duration: 300,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(spellPulse, {
scaleX: 0.5,
scaleY: 0.5,
alpha: 0.6
}, {
duration: 300,
easing: tween.easeInOut,
onFinish: pulseSpell
});
}
});
}
pulseSpell();
// Play cast animation on bloodmage
castPlayerSpell();
// Damage hunk
castSpell(25);
// Clean up after 2 seconds
LK.setTimeout(function () {
if (spellBehind) spellBehind.destroy();
if (spellPulse) spellPulse.destroy();
}, 2000);
}
function showDualDialogue() {
if (!currentHunk) return;
// Player dialogue
var playerDialogue = worldContainer.attachAsset('dialoguebox', {
anchorX: 0.5,
anchorY: 0.5,
x: bloodmage.x,
y: bloodmage.y - 200,
scaleX: 6,
scaleY: 4
});
var playerText = new Text2('SUBMIT TO MY WILL!', {
size: 28,
fill: 0xFF00FF,
fontWeight: 'bold',
wordWrap: true,
wordWrapWidth: 180
});
playerText.anchor.set(0.5, 0.5);
playerDialogue.addChild(playerText);
// Hunk dialogue
var hunkDialogue = worldContainer.attachAsset('dialoguebox', {
anchorX: 0.5,
anchorY: 0.5,
x: currentHunk.x,
y: currentHunk.y - 200,
scaleX: 8,
scaleY: 6
});
var hunkNames = ['FUNGI-GUY', 'DJINN-TONIC', 'MINO-THROBBER', 'IGUANA-THRUST'];
var hunkDialogues = ['NEVER! MY SPORES PROTECT ME!', 'YOUR MAGIC IS WEAK, MORTAL!', 'I BOW TO NO ONE!', 'YOU CANNOT TAME THIS BEAST!'];
var hunkNameText = new Text2(hunkNames[currentHunk.hunkType], {
size: 32,
fill: 0xFF1493,
fontWeight: 'bold'
});
hunkNameText.anchor.set(0.5, 0);
hunkNameText.y = -40;
hunkDialogue.addChild(hunkNameText);
var hunkText = new Text2(hunkDialogues[currentHunk.hunkType], {
size: 24,
fill: 0xFFFFFF,
fontWeight: 'bold',
wordWrap: true,
wordWrapWidth: 200
});
hunkText.anchor.set(0.5, 0.5);
hunkText.y = 20;
hunkDialogue.addChild(hunkText);
// Auto-hide both dialogues after 4 seconds
LK.setTimeout(function () {
if (playerDialogue) playerDialogue.destroy();
if (hunkDialogue) hunkDialogue.destroy();
}, 4000);
}
function showXPMenu(captureSuccess) {
// Create XP menu overlay
var xpMenuOverlay = game.addChild(new Container());
var xpBg = xpMenuOverlay.attachAsset('xpmenu', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1366,
scaleX: 8,
scaleY: 8,
alpha: 0
});
tween(xpBg, {
alpha: 0.95
}, {
duration: 500,
easing: tween.easeOut
});
// Calculate XP earned
var baseXP = 100;
var bonusXP = captureSuccess ? 50 : 0;
var totalXP = baseXP + bonusXP;
// XP text
var xpText = new Text2('EXPERIENCE GAINED: ' + totalXP, {
size: 80,
fill: 0x00FF00,
fontWeight: 'bold'
});
xpText.anchor.set(0.5, 0.5);
xpText.x = 1024;
xpText.y = 1200;
xpText.alpha = 0;
xpMenuOverlay.addChild(xpText);
tween(xpText, {
alpha: 1
}, {
duration: 600,
easing: tween.easeOut
});
if (captureSuccess) {
var successText = new Text2('HUNK CAPTURED!', {
size: 100,
fill: 0xFF00FF,
fontWeight: 'bold'
});
successText.anchor.set(0.5, 0.5);
successText.x = 1024;
successText.y = 1400;
successText.alpha = 0;
xpMenuOverlay.addChild(successText);
tween(successText, {
alpha: 1
}, {
duration: 800,
easing: tween.easeOut
});
}
// Continue button
var continueBtn = new Text2('CONTINUE', {
size: 60,
fill: 0xFFFFFF,
fontWeight: 'bold'
});
continueBtn.anchor.set(0.5, 0.5);
continueBtn.x = 1024;
continueBtn.y = 1600;
continueBtn.interactive = true;
continueBtn.alpha = 0;
continueBtn.down = function () {
xpMenuOverlay.destroy();
hideBattleUI();
};
xpMenuOverlay.addChild(continueBtn);
tween(continueBtn, {
alpha: 1
}, {
duration: 1000,
easing: tween.easeOut
});
}
function showHunkDialogue() {
var hunkNames = ['FUNGI-GUY', 'DJINN-TONIC', 'MINO-THROBBER', 'IGUANA-THRUST'];
var hunkDialogues = ['READY TO GET FUNGAL?', 'YOUR WISH IS MY COMMAND~', 'PREPARE TO BE DOMINATED!', 'TASTE MY SCALES~'];
// Create dialogue box only when speak is selected with proper sizing
var hunkDialogueBox = worldContainer.attachAsset('dialoguebox', {
anchorX: 0.5,
anchorY: 0.5,
x: currentHunk.x,
y: currentHunk.y - 200,
scaleX: 8,
scaleY: 6
});
var hunkNameText = new Text2(hunkNames[currentHunk.hunkType], {
size: 32,
fill: 0xFF1493,
fontWeight: 'bold'
});
hunkNameText.anchor.set(0.5, 0);
hunkNameText.y = -40;
hunkDialogueBox.addChild(hunkNameText);
var hunkText = new Text2(hunkDialogues[currentHunk.hunkType], {
size: 24,
fill: 0xFFFFFF,
fontWeight: 'bold',
wordWrap: true,
wordWrapWidth: 200
});
hunkText.anchor.set(0.5, 0.5);
hunkText.y = 20;
hunkDialogueBox.addChild(hunkText);
// Auto-hide dialogue after 3 seconds
LK.setTimeout(function () {
if (hunkDialogueBox) {
hunkDialogueBox.destroy();
}
}, 3000);
}
LK.playMusic('cyberpunk');
; ===================================================================
--- original.js
+++ change.js
@@ -1455,42 +1455,48 @@
brostiaryIcon.interactive = true;
brostiaryIcon.down = function () {
showBropage();
};
-// Shop state variables
+// Updated shop items with plush varieties and crystal hearts
var shopOverlay = null;
var shopShowing = false;
var currentShopPage = 0;
var shopItems = [{
- name: 'CRYSTAL ORB',
- asset: 'crystal',
+ name: 'crystalheart',
+ asset: 'crystalheart',
price: 50,
- description: 'MYSTICAL CRYSTAL WITH ARCANE PROPERTIES'
+ description: 'MYSTICAL CRYSTAL WITH ARCANE PROPERTIES',
+ useDisplay: true
}, {
- name: 'SPELL SCROLL',
- asset: 'spell',
+ name: 'plush',
+ asset: 'plush',
price: 30,
- description: 'ANCIENT MAGIC SCROLL OF POWER'
+ description: 'ADORABLE COMPANION FOR LONELY NIGHTS',
+ useShelf: true
}, {
- name: 'CAPTURE DEVICE',
- asset: 'capturedevice',
- price: 100,
- description: 'HIGH-TECH HUNK CONTAINMENT UNIT'
+ name: 'plush2',
+ asset: 'plush2',
+ price: 35,
+ description: 'CUTE CUDDLY FRIEND',
+ useShelf: true
}, {
- name: 'MAGIC EFFECT',
- asset: 'effect',
+ name: 'plush3',
+ asset: 'plush3',
+ price: 40,
+ description: 'PREMIUM PLUSH COMPANION',
+ useShelf: true
+}, {
+ name: 'crystalheart',
+ asset: 'crystalheart',
price: 75,
- description: 'BOTTLED MAGICAL ESSENCE'
+ description: 'RARE MYSTICAL HEART CRYSTAL',
+ useDisplay: true
}, {
- name: 'PLUSH TOY',
- asset: 'plush',
- price: 20,
- description: 'ADORABLE COMPANION FOR LONELY NIGHTS'
-}, {
- name: 'NEON SIGN',
- asset: 'neonsign2',
- price: 40,
- description: 'STYLISH CYBERPUNK DECORATION'
+ name: 'crystalheart',
+ asset: 'crystalheart',
+ price: 100,
+ description: 'LEGENDARY HEART OF POWER',
+ useDisplay: true
}];
function showBropage() {
if (bropageShowing || battleMenuVisible) return;
bropageShowing = true;
@@ -1996,19 +2002,30 @@
var item = shopItems[i];
var localIndex = i - startIndex;
var itemX = 600 + localIndex * 400;
var itemY = 1800;
- // Item background
- var itemBg = LK.getAsset('crystal', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: itemX,
- y: itemY,
- scaleX: 3,
- scaleY: 3,
- alpha: 0.3
- });
- shopOverlay.addChild(itemBg);
+ // Add appropriate display platform
+ if (item.useDisplay) {
+ // Display platform for crystal hearts
+ var displayPlatform = shopOverlay.attachAsset('displayplatform', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: itemX,
+ y: itemY + 20,
+ scaleX: 3,
+ scaleY: 3
+ });
+ } else if (item.useShelf) {
+ // Shelf for plush items
+ var platShelf = shopOverlay.attachAsset('platshelf', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: itemX,
+ y: itemY + 30,
+ scaleX: 4,
+ scaleY: 4
+ });
+ }
// Item asset
var itemAsset = shopOverlay.attachAsset(item.asset, {
anchorX: 0.5,
anchorY: 0.5,
@@ -2016,28 +2033,25 @@
y: itemY - 50,
scaleX: 2,
scaleY: 2
});
- // Item name
- var itemName = new Text2(item.name, {
- size: 64,
- fill: 0x00FFFF,
- fontWeight: 'bold'
- });
- itemName.anchor.set(0.5, 0.5);
- itemName.x = itemX;
- itemName.y = itemY + 80;
- // Add hot pink glow
- itemName.style = {
- fontSize: 64,
- fill: 0x00FFFF,
- fontWeight: 'bold',
- dropShadow: true,
- dropShadowColor: 0xFF1493,
- dropShadowBlur: 15,
- dropShadowDistance: 0
- };
- shopOverlay.addChild(itemName);
+ // Create item name using alphabet assets
+ var nameLetters = item.name.toLowerCase();
+ var letterSpacing = 25;
+ var startX = itemX - nameLetters.length * letterSpacing / 2;
+ for (var j = 0; j < nameLetters.length; j++) {
+ var letter = nameLetters[j];
+ if (letter !== ' ') {
+ var letterAsset = shopOverlay.attachAsset(letter, {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: startX + j * letterSpacing,
+ y: itemY + 80,
+ scaleX: 0.8,
+ scaleY: 0.8
+ });
+ }
+ }
// Item price
var itemPrice = new Text2('PRICE: ' + item.price, {
size: 56,
fill: 0xFFFF00,
@@ -2297,30 +2311,9 @@
bloodmage.y = 1800;
bloodmage.velocityX = 0;
bloodmage.velocityY = 0;
}
- // Check proximity to hunks for battle UI
- var nearHunk = null;
- for (var i = 0; i < hunks.length; i++) {
- var hunk = hunks[i];
- if (!hunk.captured) {
- var dx = Math.abs(bloodmage.x - hunk.x);
- var dy = Math.abs(bloodmage.y - hunk.y);
- var distance = Math.sqrt(dx * dx + dy * dy);
- if (distance < 200) {
- nearHunk = hunk;
- break;
- }
- }
- }
- // Show/hide battle UI based on proximity
- if (nearHunk && !battleMenuVisible) {
- currentHunk = nearHunk;
- showBattleUI();
- } else if (!nearHunk && battleMenuVisible) {
- hideBattleUI();
- currentHunk = null;
- }
+ // Remove automatic proximity battle UI - now using tap-to-interact
}
// Global variables for battle UI management
var battleHunk = null;
var battleMenuVisible = false;
@@ -2490,8 +2483,20 @@
enterShop();
return;
}
}
+ // Check if tapping on a hunk to start battle
+ for (var i = 0; i < hunks.length; i++) {
+ var hunk = hunks[i];
+ if (!hunk.captured) {
+ var hunkDistance = Math.sqrt(Math.pow(worldPos.x - hunk.x, 2) + Math.pow(worldPos.y - hunk.y, 2));
+ if (hunkDistance < 150) {
+ currentHunk = hunk;
+ showBattleUI();
+ return;
+ }
+ }
+ }
// Check if near door for action button press
var nearDoor = false;
if (bloodmage && doorAsset) {
var distance = Math.abs(bloodmage.x - doorAsset.x) + Math.abs(bloodmage.y - doorAsset.y);
@@ -2741,22 +2746,296 @@
function selectCurrentOption() {
if (!battleMenuVisible || !currentHunk) return;
var selectedOption = window.currentSelectedOption;
if (selectedOption === 0) {
- // Enthrall (capture function)
- attemptCapture();
+ // Enthrall (capture function) with enhanced animations
+ performCaptureAnimation();
} else if (selectedOption === 1) {
- // Speak - show dialogue
- showHunkDialogue();
+ // Speak - show dialogue with player response
+ showDualDialogue();
} else if (selectedOption === 2) {
- // Party - show captured hunks list (placeholder for now)
- LK.effects.flashScreen(0x00FFFF, 300);
+ // Cast - perform casting animation
+ performBattleCast();
} else if (selectedOption === 3) {
// Leave - exit battle UI
hideBattleUI();
currentHunk = null;
}
}
+function performCaptureAnimation() {
+ if (!currentHunk) return;
+ // Throw capture device animation
+ var captureDevice = worldContainer.attachAsset('capturedevice', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: bloodmage.x,
+ y: bloodmage.y - 100,
+ scaleX: 1.5,
+ scaleY: 1.5
+ });
+ // Animate device flying toward hunk
+ tween(captureDevice, {
+ x: currentHunk.x,
+ y: currentHunk.y - 50,
+ rotation: Math.PI * 2
+ }, {
+ duration: 600,
+ easing: tween.easeOut,
+ onFinish: function onFinish() {
+ // Create capture effect
+ var captureEffect = worldContainer.attachAsset('captureeffect', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: currentHunk.x,
+ y: currentHunk.y - 50,
+ scaleX: 0.1,
+ scaleY: 0.1
+ });
+ // Animate effect expanding
+ tween(captureEffect, {
+ scaleX: 3,
+ scaleY: 3,
+ alpha: 0.8
+ }, {
+ duration: 800,
+ easing: tween.easeOut,
+ onFinish: function onFinish() {
+ if (currentHunk.resistance < 30) {
+ // Success - shrink hunk into device
+ tween(currentHunk, {
+ scaleX: 0.1,
+ scaleY: 0.1,
+ x: captureDevice.x,
+ y: captureDevice.y
+ }, {
+ duration: 400,
+ easing: tween.easeIn,
+ onFinish: function onFinish() {
+ attemptCapture();
+ showXPMenu(true);
+ captureDevice.destroy();
+ captureEffect.destroy();
+ }
+ });
+ } else {
+ // Failed - break free animation
+ var breakEffect = worldContainer.attachAsset('effect', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: currentHunk.x,
+ y: currentHunk.y,
+ scaleX: 2,
+ scaleY: 2
+ });
+ LK.effects.flashScreen(0xFF0000, 500);
+ tween(breakEffect, {
+ alpha: 0,
+ scaleX: 4,
+ scaleY: 4
+ }, {
+ duration: 600,
+ onFinish: function onFinish() {
+ breakEffect.destroy();
+ captureDevice.destroy();
+ captureEffect.destroy();
+ }
+ });
+ }
+ }
+ });
+ }
+ });
+}
+function performBattleCast() {
+ if (!currentHunk) return;
+ // Cast spell animation with spell behind hunk
+ var spellBehind = worldContainer.attachAsset('spell', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: currentHunk.x,
+ y: currentHunk.y,
+ scaleX: 5,
+ scaleY: 5,
+ alpha: 0.8
+ });
+ worldContainer.setChildIndex(spellBehind, worldContainer.getChildIndex(currentHunk) - 1);
+ // Pulsing spell2 at bottom of hunk
+ var spellPulse = worldContainer.attachAsset('spell2', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: currentHunk.x,
+ y: currentHunk.y + 50,
+ scaleX: 0.5,
+ scaleY: 0.5
+ });
+ // Animate pulsing
+ function pulseSpell() {
+ tween(spellPulse, {
+ scaleX: 1.2,
+ scaleY: 1.2,
+ alpha: 1
+ }, {
+ duration: 300,
+ easing: tween.easeInOut,
+ onFinish: function onFinish() {
+ tween(spellPulse, {
+ scaleX: 0.5,
+ scaleY: 0.5,
+ alpha: 0.6
+ }, {
+ duration: 300,
+ easing: tween.easeInOut,
+ onFinish: pulseSpell
+ });
+ }
+ });
+ }
+ pulseSpell();
+ // Play cast animation on bloodmage
+ castPlayerSpell();
+ // Damage hunk
+ castSpell(25);
+ // Clean up after 2 seconds
+ LK.setTimeout(function () {
+ if (spellBehind) spellBehind.destroy();
+ if (spellPulse) spellPulse.destroy();
+ }, 2000);
+}
+function showDualDialogue() {
+ if (!currentHunk) return;
+ // Player dialogue
+ var playerDialogue = worldContainer.attachAsset('dialoguebox', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: bloodmage.x,
+ y: bloodmage.y - 200,
+ scaleX: 6,
+ scaleY: 4
+ });
+ var playerText = new Text2('SUBMIT TO MY WILL!', {
+ size: 28,
+ fill: 0xFF00FF,
+ fontWeight: 'bold',
+ wordWrap: true,
+ wordWrapWidth: 180
+ });
+ playerText.anchor.set(0.5, 0.5);
+ playerDialogue.addChild(playerText);
+ // Hunk dialogue
+ var hunkDialogue = worldContainer.attachAsset('dialoguebox', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: currentHunk.x,
+ y: currentHunk.y - 200,
+ scaleX: 8,
+ scaleY: 6
+ });
+ var hunkNames = ['FUNGI-GUY', 'DJINN-TONIC', 'MINO-THROBBER', 'IGUANA-THRUST'];
+ var hunkDialogues = ['NEVER! MY SPORES PROTECT ME!', 'YOUR MAGIC IS WEAK, MORTAL!', 'I BOW TO NO ONE!', 'YOU CANNOT TAME THIS BEAST!'];
+ var hunkNameText = new Text2(hunkNames[currentHunk.hunkType], {
+ size: 32,
+ fill: 0xFF1493,
+ fontWeight: 'bold'
+ });
+ hunkNameText.anchor.set(0.5, 0);
+ hunkNameText.y = -40;
+ hunkDialogue.addChild(hunkNameText);
+ var hunkText = new Text2(hunkDialogues[currentHunk.hunkType], {
+ size: 24,
+ fill: 0xFFFFFF,
+ fontWeight: 'bold',
+ wordWrap: true,
+ wordWrapWidth: 200
+ });
+ hunkText.anchor.set(0.5, 0.5);
+ hunkText.y = 20;
+ hunkDialogue.addChild(hunkText);
+ // Auto-hide both dialogues after 4 seconds
+ LK.setTimeout(function () {
+ if (playerDialogue) playerDialogue.destroy();
+ if (hunkDialogue) hunkDialogue.destroy();
+ }, 4000);
+}
+function showXPMenu(captureSuccess) {
+ // Create XP menu overlay
+ var xpMenuOverlay = game.addChild(new Container());
+ var xpBg = xpMenuOverlay.attachAsset('xpmenu', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: 1024,
+ y: 1366,
+ scaleX: 8,
+ scaleY: 8,
+ alpha: 0
+ });
+ tween(xpBg, {
+ alpha: 0.95
+ }, {
+ duration: 500,
+ easing: tween.easeOut
+ });
+ // Calculate XP earned
+ var baseXP = 100;
+ var bonusXP = captureSuccess ? 50 : 0;
+ var totalXP = baseXP + bonusXP;
+ // XP text
+ var xpText = new Text2('EXPERIENCE GAINED: ' + totalXP, {
+ size: 80,
+ fill: 0x00FF00,
+ fontWeight: 'bold'
+ });
+ xpText.anchor.set(0.5, 0.5);
+ xpText.x = 1024;
+ xpText.y = 1200;
+ xpText.alpha = 0;
+ xpMenuOverlay.addChild(xpText);
+ tween(xpText, {
+ alpha: 1
+ }, {
+ duration: 600,
+ easing: tween.easeOut
+ });
+ if (captureSuccess) {
+ var successText = new Text2('HUNK CAPTURED!', {
+ size: 100,
+ fill: 0xFF00FF,
+ fontWeight: 'bold'
+ });
+ successText.anchor.set(0.5, 0.5);
+ successText.x = 1024;
+ successText.y = 1400;
+ successText.alpha = 0;
+ xpMenuOverlay.addChild(successText);
+ tween(successText, {
+ alpha: 1
+ }, {
+ duration: 800,
+ easing: tween.easeOut
+ });
+ }
+ // Continue button
+ var continueBtn = new Text2('CONTINUE', {
+ size: 60,
+ fill: 0xFFFFFF,
+ fontWeight: 'bold'
+ });
+ continueBtn.anchor.set(0.5, 0.5);
+ continueBtn.x = 1024;
+ continueBtn.y = 1600;
+ continueBtn.interactive = true;
+ continueBtn.alpha = 0;
+ continueBtn.down = function () {
+ xpMenuOverlay.destroy();
+ hideBattleUI();
+ };
+ xpMenuOverlay.addChild(continueBtn);
+ tween(continueBtn, {
+ alpha: 1
+ }, {
+ duration: 1000,
+ easing: tween.easeOut
+ });
+}
function showHunkDialogue() {
var hunkNames = ['FUNGI-GUY', 'DJINN-TONIC', 'MINO-THROBBER', 'IGUANA-THRUST'];
var hunkDialogues = ['READY TO GET FUNGAL?', 'YOUR WISH IS MY COMMAND~', 'PREPARE TO BE DOMINATED!', 'TASTE MY SCALES~'];
// Create dialogue box only when speak is selected with proper sizing
Neon cyberpunk App icon BROSTIARY encyclopedia of black leather biker jacket longsleeves shirtless musxles pants boots hunk outline linework glowing 3d hologram flat
Neon cyberpunk magic projectile effect
Idle animation, sleek graceful man Cyberpunk manga, facing forward idle pose shiny black leather biker jacket longsleeves shirtless Skinny abs blonde pompadour guy, action shot wine red joggers combat boots, Background removed, "Full-body character, entirely in frame, no cropping of face, head, or feet" "Complete character visible, from head to toe, fully centered in the image" "Entire character, including face and boots, fully within the frame" Character fully contained within a square frame, no edges cut off fashion model pose
Idle animation, sleek graceful man Cyberpunk manga, facing forward idle pose shiny black leather biker jacket longsleeves shirtless Skinny abs blonde pompadour guy, action shot wine red joggers combat boots, Background removed, "Full-body character, entirely in frame, no cropping of face, head, or feet" "Complete character visible, from head to toe, fully centered in the image" "Entire character, including face and boots, fully within the frame" Character fully contained within a square frame, no edges cut off fashion model pose
Neon cyberpunk anime city skyline futuristic holograms
Swishy graceful man Cyberpunk manga, wand pointed straight ahead, arm extended, jump attack, side profile view attack animation, shiny black leather biker jacket longsleeves shirtless Skinny abs blonde pompadour guy, action shot wine red joggers combat boots, Background removed, "Full-body character, entirely in frame, no cropping of face, head, or feet" "Complete character visible, from head to toe, fully centered in the image" "Entire character, including face and boots, fully within the frame" Character fully contained within a square frame, no edges cut off fashion model running pose
Cyberpunk manga man blonde undercut pompadour shiny black leather biker jacket longsleeves shirtless thin abs pecs necklaces gemstone tipped wand side profile view, action shot wand pointed straight in front arm extended wand casting spell feet planted, standing upright fierce fashion pose animation blonde undercut pompadour, vampire fangs, wine red joggers, combat boots, Background removed, "Full-body character, entirely in frame, no cropping of face, head, or feet" "Complete character visible, from head to toe, fully centered in the image" "Entire character, including face and shoes, fully within the frame" Character fully contained within a square frame, no edges cut off,
Neon cyberpunk rectangular empty outline flat two crystals hologram 2 glowing Diamonds on each side symmetrical selection highlight overlay
cyberpunk neon anime metropolis skyline holograms billboards, occult-capitalism-consumerism imagery nighttime futuristic architecture glow
Neon cyberpunk magic spell effect 3d hologram
Neon cyberpunk 3d magical glowing crystal gemstone hologram orb sphere
Swishy graceful man Cyberpunk manga, idle animation, shiny black leather biker jacket longsleeves shirtless Skinny abs blonde pompadour guy, wine red joggers combat boots, Background removed, "Full-body character, entirely in frame, no cropping of face, head, or feet" "Complete character visible, from head to toe, fully centered in the image" "Entire character, including face and boots, fully within the frame" Character fully contained within a square frame, no edges cut off fashion model idle pose
Neon cyberpunk mobile game trackpad too down flat 3d 2d hologram futuristic magic occult chic
round directional arrows Neon cyberpunk mobile game trackpad too down flat 3d 2d hologram futuristic magic occult chic
Neon cyberpunk skyscraper occult capitalist 3d hologram billboards futuristic elaborate architecture multidimensional towering city spires glowing
Neon cyberpunk futuristic glowing side-view 2d platformer style platform flat top
Neon cyberpunk futuristic glowing side-view 2d platformer style platform flat top hologram projection hovering hover platform antigravity jet thrusters
Neon cyberpunk button icon magic spell effect 3d hologram
Neon cyberpunk bag inventory button icon magic glowing futuristic 3d hologram
Same pose Limb positions variations, Front arm in front of body, front leg extended behind, back leg in front, limbs positions swapped, Swishy graceful man Cyberpunk manga, side profile view walking animation, shiny black leather biker jacket longsleeves shirtless Skinny abs blonde pompadour guy, wine red joggers combat boots, Background removed, "Full-body character, entirely in frame, no cropping of face, head, or feet" "Complete character visible, from head to toe, fully centered in the image" "Entire character, including face and boots, fully within the frame" Character fully contained within a square frame, no edges cut off fashion model idle pose
man Cyberpunk manga, minotaur monster hunk, shiny black leather biker jacket longsleeves shirtless muscles, jockstrap combat boots, Background removed, "Full-body character, entirely in frame, no cropping of face, head, or feet" "Complete character visible, from horns to hooves, fully centered in the image" "Entire character, including face and boots, fully within the frame" Character fully contained within a square frame, no edges cut off fashion model idle pose
Neon cyberpunk mobile game button magic gemstone crystal sigil eyeball heart triangle topdown flat 3d 2d hologram futuristic glowing occult chic
idle animation hunky Minotaur man Cyberpunk manga, minotaur monster hunk, shiny black leather biker jacket longsleeves shirtless muscles, jockstrap combat boots, Background removed, "Full-body character, entirely in frame, no cropping of face, head, or feet" "Complete character visible, from horns to hooves, fully centered in the image" "Entire character, including face and boots, fully within the frame" Character fully contained within a square frame, no edges cut off fashion model idle pose
idle animation hunky Minotaur man Cyberpunk manga, minotaur monster hunk, shiny black leather biker jacket longsleeves shirtless muscles, jockstrap combat boots, Background removed, "Full-body character, entirely in frame, no cropping of face, head, or feet" "Complete character visible, from horns to hooves, fully centered in the image" "Entire character, including face and boots, fully within the frame" Character fully contained within a square frame, no edges cut off fashion model idle pose
idle animation hunky Minotaur man Cyberpunk manga, minotaur monster hunk, shiny black leather biker jacket longsleeves shirtless muscles, jockstrap combat boots, Background removed, "Full-body character, entirely in frame, no cropping of face, head, or feet" "Complete character visible, from horns to hooves, fully centered in the image" "Entire character, including face and boots, fully within the frame" Character fully contained within a square frame, no edges cut off fashion model idle pose
idle animation hunky Minotaur man Cyberpunk manga, minotaur monster hunk, shiny black leather biker jacket longsleeves shirtless muscles, jockstrap combat boots, Background removed, "Full-body character, entirely in frame, no cropping of face, head, or feet" "Complete character visible, from horns to hooves, fully centered in the image" "Entire character, including face and boots, fully within the frame" Character fully contained within a square frame, no edges cut off fashion model idle pose
Swishy graceful man Cyberpunk manga, wand pointed straight ahead, arm extended, side profile view attack animation, shiny black leather biker jacket longsleeves shirtless Skinny abs blonde pompadour guy, action shot wine red joggers combat boots, Background removed, "Full-body character, entirely in frame, no cropping of face, head, or feet" "Complete character visible, from head to toe, fully centered in the image" "Entire character, including face and boots, fully within the frame" Character fully contained within a square frame, no edges cut off fashion model walking pose Style of vogue magazine
Black leather combat boots, wine red joggers, Swishy graceful man Cyberpunk manga, arm extended, side profile view walking animation, shiny black leather biker jacket longsleeves shirtless Skinny abs blonde pompadour guy, action shot wine red joggers combat boots, Background removed, "Full-body character, entirely in frame, no cropping of face, head, or feet" "Complete character visible, from head to toe, fully centered in the image" "Entire character, including face and boots, fully within the frame" Character fully contained within a square frame, no edges cut off fashion model walking pose Style of vogue magazine
Neon cyberpunk mobile game menu overlay boxes for CAST, SPEAK, CALL, ENTHRALL, LEAVE magic gemstone crystal sigil eyeball heart triangle topdown flat 3d 2d hologram futuristic glowing occult chic HOLOGRAM menu
Neon cyberpunk door shop entryway storefront entrance doorway
Neon cyberpunk blank empty videogame meter hologram glowing
Magical spell effect 3d cyberpunk hologram sacred geometry diagram tree of life
Neon cyberpunk experience menu form blank boxes labeled space for current level, experience gained, flat 2d 3d hologram glowing futuristic occult sigil heart eye triangle circle magick
Swishy graceful man Cyberpunk manga, side profile view, flying flight levitation action shot shiny black leather biker jacket longsleeves shirtless Skinny abs blonde pompadour guy, dynamic motion lifting off ground wine red joggers combat boots, tilting forward legs relaxed toes pointed arms relaxed at sides, Background removed, "Full-body character, entirely in frame, no cropping of face, head, or feet" "Complete character visible, from head to toe, fully centered in the image" "Entire character, including face and boots, fully within the frame" Character fully contained within a square frame, no edges cut off fashion model pose style of Vogue magazine
Swishy graceful man Cyberpunk manga, side profile view, flying flight levitation magic spell action shot shiny black leather biker jacket longsleeves shirtless Skinny abs blonde pompadour guy, dynamic motion lifting off ground wine red joggers combat boots, gemstone tipped magic wand heart triangle eye sigil hologram 3d neon, tilting forward legs relaxed toes pointed arms relaxed at sides, Background removed, "Full-body character, entirely in frame, no cropping of face, head, or feet" "Complete character visible, from head to toe, fully centered in the image" "Entire character, including face and boots, fully within the frame" Character fully contained within a square frame, no edges cut off fashion model pose style of Vogue magazine
3d hologram neon cyberpunk starlight magick galaxy overlay projection asteroid starfield Platforming magical dimension pathway level obstacle layout videogame
3d hologram neon cyberpunk starlight magick galaxy overlay projection asteroid starfield Platforming magical dimension pathway level obstacle layout videogame
neon galaxy projection 3d simulation glowing swirling nebulas supernova solar system outer space purple cyan stars black holes esoteric magick sigils sparkle glowing cyberpunk starlight magick galaxy overlay projection asteroid starfield swirling background magical dimension pathway level obstacle layout videogame
3d hologram neon cyberpunk starlight magick galaxy overlay projection asteroid starfield Platforming magical dimension pathway level obstacle layout videogame Map space layout magical mystical cosmic colorful glowing scene blackhole supernova nebula galaxies universe
Neon cyberpunk manga Magical underwater crystal cavern background image deep sea cave majestic cavern background scene landscape ocean floor seaweed
Magical underwater crystal cavern background image deep sea cave anime majestic
cyberpunk neon anime metropolis skyline holograms billboards, occult-capitalism-consumerism imagery nighttime futuristic architecture glow
16:9 banner, Neon cyberpunk horror landscape scene futuristic spires skyscrapers towers skyline hologram sigils lovecraftian bladerunner tower defense neon purple blue pink occult sigils projections 3d
Neon cyberpunk blank rectangular hologram empty overlay
3d hologram neon cyberpunk starlight magick galaxy overlay projection asteroid starfield Platforming magical dimension pathway level l layout videogame Map outerspace magical mystical cosmic colorful glowing scene blackholes supernovas nebulas galaxies universe background scene
cyberpunk neon anime metropolis skyline corporate holograms billboards, occult-capitalism-consumerism imagery nighttime futuristic architecture glow
3d hologram neon cyberpunk starlight magick galaxy overlay projection asteroid starfield magical dimension videogame Map outerspace magical mystical cosmic colorful glowing scene blackholes supernovas nebulas galaxies universe background scene
3d hologram neon cyberpunk starlight magick galaxy overlay projection asteroid starfield magical dimension videogame Map outerspace magical mystical cosmic colorful glowing scene blackholes supernovas nebulas galaxies universe background scene
neon cyberpunk manga seaside biome ocean beach holograms projections cyber deep sea background scene large hd overworld futuristic side platformer bg sea floor coastal
Swishy graceful man Cyberpunk manga, camera-facing arm bent In fro t of body, side profile view walking animation, shiny black leather biker jacket longsleeves shirtless Skinny abs blonde undercut pompadour guy, action shot wine red joggers combat boots, Background removed, "Full-body character, entirely in frame, no cropping of face, head, or feet" "Complete character visible, from head to toe, fully centered in the image" "Entire character, including hair and boots, fully within the frame" Character fully contained within a square frame, no edges cut off fashion model walking pose Style of vogue magazine
Top down isometric anime cyberpunk forest neon map grid hologram projection
Top down isometric anime forest River mountains neon map grid hologram
Top down isometric anime region neon map grid hologram
Top down isometric Cyberpunk forest thick foliage woods, anime Akira-nausicaa inspired, background scene, large sci-fi horror bioluminescent glowing alien flora
Top down isometric Cyberpunk forest, anime Akira-nausicaa inspired, background scene, large sci-fi horror bioluminescent glowing alien flora
Top down isometric neon cyberpunk castle mansion interior dungeon background large
Top down isometric neon cyberpunk castle courtyard dungeon background large
Top down isometric neon cyberpunk castle dungeon background large
Top down isometric cyberpunk simulation hologram grid projection forest biome, wilderness dense foliage wild rainforest mountain river
Top down isometric cyberpunk simulation hologram grid projection forest
Top down isometric Cyberpunk forest background image large
Cyberpunk forest background image large
Neon cyberpunk manga subterranean underground tunnels crystal caverns glowing huge ancient technology ruins futurustic underworld holograms spirits projections magical dimension cave background image deep caverns majestic background scene landscape tech purgatory catacombs maze Backdrop
neon cyberpunk manga undersea landscape oceanic holograms 3d deepsea seafloor underwater background scene large hd side platformer bg
2D platformer outerspace cosmic cyberpunk neon side profile view hologram stars magick galaxies cosmic black holes milkway star system overlay projection asteroid starfield Platforming magical dimension pathway level obstacle layout videogame
UI of 2D videogame asset management tool app, empty slots for assets, sleek flat intuitive User Interface futuristic style of Apple product ui, blank template sans uploaded assets
cyberpunk neon manga city metropolis skyline holograms billboards advertisements signs, magic sigils glow in subliminal messages with corporate logos, encouraging consumption, imagery nighttime futuristic hologram 3D projections horror sci-fi
cyberpunk neon anime metropolis skyline corporate holograms billboards, occult-capitalism-consumerism imagery nighttime futuristic architecture glow
neon cyberpunk manga undersea landscape ocean computer simulation underwater seafloor underwater background hd 2 sidescrolling platformer videogame bg undersea landscape
Expand on both sides landscape orientation neon cyberpunk metropolis world sidescrolling platformer futuristic holograms skyline jewel-tones forest cosmos ocean subterranean glowing simulation projection fantasy sci-fi background