User prompt
I can no longer see player character when I was trying to prevent multiple of identical npcs from appearing onscreen simultaneously.
User prompt
I’m unable to see the opening cutscene. Also, make sure that platforms, stairs, and doors aren’t overlapping each other, that characters aren’t appearing onscreen visibly simultaneously (no clones, no visible character repetition)
User prompt
Use expositionbox for exposition and dialoguebox for speech and rooftop for background to add an opening cutscene, animated, based on the following script: [expositionbox fades in, followed by the text fading into expositionbox] In the heart of Nocturneon City, where dazzling holograms conceal grim realities, an ancient legend, long forgotten, awakes . Chase Æros, a Bloodmage with a Wand of Want, seeks to turn the tide against the corporate occult. His weapon? Charm. His army? The beasts of his Brostiary. Chase : Time to shake up this dystopian disaster. One hunk at a time! (Chase leaps from a rooftop, wand glowing, as neon sigils flare around him.) /when action occurs like in brackets or parentheses, don’t show that text, but rather animate the action being described
User prompt
Background assets should extend to the bottom of the screen—there’s currently a conspicuous strip of black empty space along the bottom edge of the game, where track pad and jump+spell buttons are. Background assets should be filling that space. Line the bottom row of platforms up with the bottom edge of building assets so there isn’t an obvious, unsightly seam. Deploy various cosmic and space themed assets to the north of the top edge of city background assets. Deploy various forest assets to the east, and ocean assets to the west. Platforms, stairs, doors should not overlap each other the way background assets, intended to have a collage effect do. They need to be neat and orderly. Platforms should extend in all 4 directions. Animate some platforms to move in a fixed line, back and forth ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Repeat the above process with nocturnecity and world assets, layering them to minimize borders and expand the backgrounds to both the left and right. for some reason bg4 appears to be loading immensely larger than all the other background assets, and should be rendered at a scale closer to other background assets, incorporated in the background to give the scene dimension and fill any empty space. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Implement maplarge as a bottom layer background asset, layering the other background assets onto maplarge in corresponding positions to their placement in maplarge
User prompt
Switch the current walk animation to prowl - prowl6 (using the same method of looping forward, reverse, forward). Implement neonsign3 and neonsign4 as background assets (on the same layer as other neon sign assets) with a blinking/color changing animation effect. Space platforms and stairs farther apart so they’re not overlapping ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
You over compensated with scaling the walk animation, player character now appears a foot and a half taller—keep walk same scale as idle animation, I was just asking a few frames having warped ratios. Make sure clouds don’t drift behind background assets ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Cloud assets shouldn’t drift behind background assets. Background assets should be arranged with visual coherence to fill blank empty/black spaces. Holograms should be layered in front of background images, behind clouds, and should blink and alternate between visual animation effects and change color. Player’s walk animation has warped assets and the movement speed is too slow. Stairs should have collision and be able to be walked up. Platforms shouldn’t overlap, and with stairs connecting them vertically. ↪💡 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(background2, 12);' Line Number: 2005
User prompt
Please fix the bug: 'The supplied index is out of bounds' in or related to this line: 'worldContainer.setChildIndex(nocturneCityBg, 11);' Line Number: 1993
User prompt
Please fix the bug: 'The supplied index is out of bounds' in or related to this line: 'worldContainer.setChildIndex(nocturneCityLayout, 10);' Line Number: 1980
User prompt
Set world as an anchoring background asset, encompassing the city with cosmic assets layering in sky above city. Layer swirling galaxies and environmental effects ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Please implement nocturnecitylayout and world as background images. Stairs should function like platforms with collision and being in foreground—player character currently walks in front of them instead of up them. Space platforms and stairs better so they’re not overlapping and jumbled. Bring holocosmos assets forward/beginning at the upper edge of city assets. Animate swirling galaxy effects. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Please implement Stairs and Stairs2 to connect between various platforms at different heights and more easily enable movement vertically. To the north of nocturne city assets, please implement an additional area called Holocosmos using the same type of animation as nocturne city, with the uploaded alphabet assets. Backgrounds: Galaxybg galaxybg2 galaxybg3 galaxybg4 Midground: galaxy starlight2 galaxy2 Environmental effects (swirling animation): galaxy platforms foreground: starlight starlight2 galaxy3 galaxy4 ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Use assetmanager to replace current asset management ui, making it functional based on the image and how it would function logically ↪💡 Consider importing and using the following plugins: @upit/tween.v1
Code edit (1 edits merged)
Please save this source code
User prompt
Implement assets manager and placement tools instead of biome world generation ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Re-trying the world and background generation system. Let’s instead Create a UI and system tools which pause gameplay/animation loops to open an assets menu. These are all the same assets from beneath the Assets tab, just viewable within the Play tab. Make the visual assets able to be selected, dragged and manually placed, flipped, copied, pasted, deleted, pinched to resize, and moved forward and backward in layering arrangements. If a set of assets appears as a multi-frame animation, such as NPCs or player character idle and jump animations, group them together, presented as an animated loop, forward and backward and forward, etc. keep the ui sleek, user friendly, and aesthetically pleasing. ↪💡 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(platVisual, 25 + p);' Line Number: 3006
User prompt
Please fix the bug: 'The supplied index is out of bounds' in or related to this line: 'worldContainer.setChildIndex(platVisual, 25 + p);' Line Number: 3003
User prompt
Kay so when loading in, why am I consistently seeing forest assets, cosmic assets, and underdeep assets? Make sure to follow this template, and layering, and then when loading the game for the first time, the only background assets we should see, being in nocturne city, in order: 4: bg bg2 bg3 bg4 nocturnecitylayout 3: building building2 Building2 building4 statue 2: building3 neonSign neonsign2 (the neon signs should fade in and out, as if they’re blinking) cloud1 - cloud3(drifting from left to right, make sure there’s plenty of them, and different sizes) 1: platform platform2 platform3 platform4 stairs stairs2 door - door3 (doors should always be paired with a platform in front of it) Make sure the stairs, doors, and npcs are all in the foreground, and load the player to be standing on platform2 with the idle animation looping. That’s not to say remove other biome elements, but use screenshot as reference for general layering and aesthetics guide. ↪💡 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(platVisual, 25 + p);' Line Number: 3001
User prompt
Kay so when loading in, why am I consistently seeing forest assets, cosmic assets, and underdeep assets? Make sure to follow this template, and layering, and then when loading the game for the first time, the only background assets we should see, being in nocturne city, in order: 4: bg bg2 bg3 bg4 nocturnecitylayout 3: building building2 Building2 building4 statue 2: building3 neonSign neonsign2 (the neon signs should fade in and out, as if they’re blinking) cloud1 - cloud3(drifting from left to right, make sure there’s plenty of them, and different sizes) 1: platform platform2 platform3 platform4 stairs stairs2 door - door3 (doors should always be paired with a platform in front of it) Make sure the stairs, doors, and npcs are all in the foreground, and load the player to be standing on platform2 with the idle animation looping. ↪💡 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(building, 10 + j);' Line Number: 5145
/****
* 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: 1,
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
}));
self.idleFrames.push(self.attachAsset('playeridle6', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0,
scaleX: baseIdleScale * 1.15,
scaleY: baseIdleScale
}));
// Add more idle animation frames for enhanced variety
self.idleFrames.push(self.attachAsset('playeridle9', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0,
scaleX: baseIdleScale * 1.08,
scaleY: baseIdleScale
}));
self.idleFrames.push(self.attachAsset('playeridle10', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0,
scaleX: baseIdleScale * 0.98,
scaleY: baseIdleScale
}));
self.idleFrames.push(self.attachAsset('playeridle11', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0,
scaleX: baseIdleScale * 1.13,
scaleY: baseIdleScale
}));
self.idleFrames.push(self.attachAsset('playeridle12', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0,
scaleX: baseIdleScale * 1.02,
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
}));
self.walkFrames.push(self.attachAsset('playerwalk9', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0,
scaleX: baseWalkScale * 1.06,
// Fix warped frame - normalized scale
scaleY: baseWalkScale
}));
self.walkFrames.push(self.attachAsset('playerwalk10', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0,
scaleX: baseWalkScale * 0.93,
// Adjust for narrower asset
scaleY: baseWalkScale
}));
self.walkFrames.push(self.attachAsset('playerwalk11', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0,
scaleX: baseWalkScale * 1.51,
// Fix skinny frame
scaleY: baseWalkScale
}));
self.walkFrames.push(self.attachAsset('playerwalk12', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0,
scaleX: baseWalkScale * 0.78,
// Adjust for wider asset
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
}));
// Create fly animation frames with consistent scaling
var baseFlyScale = 1.0;
self.flyFrames = [];
self.flyFrames.push(self.attachAsset('playerfly', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0,
scaleX: baseFlyScale * 0.99,
scaleY: baseFlyScale
}));
self.flyFrames.push(self.attachAsset('playerfly2', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0,
scaleX: baseFlyScale * 0.79,
scaleY: baseFlyScale
}));
self.flyFrames.push(self.attachAsset('playerfly3', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0,
scaleX: baseFlyScale * 1.06,
scaleY: baseFlyScale
}));
self.flyFrames.push(self.attachAsset('playerfly4', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0,
scaleX: baseFlyScale * 0.73,
scaleY: baseFlyScale
}));
self.flyFrames.push(self.attachAsset('playerfly5', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0,
scaleX: baseFlyScale * 0.76,
scaleY: baseFlyScale
}));
self.flyFrames.push(self.attachAsset('playerfly6', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0,
scaleX: baseFlyScale * 0.80,
scaleY: baseFlyScale
}));
// Create falling frames
self.fallFrames = [];
self.fallFrames.push(self.attachAsset('playerfly7', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0,
scaleX: baseFlyScale * 0.97,
scaleY: baseFlyScale
}));
self.fallFrames.push(self.attachAsset('playerfly8', {
anchorX: 0.5,
anchorY: 1.0,
alpha: 0,
scaleX: baseFlyScale * 0.79,
scaleY: baseFlyScale
}));
self.flyAnimationDirection = 1;
self.currentFlyFrame = 0;
self.isFlying = false;
self.idleAnimationDirection = 1; // 1 for forward, -1 for reverse
// REBUILT ANIMATION SYSTEM: Clear hierarchy with no conflicts
self.currentAnimationState = 'idle'; // Track current state: idle, walk, jump, fly, fall
self.clearAllAnimations = function () {
// Clear ALL timers first
LK.clearTimeout(self.idleAnimationTimer);
LK.clearTimeout(self.walkAnimationTimer);
LK.clearTimeout(self.jumpAnimationTimer);
LK.clearTimeout(self.flyAnimationTimer);
// Hide ALL 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;
}
for (var i = 0; i < self.jumpFrames.length; i++) {
self.jumpFrames[i].alpha = 0;
}
for (var i = 0; i < self.flyFrames.length; i++) {
self.flyFrames[i].alpha = 0;
}
for (var i = 0; i < self.fallFrames.length; i++) {
self.fallFrames[i].alpha = 0;
}
};
self.startIdleAnimation = function () {
// ONLY start if truly idle - no other states active
if (self.isMoving || self.isJumping || self.isFlying || self.currentAnimationState !== 'idle') return;
// Clear everything first
self.clearAllAnimations();
// Verify idle frames exist (playeridle to playeridle12)
if (!self.idleFrames || self.idleFrames.length < 6) return;
// Show current idle frame ONLY
self.idleFrames[self.currentIdleFrame].alpha = 1;
// Calculate next frame with ping-pong effect
var nextFrameIndex = self.currentIdleFrame + self.idleAnimationDirection;
// Reverse direction at boundaries for smooth ping-pong
if (nextFrameIndex >= self.idleFrames.length - 1) {
nextFrameIndex = self.idleFrames.length - 1;
self.idleAnimationDirection = -1;
} else if (nextFrameIndex <= 0) {
nextFrameIndex = 0;
self.idleAnimationDirection = 1;
}
var currentFrame = self.idleFrames[self.currentIdleFrame];
var nextFrame = self.idleFrames[nextFrameIndex];
// Smooth cross-fade transition
tween(currentFrame, {
alpha: 0
}, {
duration: 120,
easing: tween.easeInOut
});
tween(nextFrame, {
alpha: 1
}, {
duration: 120,
easing: tween.easeInOut
});
self.currentIdleFrame = nextFrameIndex;
// Continue ONLY if still in idle state
self.idleAnimationTimer = LK.setTimeout(function () {
if (self.currentAnimationState === 'idle' && !self.isMoving && !self.isJumping && !self.isFlying) {
self.startIdleAnimation();
}
}, 180);
};
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();
}
}, 60);
};
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;
}
// Use different frames based on jump type
var frameIndex = 0;
if (self.isFlying) {
// Flight mode uses playerjump3 (frame 2)
frameIndex = 2;
} else if (self.jumpCount === 1) {
// Double jump uses playerjump2 (frame 1)
frameIndex = 1;
} else {
// Regular jump uses playerjump (frame 0)
frameIndex = 0;
}
// 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.startFlyAnimation = 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;
}
for (var i = 0; i < self.jumpFrames.length; i++) {
self.jumpFrames[i].alpha = 0;
}
for (var i = 0; i < self.fallFrames.length; i++) {
self.fallFrames[i].alpha = 0;
}
// Apply direction to fly frames
for (var i = 0; i < self.flyFrames.length; i++) {
self.flyFrames[i].scale.x = Math.abs(self.flyFrames[i].scale.x) * self.facingDirection;
}
// Show current fly frame
for (var i = 0; i < self.flyFrames.length; i++) {
self.flyFrames[i].alpha = i === self.currentFlyFrame ? 1 : 0;
}
// Animate fly frames with ping-pong effect
var currentFrame = self.flyFrames[self.currentFlyFrame];
var nextFrameIndex = self.currentFlyFrame + self.flyAnimationDirection;
if (nextFrameIndex >= self.flyFrames.length - 1) {
nextFrameIndex = self.flyFrames.length - 1;
self.flyAnimationDirection = -1;
} else if (nextFrameIndex <= 0) {
nextFrameIndex = 0;
self.flyAnimationDirection = 1;
}
var nextFrame = self.flyFrames[nextFrameIndex];
tween(currentFrame, {
alpha: 0
}, {
duration: 80,
easing: tween.easeInOut
});
tween(nextFrame, {
alpha: 1
}, {
duration: 80,
easing: tween.easeInOut
});
self.currentFlyFrame = nextFrameIndex;
if (self.isFlying) {
self.flyAnimationTimer = LK.setTimeout(function () {
self.startFlyAnimation();
}, 120);
}
};
self.stopFlyAnimation = function () {
LK.clearTimeout(self.flyAnimationTimer);
for (var i = 0; i < self.flyFrames.length; i++) {
self.flyFrames[i].alpha = 0;
}
};
self.startFallAnimation = function () {
// Hide fly frames
for (var i = 0; i < self.flyFrames.length; i++) {
self.flyFrames[i].alpha = 0;
}
// Apply direction and show fall frames
for (var i = 0; i < self.fallFrames.length; i++) {
self.fallFrames[i].scale.x = Math.abs(self.fallFrames[i].scale.x) * self.facingDirection;
}
// Alternate between fall frames
var frameIndex = Math.floor(Date.now() / 150) % self.fallFrames.length;
for (var i = 0; i < self.fallFrames.length; i++) {
self.fallFrames[i].alpha = i === frameIndex ? 1 : 0;
}
};
self.stopFallAnimation = function () {
for (var i = 0; i < self.fallFrames.length; i++) {
self.fallFrames[i].alpha = 0;
}
};
self.update = function () {
// REBUILT PHYSICS SYSTEM: Clear separation of flight and ground physics
// FLIGHT MODE: Pure trackpad control with zero drift
if (self.isFlying && jumpButtonHeld) {
self.currentAnimationState = 'fly';
// ABSOLUTE ZERO DRIFT: Force all velocities to zero
self.velocityX = 0;
self.velocityY = 0;
self.grounded = false;
// ONLY move if trackpad is pressed with valid input
if (trackpadPressed && trackpadAngle !== undefined) {
var moveSpeed = self.speed * 0.8;
var moveX = Math.cos(trackpadAngle) * moveSpeed;
var moveY = Math.sin(trackpadAngle) * moveSpeed;
// Apply movement directly - NO velocity interference
self.x += moveX;
self.y += moveY;
// Update facing direction
if (moveX > 0) self.facingDirection = -1;else if (moveX < 0) self.facingDirection = 1;
}
// If no trackpad input: COMPLETE STILLNESS (no drift at all)
// Start/continue flight animation
if (self.currentAnimationState === 'fly') {
self.startFlyAnimation();
}
// Skip ALL other physics
return;
}
// GROUND/AIR PHYSICS: Traditional system
if (!self.grounded && !self.isFlying) {
// Falling
self.velocityY += self.gravity;
self.velocityX *= 0.98; // Air resistance
self.currentAnimationState = 'fall';
} else if (self.grounded) {
// Ground physics
self.velocityY += self.gravity;
}
// Apply velocities
self.x += self.velocityX;
self.y += self.velocityY;
// REBUILT ANIMATION STATE MACHINE
var newState = 'idle';
self.isMoving = Math.abs(self.velocityX) > 0.1;
self.isJumping = !self.grounded && !self.isFlying && Math.abs(self.velocityY) > 2;
if (self.isFlying) {
newState = 'fly';
} else if (self.isJumping) {
if (self.velocityY > 5) {
newState = 'fall';
} else {
newState = 'jump';
}
} else if (self.isMoving) {
newState = 'walk';
} else {
newState = 'idle';
}
// ONLY change animation if state actually changed
if (newState !== self.currentAnimationState) {
self.currentAnimationState = newState;
// Clear all animations before starting new one
self.clearAllAnimations();
// Start appropriate animation
if (newState === 'idle') {
self.startIdleAnimation();
} else if (newState === 'walk') {
self.startWalkingAnimation();
} else if (newState === 'jump') {
self.startJumpAnimation();
} else if (newState === 'fly') {
self.startFlyAnimation();
} else if (newState === 'fall') {
self.startFallAnimation();
}
}
};
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;
});
var Stairs = Container.expand(function () {
var self = Container.call(this);
// Randomly choose between stairs assets
var stairsAsset = Math.random() > 0.5 ? 'Stairs' : 'Stairs2';
var stairs = self.attachAsset(stairsAsset, {
anchorX: 0.5,
anchorY: 1.0
});
// Store stairs type for reference
self.stairsType = stairsAsset;
// Make stairs interactive for climbing
stairs.interactive = true;
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 isFlying = false;
var flyFrames = [];
var currentFlyFrame = 0;
var flyAnimationTimer = 0;
var flyAnimationDirection = 1;
var jumpHoldStartTime = 0;
var jumpButtonHeld = false;
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 more visible with better opacity
cloud.alpha = 0.6 + 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 - avoid door positions
if (i % 2 === 1 && Math.random() > 0.3) {
var hunk = new Hunk();
// Offset hunk position to avoid doors
hunk.x = platform.x + (Math.random() > 0.5 ? 150 : -150);
hunk.y = platform.y - 20;
hunks.push(hunk);
worldContainer.addChild(hunk);
}
}
// Add more platforms and hunks for extended level
var extendedPlatforms = [{
x: startX + 400,
y: 1500
}, {
x: startX + 900,
y: 1300
}, {
x: startX + 1400,
y: 1100
}, {
x: startX + 1900,
y: 1400
}];
for (var p = 0; p < extendedPlatforms.length; p++) {
var platform = new Platform();
platform.x = extendedPlatforms[p].x;
platform.y = extendedPlatforms[p].y;
platforms.push(platform);
worldContainer.addChild(platform);
// Add single hunk every other extended platform
if (p % 2 === 1) {
var hunk = new Hunk();
hunk.x = platform.x;
hunk.y = platform.y - 20;
hunks.push(hunk);
worldContainer.addChild(hunk);
}
}
// Generate Holocosmos area north of main level (higher Y coordinates)
if (startX > 8000) {
// Generate Holocosmos beyond main city area
// Add galaxy backgrounds for Holocosmos
var galaxyBgs = ['Galaxybg', 'galaxybg2', 'galaxybg3', 'galaxybg4'];
for (var layer = 0; layer < galaxyBgs.length; layer++) {
var galaxyBg = worldContainer.attachAsset(galaxyBgs[layer], {
anchorX: 0.5,
anchorY: 1.0,
x: startX + 1500,
y: 800 - layer * 200,
// Much higher than main level
scaleX: 2.5 - layer * 0.2,
scaleY: 2.5 - layer * 0.2
});
galaxyBg.alpha = 0.4 + layer * 0.15;
backgroundElements.push(galaxyBg);
worldContainer.setChildIndex(galaxyBg, layer);
}
// Add galaxy midground elements
var galaxyMidgrounds = ['galaxy', 'starlight2', 'galaxy2'];
for (var i = 0; i < galaxyMidgrounds.length; i++) {
var midground = worldContainer.attachAsset(galaxyMidgrounds[i], {
anchorX: 0.5,
anchorY: 0.5,
x: startX + 500 + i * 800,
y: 600 + Math.random() * 400,
scaleX: 1.5 + Math.random() * 1.0,
scaleY: 1.5 + Math.random() * 1.0
});
midground.alpha = 0.6 + Math.random() * 0.3;
backgroundElements.push(midground);
}
// Add swirling galaxy environmental effects
var _loop = function _loop() {
swirl = worldContainer.attachAsset('galaxy', {
anchorX: 0.5,
anchorY: 0.5,
x: startX + Math.random() * 2000,
y: 400 + Math.random() * 600,
scaleX: 0.8 + Math.random() * 1.2,
scaleY: 0.8 + Math.random() * 1.2
});
swirl.alpha = 0.3 + Math.random() * 0.4;
// Add swirling animation
function animateSwirl(swirlObj) {
tween(swirlObj, {
rotation: swirlObj.rotation + Math.PI * 2
}, {
duration: 3000 + Math.random() * 2000,
easing: tween.linear,
onFinish: function onFinish() {
animateSwirl(swirlObj);
}
});
}
animateSwirl(swirl);
backgroundElements.push(swirl);
},
swirl;
for (var i = 0; i < 5; i++) {
_loop();
}
// Generate cosmic platforms using starlight and galaxy assets
var cosmicPlatformAssets = ['starlight', 'starlight2', 'galaxy3', 'galaxy4'];
for (var i = 0; i < 6; i++) {
var platformAsset = cosmicPlatformAssets[Math.floor(Math.random() * cosmicPlatformAssets.length)];
var cosmicPlatform = worldContainer.attachAsset(platformAsset, {
anchorX: 0.5,
anchorY: 0.5,
x: startX + 300 + i * 400,
y: 600 - i % 3 * 150,
// Floating cosmic platforms
scaleX: 3.0,
scaleY: 3.0
});
// Add cosmic glow effect
cosmicPlatform.tint = [0x9966FF, 0x66FFFF, 0xFF66FF, 0xFFFF66][Math.floor(Math.random() * 4)];
cosmicPlatform.alpha = 0.8;
// Make platforms solid for collision
platforms.push({
x: cosmicPlatform.x,
y: cosmicPlatform.y,
width: cosmicPlatform.width * cosmicPlatform.scale.x,
height: cosmicPlatform.height * cosmicPlatform.scale.y,
scale: {
x: cosmicPlatform.scale.x,
y: cosmicPlatform.scale.y
},
intersects: function intersects(other) {
// Basic intersection check
return cosmicPlatform.intersects ? cosmicPlatform.intersects(other) : false;
}
});
worldContainer.addChild(cosmicPlatform);
}
// Add HOLOCOSMOS title using alphabet assets
var holocosmosLetters = [{
asset: 'h',
x: startX + 200
}, {
asset: 'o',
x: startX + 300
}, {
asset: 'l',
x: startX + 400
}, {
asset: 'o',
x: startX + 500
}, {
asset: 'c',
x: startX + 600
}, {
asset: 'o',
x: startX + 700
}, {
asset: 's',
x: startX + 800
}, {
asset: 'm',
x: startX + 900
}, {
asset: 'o',
x: startX + 1000
}, {
asset: 's',
x: startX + 1100
}];
for (var i = 0; i < holocosmosLetters.length; i++) {
var letter = worldContainer.attachAsset(holocosmosLetters[i].asset, {
anchorX: 0.5,
anchorY: 0.5,
x: holocosmosLetters[i].x,
y: 300,
scaleX: 2.5,
scaleY: 2.5
});
letter.tint = 0x9966FF;
letter.alpha = 0.9;
// Add floating animation to letters
(function (letterObj, index) {
function floatLetter() {
tween(letterObj, {
y: 250 + Math.sin(Date.now() * 0.001 + index) * 30
}, {
duration: 2000 + Math.random() * 1000,
easing: tween.easeInOut,
onFinish: floatLetter
});
}
floatLetter();
})(letter, i);
backgroundElements.push(letter);
}
}
// Update last generated position
lastGeneratedX = startX + 2500;
}
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 nocturnecity as the main side background layer to prevent player going behind elements
var nocturneCityBg = worldContainer.attachAsset('nocturnecity', {
anchorX: 0.5,
anchorY: 1.0,
x: 2500,
y: 2732,
scaleX: 2.5,
scaleY: 2.5
});
// Ensure nocturnecity stays at the very back
worldContainer.setChildIndex(nocturneCityBg, 0);
// 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
});
background2.alpha = 0.7;
// 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
});
background.alpha = 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 more visible with better opacity
cloud.alpha = 0.8 + Math.random() * 0.2;
// 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 < 15; i++) {
var building = new Building();
building.x = 100 + i * 400;
building.y = 2000; // Position at ground level so buildings meet platforms
building.scale.x = 0.6 + Math.random() * 0.8; // More varied building sizes
building.scale.y = 0.6 + Math.random() * 0.8;
buildings.push(building);
worldContainer.addChild(building);
}
// Add additional statues for better edge concealment
for (var s = 0; s < 8; s++) {
var statue = worldContainer.attachAsset('statue', {
anchorX: 0.5,
anchorY: 1.0,
x: 500 + s * 800,
y: 2000,
scaleX: 0.7 + Math.random() * 0.6,
scaleY: 0.7 + Math.random() * 0.6
});
statue.tint = 0x555555 + Math.floor(Math.random() * 0x333333);
backgroundElements.push(statue);
// Ensure statues stay behind platforms
var statueIndex = worldContainer.getChildIndex(statue);
worldContainer.setChildIndex(statue, Math.max(0, statueIndex - 5));
}
// Add additional neon signs for better visual coverage
for (var n = 0; n < 15; n++) {
var neonAsset = Math.random() > 0.5 ? 'neonSign' : 'neonsign2';
var neonSign = worldContainer.attachAsset(neonAsset, {
anchorX: 0.5,
anchorY: 0.5,
x: 200 + n * 450,
y: 1300 + Math.random() * 600,
scaleX: 0.6 + Math.random() * 0.8,
scaleY: 0.6 + Math.random() * 0.8
});
neonSign.alpha = 0.5 + Math.random() * 0.4;
neonSign.tint = [0xFF00FF, 0x00FFFF, 0xFFFF00, 0xFF0088, 0x88FF00][Math.floor(Math.random() * 5)];
backgroundElements.push(neonSign);
}
// Add more vertical decorative elements to fill gaps
for (var v = 0; v < 12; v++) {
var decorAssets = ['crystal', 'artefact', 'skilltree'];
var decorAsset = decorAssets[Math.floor(Math.random() * decorAssets.length)];
var decoration = worldContainer.attachAsset(decorAsset, {
anchorX: 0.5,
anchorY: 0.5,
x: 400 + v * 500,
y: 1000 + Math.random() * 800,
scaleX: 1.5 + Math.random() * 1.0,
scaleY: 1.5 + Math.random() * 1.0
});
decoration.alpha = 0.4 + Math.random() * 0.3;
decoration.tint = 0x666666 + Math.floor(Math.random() * 0x999999);
backgroundElements.push(decoration);
var decorIndex = worldContainer.getChildIndex(decoration);
worldContainer.setChildIndex(decoration, Math.max(0, decorIndex - 8));
}
var ground = new Platform();
ground.x = 1024;
ground.y = 2000;
ground.scale.x = 10;
platforms.push(ground);
worldContainer.addChild(ground);
// Create repeating bottom platform foundation
for (var b = 0; b < 15; b++) {
var bottomPlatform = new Platform();
bottomPlatform.x = 300 + b * 400;
bottomPlatform.y = 2000; // Ground level
bottomPlatform.scale.x = 1.2;
bottomPlatform.scale.y = 0.8;
platforms.push(bottomPlatform);
worldContainer.addChild(bottomPlatform);
}
// Create platform layout based on nocturnecitylayout guide
var platformPositions = [{
x: 400,
y: 1800
},
// Starting platform
{
x: 800,
y: 1600
},
// Lower left area
{
x: 1200,
y: 1500
},
// Lower mid
{
x: 1600,
y: 1600
},
// Shop door platform
{
x: 2000,
y: 1400
},
// Mid level ascending
{
x: 2400,
y: 1200
},
// Mid upper
{
x: 2800,
y: 1000
},
// Upper mid
{
x: 3200,
y: 1100
},
// Plateau area
{
x: 3600,
y: 1300
},
// Right mid
{
x: 4000,
y: 1500
},
// Right lower
{
x: 4400,
y: 1200
},
// Far right upper
{
x: 4800,
y: 1000
},
// Far right peak
{
x: 5200,
y: 1300
},
// Extended plateau
{
x: 5600,
y: 1400
},
// Final ascent
{
x: 6000,
y: 1100
} // End platform
];
// Door positions based on layout guide
var doorPositions = [{
platformIndex: 2,
isShop: true
},
// Bottom left shop door
{
platformIndex: 5,
isShop: false
},
// Mid level door
{
platformIndex: 8,
isShop: false
} // Upper right door
];
for (var i = 0; i < platformPositions.length; i++) {
var platform = new Platform();
platform.x = platformPositions[i].x;
platform.y = platformPositions[i].y;
platforms.push(platform);
worldContainer.addChild(platform);
// Ensure platform appears in foreground
var platformIndex = worldContainer.getChildIndex(platform);
worldContainer.setChildIndex(platform, worldContainer.children.length - 1);
// Check if this platform should have a door
var doorInfo = doorPositions.find(function (d) {
return d.platformIndex === i;
});
if (doorInfo) {
// Add platform beneath door for proper standing surface
var doorPlatform = new Platform();
doorPlatform.x = platform.x;
doorPlatform.y = platform.y + 50; // Slightly below main platform
doorPlatform.scale.x = 1.2;
platforms.push(doorPlatform);
worldContainer.addChild(doorPlatform);
// Ensure door platform is in foreground
var doorPlatformIndex = worldContainer.getChildIndex(doorPlatform);
worldContainer.setChildIndex(doorPlatform, worldContainer.children.length - 1);
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;
door.isShop = doorInfo.isShop;
// Ensure door appears in front of platforms
var doorIndex = worldContainer.getChildIndex(door);
worldContainer.setChildIndex(door, worldContainer.children.length - 1);
if (doorInfo.isShop) {
doorAsset = door; // Store shop door reference
// Add hidesign floating over shop door
var hideSign = worldContainer.attachAsset('hidesign', {
anchorX: 0.5,
anchorY: 1.0,
x: platform.x,
y: platform.y - 600,
scaleX: 4,
scaleY: 4
});
hideSign.interactive = true;
hideSign.down = function (x, y, obj) {
enterShop();
};
// 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();
} else {
// Non-shop doors get random interior
door.interiorAsset = 'interior' + (Math.floor(Math.random() * 8) + 1);
door.down = function () {
showInterior(this.interiorAsset);
};
}
}
}
// Add single hunks at strategic positions - positioned away from doors
var hunkPositions = [{
x: 1000,
y: 1480,
platformIndex: 1
},
// First hunk on safe platform
{
x: 3400,
y: 980,
platformIndex: 7
},
// Mid level hunk - away from doors
{
x: 5400,
y: 1280,
platformIndex: 13
} // Final hunk - clear area
];
for (var h = 0; h < hunkPositions.length; h++) {
var hunk = new Hunk();
hunk.x = hunkPositions[h].x;
hunk.y = hunkPositions[h].y;
hunks.push(hunk);
worldContainer.addChild(hunk);
}
// Add stairs to connect platforms at different heights
var stairsPositions = [{
x: 600,
y: 1700,
connectsTo: {
x: 800,
y: 1600
}
}, {
x: 1000,
y: 1550,
connectsTo: {
x: 1200,
y: 1500
}
}, {
x: 1800,
y: 1450,
connectsTo: {
x: 2000,
y: 1400
}
}, {
x: 2200,
y: 1250,
connectsTo: {
x: 2400,
y: 1200
}
}, {
x: 2600,
y: 1050,
connectsTo: {
x: 2800,
y: 1000
}
}, {
x: 3400,
y: 1150,
connectsTo: {
x: 3600,
y: 1300
}
}, {
x: 4200,
y: 1350,
connectsTo: {
x: 4400,
y: 1200
}
}, {
x: 4600,
y: 1050,
connectsTo: {
x: 4800,
y: 1000
}
}];
for (var i = 0; i < stairsPositions.length; i++) {
var stairs = new Stairs();
stairs.x = stairsPositions[i].x;
stairs.y = stairsPositions[i].y;
// Scale stairs based on height difference
var heightDiff = Math.abs(stairsPositions[i].y - stairsPositions[i].connectsTo.y);
stairs.scale.x = 0.8;
stairs.scale.y = 0.6 + heightDiff / 300 * 0.4;
// Rotate stairs to point toward connected platform
var dx = stairsPositions[i].connectsTo.x - stairsPositions[i].x;
if (dx < 0) {
stairs.scale.x = -0.8; // Flip stairs if going left
}
worldContainer.addChild(stairs);
// Ensure stairs appear behind platforms but in front of backgrounds
var stairsIndex = worldContainer.getChildIndex(stairs);
worldContainer.setChildIndex(stairs, Math.max(10, stairsIndex - 20));
}
// Add hunks inside interiors for immersion
var interiorHunks = [{
x: 2400,
y: 1000,
interior: true
}, {
x: 4200,
y: 900,
interior: true
}];
for (var ih = 0; ih < interiorHunks.length; ih++) {
var interiorHunk = new Hunk();
interiorHunk.x = interiorHunks[ih].x;
interiorHunk.y = interiorHunks[ih].y;
interiorHunk.isInterior = true;
hunks.push(interiorHunk);
worldContainer.addChild(interiorHunk);
}
bloodmage = new Bloodmage();
bloodmage.x = 400; // Start on first platform
bloodmage.y = 1780;
bloodmage.grounded = true; // Ensure character starts on ground
bloodmage.isMoving = false; // Ensure character is not moving
bloodmage.isJumping = false; // Ensure character is not jumping
bloodmage.isFlying = false; // Ensure character is not flying
worldContainer.addChild(bloodmage);
// CRITICAL: Ensure player appears in front of ALL background elements
var playerIndex = worldContainer.getChildIndex(bloodmage);
worldContainer.setChildIndex(bloodmage, worldContainer.children.length - 1);
// COMPLETELY REBUILT ANIMATION INITIALIZATION
// Set initial state
bloodmage.currentAnimationState = 'idle';
bloodmage.currentIdleFrame = 0;
bloodmage.idleAnimationDirection = 1;
bloodmage.isMoving = false;
bloodmage.isJumping = false;
bloodmage.isFlying = false;
// Clear ALL animations and timers
bloodmage.clearAllAnimations();
// Verify idle frames exist and are properly set up (playeridle to playeridle12)
if (bloodmage.idleFrames.length >= 6) {
// Show ONLY the first idle frame (playeridle)
bloodmage.idleFrames[0].alpha = 1;
bloodmage.currentIdleFrame = 0;
// Start proper idle animation immediately
LK.setTimeout(function () {
bloodmage.startIdleAnimation();
}, 300); // Slight delay to ensure everything is initialized
}
// Generate initial Holocosmos area north of Nocturne City
generateLevelChunk(8000); // Generate Holocosmos area beyond main city
// Track initial generation position
lastGeneratedX = 10500; // Extended to accommodate Holocosmos area
}
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) {
jumpButtonHeld = true;
jumpHoldStartTime = Date.now();
var _animateButtonBlink = function animateButtonBlink() {
if (currentBlinkFrame < blinkFrames.length) {
var frameAsset = LK.getAsset(blinkFrames[currentBlinkFrame], {
anchorX: 0.5,
anchorY: 0.5
});
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;
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();
}
}
});
}
});
}
};
var blinkFrames = ['buttonblink', 'buttonblink2', 'buttonblink3', 'buttonblink4'];
var currentBlinkFrame = 0;
_animateButtonBlink();
var currentTime = Date.now();
var timeSinceLastJump = currentTime - bloodmage.lastJumpTime;
// Check for double tap timing - but only if finger held down on second tap
if (timeSinceLastJump < doubleTapThreshold && bloodmage.jumpCount === 1) {
// Double tap detected - check if this is being held for flight
// Start flight mode immediately on double tap detection
bloodmage.isFlying = true;
isFlying = true;
// Strong initial upward boost for flight initiation
bloodmage.velocityY = -12; // Stronger boost to feel responsive
bloodmage.grounded = false;
bloodmage.startFlyAnimation();
LK.getSound('jump').play();
bloodmage.jumpCount = 0;
// Add visual flight initiation effect
var flightEffect = worldContainer.attachAsset('spell2', {
anchorX: 0.5,
anchorY: 0.5,
x: bloodmage.x,
y: bloodmage.y - 10,
alpha: 0.9,
scaleX: 0.8,
scaleY: 0.8
});
tween(flightEffect, {
alpha: 0,
scaleX: 2.0,
scaleY: 2.0
}, {
duration: 600,
easing: tween.easeOut,
onFinish: function onFinish() {
flightEffect.destroy();
}
});
} else {
// Normal jump attempt - record this as first tap
var jumpSuccess = bloodmage.jump();
if (jumpSuccess) {
bloodmage.lastJumpTime = currentTime;
bloodmage.jumpCount = 1; // Mark as first jump for double-tap detection
}
}
}
};
jumpBtn.up = function () {
if (jumpButtonHeld && isFlying && bloodmage) {
// Release flight mode with graceful descent
jumpButtonHeld = false;
isFlying = false;
bloodmage.isFlying = false;
bloodmage.stopFlyAnimation();
bloodmage.startFallAnimation();
// Apply realistic falling physics with parabolic arc
var currentUpwardVelocity = Math.min(bloodmage.velocityY, 0);
bloodmage.velocityY = Math.max(currentUpwardVelocity, 3); // Gentle fall start
// Maintain some horizontal momentum for natural arc
bloodmage.velocityX *= 0.7; // Slight air resistance
// Add falling visual effect
var fallEffect = worldContainer.attachAsset('spell', {
anchorX: 0.5,
anchorY: 0.5,
x: bloodmage.x,
y: bloodmage.y - 20,
alpha: 0.6,
scaleX: 1.5,
scaleY: 0.8
});
tween(fallEffect, {
alpha: 0,
y: bloodmage.y + 50,
scaleX: 0.8,
scaleY: 1.2
}, {
duration: 800,
easing: tween.easeIn,
onFinish: function onFinish() {
fallEffect.destroy();
}
});
}
jumpButtonHeld = false;
};
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();
}
}
};
// Score text removed - using Brostiary for hunk tracking instead
// 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 using gold coins instead
var currencyText = new Text2('GOLD: ' + capturedHunks.length * 10, {
size: 100,
fill: 0xFFD700,
fontWeight: 'bold'
});
currencyText.anchor.set(0.5, 0.5);
currencyText.x = 1024;
currencyText.y = 2500;
currencyText.alpha = 0;
// Add gold glow
currencyText.style = {
fontSize: 100,
fill: 0xFFD700,
fontWeight: 'bold',
dropShadow: true,
dropShadowColor: 0xFF8C00,
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 = 500 + localIndex * 500;
var itemY = 1800;
// Add appropriate display platform with better positioning
if (item.useDisplay) {
// Display platform for crystal hearts - positioned beneath item
var displayPlatform = shopOverlay.attachAsset('displayplatform', {
anchorX: 0.5,
anchorY: 0.5,
x: itemX,
y: itemY + 80,
scaleX: 2.5,
scaleY: 2.5
});
} else if (item.useShelf) {
// Shelf for plush items - positioned beneath item
var platShelf = shopOverlay.attachAsset('platshelf', {
anchorX: 0.5,
anchorY: 0.5,
x: itemX,
y: itemY + 100,
scaleX: 3,
scaleY: 3
});
}
// Item asset positioned above platform/shelf
var itemAsset = shopOverlay.attachAsset(item.asset, {
anchorX: 0.5,
anchorY: 1.0,
x: itemX,
y: itemY - 20,
scaleX: 1.8,
scaleY: 1.8,
alpha: 0
});
// Animate item appearing
tween(itemAsset, {
alpha: 1,
y: itemY - 50
}, {
duration: 400,
easing: tween.bounceOut
});
// Use proper text instead of alphabet assets for better legibility
var itemNameText = new Text2(item.name.toUpperCase(), {
size: 48,
fill: 0xFFFFFF,
fontWeight: 'bold',
wordWrap: true,
wordWrapWidth: 300
});
itemNameText.anchor.set(0.5, 0.5);
itemNameText.x = itemX;
itemNameText.y = itemY + 150;
itemNameText.alpha = 0;
// Add glow effect for better visibility
itemNameText.style = {
fontSize: 48,
fill: 0xFFFFFF,
fontWeight: 'bold',
dropShadow: true,
dropShadowColor: 0x000000,
dropShadowBlur: 8,
dropShadowDistance: 2,
wordWrap: true,
wordWrapWidth: 300
};
shopOverlay.addChild(itemNameText);
// Animate text appearing
tween(itemNameText, {
alpha: 1
}, {
duration: 400,
easing: tween.easeOut
});
// Item price with better visual hierarchy
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 + 220;
itemPrice.alpha = 0;
// Add hot pink glow
itemPrice.style = {
fontSize: 56,
fill: 0xFFFF00,
fontWeight: 'bold',
dropShadow: true,
dropShadowColor: 0xFF1493,
dropShadowBlur: 15,
dropShadowDistance: 0
};
shopOverlay.addChild(itemPrice);
tween(itemPrice, {
alpha: 1
}, {
duration: 300,
easing: tween.easeOut
});
// Buy button with enhanced visual feedback
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 + 300;
buyButton.interactive = true;
buyButton.alpha = 0;
// 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 () {
// Add purchase animation
tween(buyButton, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(buyButton, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 100,
easing: tween.easeIn
});
}
});
purchaseItem(itemIndex);
};
}(i);
shopOverlay.addChild(buyButton);
tween(buyButton, {
alpha: 1
}, {
duration: 400,
easing: tween.easeOut
});
}
// 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('GOLD: ' + capturedHunks.length * 10);
}
// Clean up transition
transitionOverlay.destroy();
}
});
}
function showShop() {
enterShop();
}
function purchaseItem(itemIndex) {
var item = shopItems[itemIndex];
var goldAmount = capturedHunks.length * 10;
if (goldAmount >= item.price) {
// Calculate how many hunks to remove based on price
var hunksToRemove = Math.ceil(item.price / 10);
for (var i = 0; i < hunksToRemove && capturedHunks.length > 0; i++) {
capturedHunks.pop();
}
storage.capturedHunks = capturedHunks;
// Score text was removed, no need to update
// 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;
var targetY = -bloodmage.y + 1366;
cameraX += (targetX - cameraX) * 0.1;
// Add vertical camera tracking for flight mode
var currentCameraY = worldContainer.y || 0;
currentCameraY += (targetY - currentCameraY) * 0.1;
worldContainer.x = cameraX;
worldContainer.y = currentCameraY;
}
}
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 properly positioned and sized between trackpad and buttons
combatMenuUI = game.attachAsset('combatmenu', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 2200,
scaleX: 2.8,
scaleY: 1.8,
alpha: 0
});
combatMenuUI.interactive = true;
// Animate combat UI appearing
tween(combatMenuUI, {
alpha: 0.95
}, {
duration: 600,
easing: tween.easeOut
});
// Position cursor with proper sizing for 4-option grid
cursorUI = game.attachAsset('cursor', {
anchorX: 0.5,
anchorY: 0.5,
x: 774,
y: 2050,
scaleX: 0.42,
scaleY: 0.56,
alpha: 0
});
// Animate cursor appearing
LK.setTimeout(function () {
tween(cursorUI, {
alpha: 1
}, {
duration: 400,
easing: tween.easeOut
});
}, 500);
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 removed - using Brostiary for hunk tracking instead
// 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 2.8x1.8)
var menuLeft = 1024 - 350; // Full width of scaled menu (250 * 2.8 scale)
var menuRight = 1024 + 350;
var menuTop = 2200 - 225; // Full height of scaled menu (250 * 1.8 scale)
var menuBottom = 2200 + 225;
if (x >= menuLeft && x <= menuRight && y >= menuTop && y <= menuBottom) {
// 2x2 grid layout for 4 options
var relativeX = (x - menuLeft) / (menuRight - menuLeft);
var relativeY = (y - menuTop) / (menuBottom - menuTop);
var colIndex = relativeX < 0.5 ? 0 : 1; // Left or right column
var rowIndex = relativeY < 0.5 ? 0 : 1; // Top or bottom row
var newOption = rowIndex * 2 + colIndex; // Convert 2D to 1D index
newOption = Math.max(0, Math.min(3, newOption));
// Cursor positions for 2x2 grid layout with updated combat menu position
var positions = [{
x: 774,
y: 2050
}, {
x: 1274,
y: 2050
}, {
x: 774,
y: 2350
}, {
x: 1274,
y: 2350
}];
if (newOption === window.currentSelectedOption) {
// Same option clicked - select it with visual feedback
LK.effects.flashObject(window.currentCursor, 0x00FF00, 200);
selectCurrentOption();
} else {
// Different option - move cursor there with smooth animation
window.currentSelectedOption = newOption;
if (window.currentCursor && positions[window.currentSelectedOption]) {
// Flash cursor to show selection change
LK.effects.flashObject(window.currentCursor, 0xFFFF00, 150);
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 - more generous interaction
for (var i = 0; i < hunks.length; i++) {
var hunk = hunks[i];
if (!hunk.captured) {
// More generous proximity and tap area
var playerDistance = Math.sqrt(Math.pow(bloodmage.x - hunk.x, 2) + Math.pow(bloodmage.y - hunk.y, 2));
var tapDistance = Math.sqrt(Math.pow(worldPos.x - hunk.x, 2) + Math.pow(worldPos.y - hunk.y, 2));
if (playerDistance < 600 && tapDistance < 500) {
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
}
// Check 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) {
jumpButtonHeld = true;
jumpHoldStartTime = Date.now();
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 - initiate flight if conditions met regardless of movement
if (timeSinceLastJump < doubleTapThreshold) {
// Double tap detected - initiate flight mode
bloodmage.isFlying = true;
isFlying = true;
// Gentle lift to enter flight mode smoothly
bloodmage.velocityY = Math.min(bloodmage.velocityY, -8); // Smooth entry
bloodmage.grounded = false;
bloodmage.startFlyAnimation();
LK.getSound('jump').play();
bloodmage.jumpCount = 0; // Reset for next sequence
// Visual flight effect
var flightEffect = worldContainer.attachAsset('spell2', {
anchorX: 0.5,
anchorY: 0.5,
x: bloodmage.x,
y: bloodmage.y - 10,
alpha: 0.9,
scaleX: 0.8,
scaleY: 0.8
});
tween(flightEffect, {
alpha: 0,
scaleX: 2.0,
scaleY: 2.0
}, {
duration: 600,
easing: tween.easeOut,
onFinish: function onFinish() {
flightEffect.destroy();
}
});
} else {
// Normal jump attempt
var jumpSuccess = bloodmage.jump();
if (jumpSuccess) {
bloodmage.lastJumpTime = currentTime;
bloodmage.jumpCount = 1; // Mark first jump for double-tap detection
}
}
}
// 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 () {
// Handle jump button release for flight mode
if (jumpButtonHeld && isFlying && bloodmage) {
// Release flight mode with graceful descent
jumpButtonHeld = false;
isFlying = false;
bloodmage.isFlying = false;
bloodmage.stopFlyAnimation();
bloodmage.startFallAnimation();
// Apply realistic falling physics with parabolic arc
var currentUpwardVelocity = Math.min(bloodmage.velocityY, 0);
bloodmage.velocityY = Math.max(currentUpwardVelocity, 3); // Gentle fall start
// Maintain some horizontal momentum for natural arc
bloodmage.velocityX *= 0.7; // Slight air resistance
// Add falling visual effect
var fallEffect = worldContainer.attachAsset('spell', {
anchorX: 0.5,
anchorY: 0.5,
x: bloodmage.x,
y: bloodmage.y - 20,
alpha: 0.6,
scaleX: 1.5,
scaleY: 0.8
});
tween(fallEffect, {
alpha: 0,
y: bloodmage.y + 50,
scaleX: 0.8,
scaleY: 1.2
}, {
duration: 800,
easing: tween.easeIn,
onFinish: function onFinish() {
fallEffect.destroy();
}
});
}
// Handle trackpad release
trackpadPressed = false;
if (bloodmage) {
bloodmage.velocityX = 0;
}
trackpadThumb.x = 200;
trackpadThumb.y = -200;
// Always reset jump button held state on any touch release
jumpButtonHeld = false;
};
function updateTrackpad(x, y) {
// Convert to local trackpad coordinates
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);
// Constrain to trackpad area
if (dist > 80) {
dx = dx / dist * 80;
dy = dy / dist * 80;
}
// Update visual trackpad thumb
trackpadThumb.x = 200 + dx;
trackpadThumb.y = -200 + dy;
if (bloodmage && dist > 8) {
// Calculate angle for ALL 8 directions with proper recognition
trackpadAngle = Math.atan2(dy, dx);
if (bloodmage.isFlying && jumpButtonHeld) {
// REBUILT FLIGHT CONTROL: Pure 8-directional movement
var flightSpeed = bloodmage.speed * 0.8;
// Calculate movement components for ALL 8 directions
var moveX = Math.cos(trackpadAngle) * flightSpeed;
var moveY = Math.sin(trackpadAngle) * flightSpeed;
// CRITICAL: The flight movement is handled in bloodmage.update()
// Just store the trackpad state - NO direct position changes here
bloodmage.velocityX = 0;
bloodmage.velocityY = 0;
bloodmage.grounded = false;
// Update facing direction
if (moveX > 0) bloodmage.facingDirection = -1;else if (moveX < 0) bloodmage.facingDirection = 1;
} else {
// Ground movement - horizontal only
bloodmage.velocityX = dx / 80 * bloodmage.speed * 3.5;
}
}
}
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) {
// Cast - perform casting animation
performBattleCast();
} else if (selectedOption === 2) {
// Speak - show dialogue with player response
showDualDialogue();
} else if (selectedOption === 3) {
// Leave - exit battle UI
hideBattleUI();
currentHunk = null;
}
}
function performCaptureAnimation() {
if (!currentHunk) return;
// Store player position to prevent falling
var castX = bloodmage.x;
var castY = bloodmage.y;
var wasGrounded = bloodmage.grounded;
// Disable physics completely during battle action
bloodmage.x = castX;
bloodmage.y = castY;
bloodmage.grounded = wasGrounded;
bloodmage.velocityX = 0;
bloodmage.velocityY = 0;
bloodmage.isMoving = false;
bloodmage.isFlying = false;
// Perform cast animation first
performPlayerCastAnimation();
// 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() {
// RNG based on hunk's resistance meter
var captureChance = 1 - currentHunk.resistance / currentHunk.maxResistance;
var captureRoll = Math.random();
if (captureRoll < captureChance) {
// Success - shrink hunk into device
LK.getSound('capture').play();
tween(currentHunk, {
scaleX: 0.1,
scaleY: 0.1,
x: captureDevice.x,
y: captureDevice.y
}, {
duration: 400,
easing: tween.easeIn,
onFinish: function onFinish() {
currentHunk.captured = true;
currentHunk.visible = false;
capturedHunks.push(currentHunk.hunkType);
storage.capturedHunks = capturedHunks;
if (!brostiary[currentHunk.hunkType]) {
brostiary[currentHunk.hunkType] = true;
storage.brostiary = brostiary;
}
// scoreText removed - using Brostiary for hunk tracking instead
showXPMenu(true);
captureDevice.destroy();
captureEffect.destroy();
// Restore player position and state
bloodmage.x = castX;
bloodmage.y = castY;
bloodmage.grounded = wasGrounded;
bloodmage.velocityX = 0;
bloodmage.velocityY = 0;
}
});
} else {
// Failed - device bounces off hunk
tween(captureDevice, {
x: captureDevice.x + (captureDevice.x - currentHunk.x) * 0.5,
y: captureDevice.y - 100,
rotation: Math.PI * 4
}, {
duration: 400,
easing: tween.bounceOut,
onFinish: function onFinish() {
captureDevice.destroy();
}
});
// 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();
captureEffect.destroy();
// Restore player position
bloodmage.x = castX;
bloodmage.y = castY;
bloodmage.grounded = wasGrounded;
}
});
}
}
});
}
});
}
function performBattleCast() {
if (!currentHunk) return;
// Store player position and state to prevent falling
var playerGrounded = bloodmage.grounded;
var playerX = bloodmage.x;
var playerY = bloodmage.y;
var playerVelY = bloodmage.velocityY;
// 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();
// Perform cast animation while keeping player in place
performPlayerCastAnimation();
// Damage hunk with additional sound effect
castSpell(25);
LK.getSound('climax').play();
// Clean up after 2 seconds
LK.setTimeout(function () {
if (spellBehind) spellBehind.destroy();
if (spellPulse) spellPulse.destroy();
// Restore player position and state
bloodmage.x = playerX;
bloodmage.y = playerY;
bloodmage.velocityY = playerGrounded ? 0 : playerVelY;
bloodmage.grounded = playerGrounded;
}, 2000);
}
function showDualDialogue() {
if (!currentHunk) return;
// Player dialogue floating above head
var playerDialogue = worldContainer.attachAsset('dialoguebox', {
anchorX: 0.5,
anchorY: 1.0,
x: bloodmage.x,
y: bloodmage.y - 400,
scaleX: 6,
scaleY: 4,
alpha: 0
});
// Animate dialogue appearing
tween(playerDialogue, {
alpha: 1,
y: bloodmage.y - 450
}, {
duration: 300,
easing: tween.easeOut
});
var playerText = new Text2('SUBMIT TO MY WILL!', {
size: 18,
fill: 0xFF00FF,
fontWeight: 'bold',
wordWrap: true,
wordWrapWidth: 120
});
playerText.anchor.set(0.5, 0.5);
playerText.x = 0;
playerText.y = 0;
playerDialogue.addChild(playerText);
// Hunk dialogue floating above head
var hunkDialogue = worldContainer.attachAsset('dialoguebox', {
anchorX: 0.5,
anchorY: 1.0,
x: currentHunk.x,
y: currentHunk.y - 400,
scaleX: 8,
scaleY: 6,
alpha: 0
});
// Animate dialogue appearing with slight delay
LK.setTimeout(function () {
tween(hunkDialogue, {
alpha: 1,
y: currentHunk.y - 450
}, {
duration: 300,
easing: tween.easeOut
});
}, 200);
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: 20,
fill: 0xFFFFFF,
fontWeight: 'bold',
wordWrap: true,
wordWrapWidth: 160
});
hunkText.anchor.set(0.5, 0.5);
hunkText.y = 10;
hunkDialogue.addChild(hunkText);
// Play grunt sound for hunk dialogue
LK.getSound('grunt').play();
// Auto-hide both dialogues after 4 seconds with fade out
LK.setTimeout(function () {
tween(playerDialogue, {
alpha: 0,
y: bloodmage.y - 500
}, {
duration: 300,
easing: tween.easeIn,
onFinish: function onFinish() {
if (playerDialogue) playerDialogue.destroy();
}
});
tween(hunkDialogue, {
alpha: 0,
y: currentHunk.y - 500
}, {
duration: 300,
easing: tween.easeIn,
onFinish: function onFinish() {
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: 12,
scaleY: 10,
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 positioned within menu boundaries
var xpText = new Text2('EXPERIENCE GAINED: ' + totalXP, {
size: 60,
fill: 0x00FF00,
fontWeight: 'bold',
wordWrap: true,
wordWrapWidth: 600
});
xpText.anchor.set(0.5, 0.5);
xpText.x = 1024;
xpText.y = 1300;
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('hedonism');
// REBUILT TITLE ANIMATION: Proper spacing and squeeze effect with wave momentum
function showTitle() {
var titleContainer = game.addChild(new Container());
// Letter positions for "NOCTURNE CITY" - NOCTURNE moved 0.5 inch left with proper spacing
var letters = [{
asset: 'n',
finalX: -600,
// NOCTURNE moved left 0.5 inch
startX: 2500 // Start from right side for squeeze effect
}, {
asset: 'o',
finalX: -500,
startX: 2500
}, {
asset: 'c',
finalX: -400,
startX: 2500
}, {
asset: 't',
finalX: -300,
startX: 2500
}, {
asset: 'u',
finalX: -200,
startX: 2500
}, {
asset: 'r',
finalX: -100,
startX: 2500
}, {
asset: 'n',
finalX: 0,
startX: 2500
}, {
asset: 'e',
finalX: 100,
startX: 2500
}, {
// Space between NOCTURNE and CITY - CITY in original position
asset: 'c',
finalX: 300,
// Proper gap between words
startX: 3000
}, {
asset: 'i',
finalX: 400,
startX: 3000
}, {
asset: 't',
finalX: 500,
startX: 3000
}, {
asset: 'y',
finalX: 600,
startX: 3000
}];
var letterAssets = [];
// Create all letters starting from right side
for (var i = 0; i < letters.length; i++) {
var letter = titleContainer.attachAsset(letters[i].asset, {
anchorX: 0.5,
anchorY: 0.5,
x: letters[i].startX,
y: 600,
// Above player position
scaleX: 0.5,
// Start small for squeeze effect
scaleY: 0.5,
alpha: 0
});
letterAssets.push(letter);
}
// Animate letters with wave momentum and squeeze effect
function animateSqueezeIn() {
for (var i = 0; i < letterAssets.length; i++) {
var letter = letterAssets[i];
var finalX = 1024 + letters[i].finalX;
// Each letter appears with staggered timing for wave effect
(function (index, targetLetter, targetX) {
LK.setTimeout(function () {
// Fade in letter
tween(targetLetter, {
alpha: 1
}, {
duration: 200,
easing: tween.easeOut
});
// Squeeze animation - expand and move to final position
tween(targetLetter, {
x: targetX,
scaleX: 2.8,
// Final scale
scaleY: 2.8
}, {
duration: 600,
easing: tween.bounceOut // Wave momentum effect
});
}, index * 120); // Staggered timing
})(i, letter, finalX);
}
// Hold for 3 seconds then fade out left to right
LK.setTimeout(function () {
animateLettersOut();
}, 3500);
}
// Animate letters fading out from left to right
function animateLettersOut() {
for (var i = 0; i < letterAssets.length; i++) {
(function (index, targetLetter) {
LK.setTimeout(function () {
tween(targetLetter, {
alpha: 0,
y: 400,
scaleX: 0.2,
scaleY: 0.2
}, {
duration: 300,
easing: tween.easeIn
});
}, index * 80);
})(i, letterAssets[i]);
}
// Clean up after fade
LK.setTimeout(function () {
titleContainer.destroy();
}, 2000);
}
// Start the squeeze animation
animateSqueezeIn();
}
// Show title animation on game start
showTitle();
;
var placeholderInteriorShowing = false;
var placeholderOverlay = null;
var interiorShowing = false;
var interiorOverlay = null;
function showInterior(interiorAsset) {
if (interiorShowing) return;
interiorShowing = true;
// Create interior overlay with door expand animation
var transitionOverlay = game.addChild(new Container());
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
tween(expandingDoor, {
scaleX: 5.0,
scaleY: 5.0,
alpha: 0.95
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
// Create actual interior overlay
interiorOverlay = game.addChild(new Container());
var interior = interiorOverlay.attachAsset(interiorAsset, {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1366,
scaleX: 2.0,
scaleY: 2.0,
alpha: 0
});
tween(interior, {
alpha: 1
}, {
duration: 600,
easing: tween.easeOut
});
// Hide brostiary icon when interior is showing
if (brostiaryIcon) {
brostiaryIcon.alpha = 0;
}
// Add exit button
var exitBtn = interiorOverlay.attachAsset('x', {
anchorX: 0.5,
anchorY: 0.5,
x: 1800,
y: 300,
scaleX: 2.5,
scaleY: 2.5,
alpha: 0
});
exitBtn.interactive = true;
exitBtn.down = function () {
closeInterior();
};
tween(exitBtn, {
alpha: 1
}, {
duration: 500,
easing: tween.easeOut
});
// Cleanup transition
transitionOverlay.destroy();
}
});
}
function closeInterior() {
if (!interiorShowing || !interiorOverlay) return;
interiorShowing = false;
// Show brostiary icon again
if (brostiaryIcon) {
brostiaryIcon.alpha = 1;
}
interiorOverlay.destroy();
interiorOverlay = null;
}
function showPlaceholderInterior() {
showInterior('interior');
}
function performPlayerCastAnimation() {
if (!bloodmage || isCasting) return;
isCasting = true;
LK.getSound('spell').play();
// Store player position to maintain it during animation
var castX = bloodmage.x;
var castY = bloodmage.y;
var wasGrounded = bloodmage.grounded;
// 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'];
var castAnimFrames = [];
for (var i = 0; i < castFrames.length; i++) {
var frame = worldContainer.attachAsset(castFrames[i], {
anchorX: 0.5,
anchorY: 1.0,
x: castX,
y: castY,
alpha: 0
});
frame.scale.x = bloodmage.facingDirection;
castAnimFrames.push(frame);
}
// Animate through cast frames
var currentCastFrame = 0;
function animateCast() {
if (currentCastFrame < castAnimFrames.length) {
// Keep player in exact position
bloodmage.x = castX;
bloodmage.y = castY;
bloodmage.grounded = wasGrounded;
bloodmage.velocityY = 0;
// Fade out previous frame
if (currentCastFrame > 0) {
tween(castAnimFrames[currentCastFrame - 1], {
alpha: 0
}, {
duration: 100,
easing: tween.easeInOut
});
}
// Fade in current frame
var currentFrame = castAnimFrames[currentCastFrame];
tween(currentFrame, {
alpha: 1
}, {
duration: 100,
easing: tween.easeInOut
});
currentCastFrame++;
LK.setTimeout(animateCast, 120);
} else {
// Clean up cast animation
for (var i = 0; i < castAnimFrames.length; i++) {
castAnimFrames[i].destroy();
}
isCasting = false;
// Restore player position one final time
bloodmage.x = castX;
bloodmage.y = castY;
bloodmage.grounded = wasGrounded;
bloodmage.velocityY = 0;
// Resume idle animation
if (!bloodmage.isMoving && bloodmage.grounded) {
bloodmage.startIdleAnimation();
}
}
}
animateCast();
} ===================================================================
--- original.js
+++ change.js
@@ -6,904 +6,8 @@
/****
* Classes
****/
-var AssetsManager = Container.expand(function () {
- var self = Container.call(this);
- // Core properties
- self.isActive = false;
- self.selectedAsset = null;
- self.dragTarget = null;
- self.clipboard = null;
- self.currentCategory = 'all';
- self.currentPage = 0;
- self.itemsPerPage = 12;
- // Asset categories for organization
- self.assetCategories = {
- all: 'ALL ASSETS',
- characters: 'CHARACTERS',
- platforms: 'PLATFORMS',
- buildings: 'BUILDINGS',
- effects: 'EFFECTS',
- ui: 'UI ELEMENTS',
- nature: 'NATURE'
- };
- // Categorized asset lists
- self.categorizedAssets = {
- characters: ['hunk', 'hunk2', 'hunk3', 'hunk4', 'bloodmage', 'cast', 'cast2', 'cast3', 'cast4', 'cast5', 'cast6', 'cast7', 'cast8', 'cast9', 'chazbin', 'chazbin2', 'chazbin3', 'chazbin4', 'chazbin5', 'chazbin6', 'mandroid'],
- platforms: ['platform', 'platform2', 'platform3', 'platform4', 'stairs', 'stairs2', 'cosmicplatform', 'cosmicplatform2', 'cosmicplatform3', 'mossyplatform', 'mossyplatform2', 'platshelf', 'displayplatform'],
- buildings: ['building', 'building2', 'building3', 'building4', 'Building2', 'statue', 'door', 'door2', 'door3', 'shop', 'shop2'],
- effects: ['spell', 'spell2', 'spell3', 'spell4', 'effect', 'effect2', 'effect3', 'foresteffect', 'foresteffect2', 'seaeffect', 'undereffect', 'undereffect2', 'captureeffect', 'leapattack', 'leapattack2', 'leapattack3'],
- ui: ['actionbutton', 'jumpButton', 'spellButton', 'trackpadBg', 'trackpadThumb', 'brostiary', 'inventory', 'combatmenu', 'cursor', 'dialoguebox', 'expobox', 'resistanceBar', 'resistanceFill'],
- nature: ['cloud1', 'cloud2', 'cloud3', 'trees', 'trees2', 'trees3', 'trees4', 'crystal', 'crystalheart', 'starlight', 'starlight2']
- };
- // Get all assets for 'all' category
- self.getAllAssets = function () {
- var allAssets = [];
- for (var category in self.categorizedAssets) {
- allAssets = allAssets.concat(self.categorizedAssets[category]);
- }
- // Add background assets
- var bgAssets = ['bg', 'bg2', 'bg3', 'bg4', 'nocturnecitylayout', 'forest', 'forest2', 'forest3', 'forest5', 'forestbg', 'forestbg2', 'Galaxybg', 'galaxy', 'galaxy2', 'galaxy3', 'galaxy4', 'galaxybg2', 'galaxybg3', 'galaxybg4', 'sea', 'sea2', 'sea3', 'sea4', 'sea5', 'underbg', 'underbg2', 'underbg3', 'underbg4', 'underbg5', 'cavern', 'cavern2', 'cavefloor', 'cavefloor2', 'caveoverlay', 'underoverlay', 'underoverlay2', 'underoverlay3'];
- return allAssets.concat(bgAssets);
- };
- // Animation frame groups
- self.animationGroups = {
- 'player_idle': ['playeridle', 'playeridle2', 'playeridle3', 'playeridle4', 'playeridle5', 'playeridle6', 'playeridle9', 'playeridle10', 'playeridle11', 'playeridle12'],
- 'player_walk': ['playerwalk', 'playerwalk2', 'playerwalk3', 'playerwalk4', 'playerwalk5', 'playerwalk6', 'playerwalk7', 'playerwalk8', 'playerwalk9', 'playerwalk10', 'playerwalk11', 'playerwalk12'],
- 'player_jump': ['playerjump', 'playerjump2', 'playerjump3', 'playerjump4', 'playerjump5', 'playerjump6'],
- 'player_fly': ['playerfly', 'playerfly2', 'playerfly3', 'playerfly4', 'playerfly5', 'playerfly6', 'playerfly7', 'playerfly8'],
- 'cast_sequence': ['cast', 'cast2', 'cast3', 'cast4', 'cast5', 'cast6', 'cast7', 'cast8', 'cast9'],
- 'hunk_variants': ['hunk', 'hunka', 'hunkb', 'hunkc', 'hunkd', 'hunke'],
- 'hunk2_variants': ['hunk2', 'hunk2a', 'hunk2b', 'hunk2c', 'hunk2d'],
- 'hunk3_variants': ['hunk3', 'hunk3a', 'hunk3b', 'hunk3c', 'hunk3d'],
- 'hunk4_variants': ['hunk4', 'hunk4a', 'hunk4b', 'hunk4c', 'hunk4d'],
- 'button_blink': ['buttonblink', 'buttonblink2', 'buttonblink3', 'buttonblink4']
- };
- // Initialize the assets manager
- self.init = function () {
- self.createUI();
- self.setupEventHandlers();
- };
- // Create the main UI
- self.createUI = function () {
- // Main container
- self.uiContainer = game.addChild(new Container());
- // Semi-transparent overlay
- self.overlay = self.uiContainer.attachAsset('bropage', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 1024,
- y: 1366,
- scaleX: 2.5,
- scaleY: 3.0,
- alpha: 0
- });
- // Title
- self.titleText = new Text2('ASSETS MANAGER', {
- size: 80,
- fill: 0xFFFFFF,
- fontWeight: 'bold'
- });
- self.titleText.anchor.set(0.5, 0.5);
- self.titleText.x = 1024;
- self.titleText.y = 300;
- self.uiContainer.addChild(self.titleText);
- // Close button
- self.closeButton = self.uiContainer.attachAsset('x', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 1800,
- y: 300,
- scaleX: 2,
- scaleY: 2
- });
- self.closeButton.interactive = true;
- self.closeButton.down = function () {
- self.hide();
- };
- // Category tabs
- self.createCategoryTabs();
- // Assets grid
- self.createAssetsGrid();
- // Tools panel
- self.createToolsPanel();
- // Properties panel
- self.createPropertiesPanel();
- self.uiContainer.alpha = 0;
- };
- // Create category navigation tabs
- self.createCategoryTabs = function () {
- self.categoryTabs = [];
- var tabWidth = 180;
- var startX = 200;
- var tabY = 450;
- var categoryKeys = Object.keys(self.assetCategories);
- for (var i = 0; i < categoryKeys.length; i++) {
- var categoryKey = categoryKeys[i];
- var categoryName = self.assetCategories[categoryKey];
- var tab = self.uiContainer.attachAsset('expobox', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: startX + i * tabWidth,
- y: tabY,
- scaleX: 4,
- scaleY: 1.5,
- alpha: categoryKey === self.currentCategory ? 1.0 : 0.7
- });
- var tabText = new Text2(categoryName, {
- size: 24,
- fill: categoryKey === self.currentCategory ? 0x00FFFF : 0xFFFFFF,
- fontWeight: 'bold'
- });
- tabText.anchor.set(0.5, 0.5);
- tabText.x = startX + i * tabWidth;
- tabText.y = tabY;
- self.uiContainer.addChild(tabText);
- tab.interactive = true;
- tab.categoryKey = categoryKey;
- tab.tabText = tabText;
- tab.down = function () {
- self.switchCategory(this.categoryKey);
- };
- self.categoryTabs.push({
- tab: tab,
- text: tabText,
- key: categoryKey
- });
- }
- };
- // Create assets grid display
- self.createAssetsGrid = function () {
- self.assetsGrid = self.uiContainer.addChild(new Container());
- self.assetsGrid.x = 0;
- self.assetsGrid.y = 550;
- // Navigation buttons
- self.prevButton = new Text2('◄ PREV', {
- size: 40,
- fill: 0xFFFFFF,
- fontWeight: 'bold'
- });
- self.prevButton.anchor.set(0.5, 0.5);
- self.prevButton.x = 200;
- self.prevButton.y = 1000;
- self.prevButton.interactive = true;
- self.prevButton.down = function () {
- if (self.currentPage > 0) {
- self.currentPage--;
- self.refreshAssetsGrid();
- }
- };
- self.uiContainer.addChild(self.prevButton);
- self.nextButton = new Text2('NEXT ►', {
- size: 40,
- fill: 0xFFFFFF,
- fontWeight: 'bold'
- });
- self.nextButton.anchor.set(0.5, 0.5);
- self.nextButton.x = 1800;
- self.nextButton.y = 1000;
- self.nextButton.interactive = true;
- self.nextButton.down = function () {
- var maxPages = Math.ceil(self.getCurrentAssets().length / self.itemsPerPage) - 1;
- if (self.currentPage < maxPages) {
- self.currentPage++;
- self.refreshAssetsGrid();
- }
- };
- self.uiContainer.addChild(self.nextButton);
- // Page indicator
- self.pageIndicator = new Text2('', {
- size: 30,
- fill: 0xFFFFFF
- });
- self.pageIndicator.anchor.set(0.5, 0.5);
- self.pageIndicator.x = 1024;
- self.pageIndicator.y = 1000;
- self.uiContainer.addChild(self.pageIndicator);
- };
- // Create tools panel
- self.createToolsPanel = function () {
- self.toolsPanel = self.uiContainer.addChild(new Container());
- var toolsY = 1200;
- var toolSpacing = 150;
- var startX = 300;
- var tools = [{
- name: 'SELECT',
- icon: 'cursor',
- action: 'select'
- }, {
- name: 'MOVE',
- icon: 'actionbutton',
- action: 'move'
- }, {
- name: 'SCALE',
- icon: 'resistanceFill',
- action: 'scale'
- }, {
- name: 'ROTATE',
- icon: 'spell2',
- action: 'rotate'
- }, {
- name: 'COPY',
- icon: 'crystal',
- action: 'copy'
- }, {
- name: 'PASTE',
- icon: 'crystalheart',
- action: 'paste'
- }, {
- name: 'DELETE',
- icon: 'x',
- action: 'delete'
- }, {
- name: 'LAYER ▲',
- icon: 'jumpButton',
- action: 'layerUp'
- }, {
- name: 'LAYER ▼',
- icon: 'trackpadBg',
- action: 'layerDown'
- }];
- for (var i = 0; i < tools.length; i++) {
- var tool = tools[i];
- var toolButton = self.toolsPanel.attachAsset(tool.icon, {
- anchorX: 0.5,
- anchorY: 0.5,
- x: startX + i * toolSpacing,
- y: toolsY,
- scaleX: 0.8,
- scaleY: 0.8
- });
- var toolText = new Text2(tool.name, {
- size: 20,
- fill: 0xFFFFFF,
- fontWeight: 'bold'
- });
- toolText.anchor.set(0.5, 0.5);
- toolText.x = startX + i * toolSpacing;
- toolText.y = toolsY + 60;
- self.toolsPanel.addChild(toolText);
- toolButton.interactive = true;
- toolButton.toolAction = tool.action;
- toolButton.down = function () {
- self.executeTool(this.toolAction);
- };
- }
- };
- // Create properties panel
- self.createPropertiesPanel = function () {
- self.propertiesPanel = self.uiContainer.addChild(new Container());
- self.propertiesTitle = new Text2('PROPERTIES', {
- size: 40,
- fill: 0x00FFFF,
- fontWeight: 'bold'
- });
- self.propertiesTitle.anchor.set(0.5, 0.5);
- self.propertiesTitle.x = 1024;
- self.propertiesTitle.y = 1400;
- self.propertiesPanel.addChild(self.propertiesTitle);
- self.propertiesText = new Text2('Select an asset to view properties', {
- size: 24,
- fill: 0xFFFFFF,
- wordWrap: true,
- wordWrapWidth: 800
- });
- self.propertiesText.anchor.set(0.5, 0.5);
- self.propertiesText.x = 1024;
- self.propertiesText.y = 1500;
- self.propertiesPanel.addChild(self.propertiesText);
- };
- // Get assets for current category
- self.getCurrentAssets = function () {
- if (self.currentCategory === 'all') {
- return self.getAllAssets();
- }
- return self.categorizedAssets[self.currentCategory] || [];
- };
- // Switch category
- self.switchCategory = function (categoryKey) {
- self.currentCategory = categoryKey;
- self.currentPage = 0;
- // Update tab appearance
- for (var i = 0; i < self.categoryTabs.length; i++) {
- var tabData = self.categoryTabs[i];
- if (tabData.key === categoryKey) {
- tabData.tab.alpha = 1.0;
- tabData.text.fill = 0x00FFFF;
- } else {
- tabData.tab.alpha = 0.7;
- tabData.text.fill = 0xFFFFFF;
- }
- }
- self.refreshAssetsGrid();
- };
- // Refresh the assets grid
- self.refreshAssetsGrid = function () {
- // Clear existing grid items
- for (var i = self.assetsGrid.children.length - 1; i >= 0; i--) {
- self.assetsGrid.children[i].destroy();
- }
- var assets = self.getCurrentAssets();
- var startIndex = self.currentPage * self.itemsPerPage;
- var endIndex = Math.min(startIndex + self.itemsPerPage, assets.length);
- var cols = 4;
- var rows = 3;
- var cellWidth = 300;
- var cellHeight = 200;
- var startX = 400;
- var startY = 100;
- for (var i = startIndex; i < endIndex; i++) {
- var assetName = assets[i];
- var gridIndex = i - startIndex;
- var col = gridIndex % cols;
- var row = Math.floor(gridIndex / cols);
- var cellX = startX + col * cellWidth;
- var cellY = startY + row * cellHeight;
- // Create asset preview
- self.createAssetPreview(assetName, cellX, cellY, gridIndex);
- }
- // Update page indicator
- var totalPages = Math.ceil(assets.length / self.itemsPerPage);
- self.pageIndicator.setText('Page ' + (self.currentPage + 1) + ' / ' + totalPages);
- // Update navigation buttons
- self.prevButton.alpha = self.currentPage > 0 ? 1.0 : 0.5;
- self.nextButton.alpha = self.currentPage < totalPages - 1 ? 1.0 : 0.5;
- };
- // Create asset preview in grid
- self.createAssetPreview = function (assetName, x, y, index) {
- // Check if this is part of an animation group
- var animGroup = self.findAnimationGroup(assetName);
- if (animGroup) {
- self.createAnimatedPreview(animGroup, x, y, index);
- } else {
- self.createStaticPreview(assetName, x, y, index);
- }
- };
- // Create static asset preview
- self.createStaticPreview = function (assetName, x, y, index) {
- // Background
- var bg = self.assetsGrid.attachAsset('platshelf', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: x,
- y: y,
- scaleX: 4,
- scaleY: 3,
- alpha: 0.8
- });
- // Asset preview
- var preview = self.assetsGrid.attachAsset(assetName, {
- anchorX: 0.5,
- anchorY: 0.5,
- x: x,
- y: y - 20,
- scaleX: 0.5,
- scaleY: 0.5
- });
- // Asset name
- var nameText = new Text2(assetName.toUpperCase(), {
- size: 18,
- fill: 0xFFFFFF,
- fontWeight: 'bold'
- });
- nameText.anchor.set(0.5, 0.5);
- nameText.x = x;
- nameText.y = y + 60;
- self.assetsGrid.addChild(nameText);
- // Make interactive
- bg.interactive = true;
- bg.assetName = assetName;
- bg.down = function () {
- self.spawnAsset(this.assetName);
- };
- };
- // Create animated preview
- self.createAnimatedPreview = function (animGroup, x, y, index) {
- // Background
- var bg = self.assetsGrid.attachAsset('platshelf', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: x,
- y: y,
- scaleX: 4,
- scaleY: 3,
- alpha: 0.8,
- tint: 0xFFDDDD // Highlight animated groups
- });
- // Create animation frames
- var frames = [];
- for (var i = 0; i < animGroup.assets.length; i++) {
- var frame = self.assetsGrid.attachAsset(animGroup.assets[i], {
- anchorX: 0.5,
- anchorY: 0.5,
- x: x,
- y: y - 20,
- scaleX: 0.4,
- scaleY: 0.4,
- alpha: i === 0 ? 1 : 0
- });
- frames.push(frame);
- }
- // Start animation
- var currentFrame = 0;
- var direction = 1;
- var animateFrames = function animateFrames() {
- // Fade out current frame
- tween(frames[currentFrame], {
- alpha: 0
- }, {
- duration: 200,
- easing: tween.easeInOut
- });
- // Move to next frame
- currentFrame += direction;
- if (currentFrame >= frames.length - 1) {
- currentFrame = frames.length - 1;
- direction = -1;
- } else if (currentFrame <= 0) {
- currentFrame = 0;
- direction = 1;
- }
- // Fade in new frame
- tween(frames[currentFrame], {
- alpha: 1
- }, {
- duration: 200,
- easing: tween.easeInOut
- });
- };
- // Start animation loop
- LK.setInterval(animateFrames, 400);
- // Group name
- var nameText = new Text2(animGroup.name.toUpperCase(), {
- size: 16,
- fill: 0xFFFF00,
- fontWeight: 'bold'
- });
- nameText.anchor.set(0.5, 0.5);
- nameText.x = x;
- nameText.y = y + 60;
- self.assetsGrid.addChild(nameText);
- // Make interactive
- bg.interactive = true;
- bg.animGroup = animGroup;
- bg.down = function () {
- self.spawnAnimationGroup(this.animGroup);
- };
- };
- // Find animation group for asset
- self.findAnimationGroup = function (assetName) {
- for (var groupName in self.animationGroups) {
- var assets = self.animationGroups[groupName];
- if (assets.indexOf(assetName) !== -1) {
- return {
- name: groupName,
- assets: assets
- };
- }
- }
- return null;
- };
- // Spawn individual asset
- self.spawnAsset = function (assetName) {
- var newAsset = worldContainer.attachAsset(assetName, {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 1024,
- y: 1366,
- scaleX: 1.0,
- scaleY: 1.0
- });
- newAsset.interactive = true;
- newAsset.assetName = assetName;
- self.setupAssetInteraction(newAsset);
- // Add to background elements for tracking
- backgroundElements.push(newAsset);
- // Flash effect
- tween(newAsset, {
- alpha: 0.5,
- scaleX: 1.2,
- scaleY: 1.2
- }, {
- duration: 200,
- easing: tween.easeOut,
- onFinish: function onFinish() {
- tween(newAsset, {
- alpha: 1.0,
- scaleX: 1.0,
- scaleY: 1.0
- }, {
- duration: 200,
- easing: tween.easeIn
- });
- }
- });
- };
- // Spawn animation group
- self.spawnAnimationGroup = function (animGroup) {
- var animContainer = worldContainer.addChild(new Container());
- animContainer.x = 1024;
- animContainer.y = 1366;
- animContainer.animGroup = animGroup;
- animContainer.interactive = true;
- var frames = [];
- for (var i = 0; i < animGroup.assets.length; i++) {
- var frame = animContainer.attachAsset(animGroup.assets[i], {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 0,
- y: 0,
- scaleX: 1.0,
- scaleY: 1.0,
- alpha: i === 0 ? 1 : 0
- });
- frames.push(frame);
- }
- // Animation control
- animContainer.frames = frames;
- animContainer.currentFrame = 0;
- animContainer.direction = 1;
- animContainer.isPlaying = true;
- animContainer.playAnimation = function () {
- if (!this.isPlaying) {
- return;
- }
- tween(this.frames[this.currentFrame], {
- alpha: 0
- }, {
- duration: 150,
- easing: tween.easeInOut
- });
- this.currentFrame += this.direction;
- if (this.currentFrame >= this.frames.length - 1) {
- this.currentFrame = this.frames.length - 1;
- this.direction = -1;
- } else if (this.currentFrame <= 0) {
- this.currentFrame = 0;
- this.direction = 1;
- }
- tween(this.frames[this.currentFrame], {
- alpha: 1
- }, {
- duration: 150,
- easing: tween.easeInOut
- });
- };
- animContainer.animationTimer = LK.setInterval(function () {
- animContainer.playAnimation();
- }, 300);
- self.setupAssetInteraction(animContainer);
- backgroundElements.push(animContainer);
- // Flash effect
- tween(animContainer, {
- alpha: 0.5,
- scaleX: 1.2,
- scaleY: 1.2
- }, {
- duration: 200,
- easing: tween.easeOut,
- onFinish: function onFinish() {
- tween(animContainer, {
- alpha: 1.0,
- scaleX: 1.0,
- scaleY: 1.0
- }, {
- duration: 200,
- easing: tween.easeIn
- });
- }
- });
- };
- // Setup asset interaction
- self.setupAssetInteraction = function (asset) {
- asset.down = function (x, y, obj) {
- if (!self.isActive) {
- return;
- }
- self.selectedAsset = this;
- self.dragTarget = this;
- self.lastX = x;
- self.lastY = y;
- self.updatePropertiesPanel();
- // Highlight selected asset
- tween(this, {
- tint: 0x00FFFF
- }, {
- duration: 100,
- easing: tween.easeOut
- });
- };
- asset.move = function (x, y, obj) {
- if (!self.isActive || self.dragTarget !== this) {
- return;
- }
- var dx = x - self.lastX;
- var dy = y - self.lastY;
- this.x += dx;
- this.y += dy;
- self.lastX = x;
- self.lastY = y;
- self.updatePropertiesPanel();
- };
- asset.up = function () {
- if (self.dragTarget === this) {
- self.dragTarget = null;
- tween(this, {
- tint: 0xFFFFFF
- }, {
- duration: 200,
- easing: tween.easeIn
- });
- }
- };
- };
- // Execute tool action
- self.executeTool = function (action) {
- if (!self.selectedAsset) {
- self.showMessage('Select an asset first');
- return;
- }
- switch (action) {
- case 'move':
- // Already handled by drag
- break;
- case 'scale':
- self.showScaleControls();
- break;
- case 'rotate':
- self.selectedAsset.rotation += Math.PI / 4;
- break;
- case 'copy':
- self.clipboard = {
- assetName: self.selectedAsset.assetName || 'unknown',
- x: self.selectedAsset.x,
- y: self.selectedAsset.y,
- scaleX: self.selectedAsset.scaleX,
- scaleY: self.selectedAsset.scaleY,
- rotation: self.selectedAsset.rotation,
- alpha: self.selectedAsset.alpha
- };
- self.showMessage('Asset copied');
- break;
- case 'paste':
- if (self.clipboard) {
- self.spawnAsset(self.clipboard.assetName);
- } else {
- self.showMessage('Nothing to paste');
- }
- break;
- case 'delete':
- self.deleteSelectedAsset();
- break;
- case 'layerUp':
- self.moveAssetLayer(1);
- break;
- case 'layerDown':
- self.moveAssetLayer(-1);
- break;
- }
- };
- // Show scale controls
- self.showScaleControls = function () {
- if (!self.selectedAsset) {
- return;
- }
- var scalePanel = self.uiContainer.addChild(new Container());
- var scaleBg = scalePanel.attachAsset('expobox', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 1024,
- y: 1600,
- scaleX: 8,
- scaleY: 3,
- alpha: 0.9
- });
- // Scale buttons
- var scaleUpX = new Text2('X+', {
- size: 40,
- fill: 0x00FF00,
- fontWeight: 'bold'
- });
- scaleUpX.anchor.set(0.5, 0.5);
- scaleUpX.x = 900;
- scaleUpX.y = 1580;
- scaleUpX.interactive = true;
- scaleUpX.down = function () {
- self.selectedAsset.scaleX += 0.1;
- self.updatePropertiesPanel();
- };
- scalePanel.addChild(scaleUpX);
- var scaleDownX = new Text2('X-', {
- size: 40,
- fill: 0xFF0000,
- fontWeight: 'bold'
- });
- scaleDownX.anchor.set(0.5, 0.5);
- scaleDownX.x = 900;
- scaleDownX.y = 1620;
- scaleDownX.interactive = true;
- scaleDownX.down = function () {
- self.selectedAsset.scaleX = Math.max(0.1, self.selectedAsset.scaleX - 0.1);
- self.updatePropertiesPanel();
- };
- scalePanel.addChild(scaleDownX);
- var scaleUpY = new Text2('Y+', {
- size: 40,
- fill: 0x00FF00,
- fontWeight: 'bold'
- });
- scaleUpY.anchor.set(0.5, 0.5);
- scaleUpY.x = 1148;
- scaleUpY.y = 1580;
- scaleUpY.interactive = true;
- scaleUpY.down = function () {
- self.selectedAsset.scaleY += 0.1;
- self.updatePropertiesPanel();
- };
- scalePanel.addChild(scaleUpY);
- var scaleDownY = new Text2('Y-', {
- size: 40,
- fill: 0xFF0000,
- fontWeight: 'bold'
- });
- scaleDownY.anchor.set(0.5, 0.5);
- scaleDownY.x = 1148;
- scaleDownY.y = 1620;
- scaleDownY.interactive = true;
- scaleDownY.down = function () {
- self.selectedAsset.scaleY = Math.max(0.1, self.selectedAsset.scaleY - 0.1);
- self.updatePropertiesPanel();
- };
- scalePanel.addChild(scaleDownY);
- // Close button
- var closeScaleBtn = new Text2('CLOSE', {
- size: 30,
- fill: 0xFFFFFF,
- fontWeight: 'bold'
- });
- closeScaleBtn.anchor.set(0.5, 0.5);
- closeScaleBtn.x = 1024;
- closeScaleBtn.y = 1650;
- closeScaleBtn.interactive = true;
- closeScaleBtn.down = function () {
- scalePanel.destroy();
- };
- scalePanel.addChild(closeScaleBtn);
- // Auto-close after 10 seconds
- LK.setTimeout(function () {
- if (scalePanel.parent) {
- scalePanel.destroy();
- }
- }, 10000);
- };
- // Delete selected asset
- self.deleteSelectedAsset = function () {
- if (!self.selectedAsset) {
- return;
- }
- // Remove from background elements array
- var index = backgroundElements.indexOf(self.selectedAsset);
- if (index !== -1) {
- backgroundElements.splice(index, 1);
- }
- // Clear animation timer if it's an animated group
- if (self.selectedAsset.animationTimer) {
- LK.clearInterval(self.selectedAsset.animationTimer);
- }
- self.selectedAsset.destroy();
- self.selectedAsset = null;
- self.updatePropertiesPanel();
- self.showMessage('Asset deleted');
- };
- // Move asset layer
- self.moveAssetLayer = function (direction) {
- if (!self.selectedAsset || !self.selectedAsset.parent) {
- return;
- }
- var parent = self.selectedAsset.parent;
- var currentIndex = parent.getChildIndex(self.selectedAsset);
- var newIndex = currentIndex + direction;
- if (newIndex >= 0 && newIndex < parent.children.length) {
- parent.setChildIndex(self.selectedAsset, newIndex);
- self.showMessage('Layer moved ' + (direction > 0 ? 'up' : 'down'));
- }
- };
- // Update properties panel
- self.updatePropertiesPanel = function () {
- if (!self.selectedAsset) {
- self.propertiesText.setText('Select an asset to view properties');
- return;
- }
- var props = 'SELECTED: ' + (self.selectedAsset.assetName || 'Animation Group') + '\n';
- props += 'X: ' + Math.round(self.selectedAsset.x) + '\n';
- props += 'Y: ' + Math.round(self.selectedAsset.y) + '\n';
- props += 'Scale X: ' + self.selectedAsset.scaleX.toFixed(2) + '\n';
- props += 'Scale Y: ' + self.selectedAsset.scaleY.toFixed(2) + '\n';
- props += 'Rotation: ' + (self.selectedAsset.rotation * 180 / Math.PI).toFixed(1) + '°\n';
- props += 'Alpha: ' + self.selectedAsset.alpha.toFixed(2);
- if (self.selectedAsset.animGroup) {
- props += '\nAnimation: ' + self.selectedAsset.animGroup.name;
- props += '\nFrames: ' + self.selectedAsset.animGroup.assets.length;
- }
- self.propertiesText.setText(props);
- };
- // Show temporary message
- self.showMessage = function (message) {
- var msgContainer = self.uiContainer.addChild(new Container());
- var msgBg = msgContainer.attachAsset('expobox', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 1024,
- y: 200,
- scaleX: 6,
- scaleY: 2,
- alpha: 0.9
- });
- var msgText = new Text2(message.toUpperCase(), {
- size: 30,
- fill: 0x00FFFF,
- fontWeight: 'bold'
- });
- msgText.anchor.set(0.5, 0.5);
- msgText.x = 1024;
- msgText.y = 200;
- msgContainer.addChild(msgText);
- tween(msgContainer, {
- alpha: 0
- }, {
- duration: 2000,
- easing: tween.easeOut,
- onFinish: function onFinish() {
- msgContainer.destroy();
- }
- });
- };
- // Show the assets manager
- self.show = function () {
- self.isActive = true;
- // Pause gameplay
- if (bloodmage) {
- bloodmage.velocityX = 0;
- bloodmage.velocityY = 0;
- }
- // Show UI with animation
- tween(self.uiContainer, {
- alpha: 1
- }, {
- duration: 500,
- easing: tween.easeOut
- });
- tween(self.overlay, {
- alpha: 0.95
- }, {
- duration: 500,
- easing: tween.easeOut
- });
- self.refreshAssetsGrid();
- };
- // Hide the assets manager
- self.hide = function () {
- self.isActive = false;
- self.selectedAsset = null;
- self.dragTarget = null;
- tween(self.uiContainer, {
- alpha: 0
- }, {
- duration: 400,
- easing: tween.easeIn,
- onFinish: function onFinish() {
- self.uiContainer.destroy();
- }
- });
- };
- // Setup event handlers
- self.setupEventHandlers = function () {
- // Global key handler would go here if we had keyboard support
- // For now, we'll rely on UI button interactions
- };
- return self;
-});
var BattleUI = Container.expand(function () {
var self = Container.call(this);
var bg = self.attachAsset('battleBg', {
anchorX: 0.5,
@@ -1059,11 +163,9 @@
}
};
self.animationDirection = 1; // 1 for forward, -1 for reverse
self.startBattleIdleAnimation = function () {
- if (!self.hunkIdleFrames || self.hunkIdleFrames.length === 0) {
- return;
- }
+ 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
@@ -1077,15 +179,15 @@
var nextFrame = self.hunkIdleFrames[nextFrameIndex];
tween(currentFrame, {
alpha: 0
}, {
- duration: 180,
+ duration: 150,
easing: tween.easeInOut
});
tween(nextFrame, {
alpha: 1
}, {
- duration: 180,
+ duration: 150,
easing: tween.easeInOut
});
self.currentBattleFrame = nextFrameIndex;
self.battleAnimationTimer = LK.setTimeout(function () {
@@ -1450,17 +552,13 @@
}
};
self.startIdleAnimation = function () {
// ONLY start if truly idle - no other states active
- if (self.isMoving || self.isJumping || self.isFlying || self.currentAnimationState !== 'idle') {
- return;
- }
+ if (self.isMoving || self.isJumping || self.isFlying || self.currentAnimationState !== 'idle') return;
// Clear everything first
self.clearAllAnimations();
// Verify idle frames exist (playeridle to playeridle12)
- if (!self.idleFrames || self.idleFrames.length < 6) {
- return;
- }
+ if (!self.idleFrames || self.idleFrames.length < 6) return;
// Show current idle frame ONLY
self.idleFrames[self.currentIdleFrame].alpha = 1;
// Calculate next frame with ping-pong effect
var nextFrameIndex = self.currentIdleFrame + self.idleAnimationDirection;
@@ -1473,19 +571,19 @@
self.idleAnimationDirection = 1;
}
var currentFrame = self.idleFrames[self.currentIdleFrame];
var nextFrame = self.idleFrames[nextFrameIndex];
- // Smooth cross-fade transition with enhanced easing
+ // Smooth cross-fade transition
tween(currentFrame, {
alpha: 0
}, {
- duration: 150,
+ duration: 120,
easing: tween.easeInOut
});
tween(nextFrame, {
alpha: 1
}, {
- duration: 150,
+ duration: 120,
easing: tween.easeInOut
});
self.currentIdleFrame = nextFrameIndex;
// Continue ONLY if still in idle state
@@ -1508,25 +606,19 @@
}
};
self.walkAnimationDirection = 1; // 1 for forward, -1 for reverse
self.startWalkingAnimation = function () {
- if (!self.isMoving) {
- return;
- }
+ 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
+ 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;
}
@@ -1702,13 +794,9 @@
// Apply movement directly - NO velocity interference
self.x += moveX;
self.y += moveY;
// Update facing direction
- if (moveX > 0) {
- self.facingDirection = -1;
- } else if (moveX < 0) {
- self.facingDirection = 1;
- }
+ if (moveX > 0) self.facingDirection = -1;else if (moveX < 0) self.facingDirection = 1;
}
// If no trackpad input: COMPLETE STILLNESS (no drift at all)
// Start/continue flight animation
if (self.currentAnimationState === 'fly') {
@@ -1866,11 +954,9 @@
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;
- }
+ 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;
@@ -2116,104 +1202,8 @@
originalDestroy.call(self);
};
return self;
});
-var Inventory = Container.expand(function () {
- var self = Container.call(this);
- // Initialize inventory data
- self.items = storage.inventory || {};
- self.maxSlots = 20;
- // Create inventory UI
- self.createInventoryUI = function () {
- var invBg = self.attachAsset('inventory', {
- anchorX: 0.5,
- anchorY: 0.5,
- scaleX: 10,
- scaleY: 12,
- alpha: 0.9
- });
- // Create item slots grid
- self.slots = [];
- for (var row = 0; row < 4; row++) {
- for (var col = 0; col < 5; col++) {
- var slot = self.attachAsset('platshelf', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: (col - 2) * 60,
- y: (row - 1.5) * 60,
- scaleX: 0.8,
- scaleY: 0.8
- });
- slot.interactive = true;
- slot.slotIndex = row * 5 + col;
- self.slots.push(slot);
- }
- }
- self.refreshDisplay();
- };
- self.addItem = function (itemName, quantity) {
- quantity = quantity || 1;
- if (self.items[itemName]) {
- self.items[itemName] += quantity;
- } else {
- self.items[itemName] = quantity;
- }
- storage.inventory = self.items;
- self.refreshDisplay();
- };
- self.removeItem = function (itemName, quantity) {
- quantity = quantity || 1;
- if (self.items[itemName]) {
- self.items[itemName] -= quantity;
- if (self.items[itemName] <= 0) {
- delete self.items[itemName];
- }
- }
- storage.inventory = self.items;
- self.refreshDisplay();
- };
- self.hasItem = function (itemName, quantity) {
- quantity = quantity || 1;
- return self.items[itemName] && self.items[itemName] >= quantity;
- };
- self.refreshDisplay = function () {
- // Clear existing item displays
- for (var i = 0; i < self.slots.length; i++) {
- var slot = self.slots[i];
- // Remove item display if exists
- if (slot.itemDisplay) {
- slot.itemDisplay.destroy();
- slot.itemDisplay = null;
- }
- }
- // Display current items
- var itemNames = Object.keys(self.items);
- for (var i = 0; i < itemNames.length && i < self.slots.length; i++) {
- var itemName = itemNames[i];
- var quantity = self.items[itemName];
- var slot = self.slots[i];
- // Create item display
- slot.itemDisplay = slot.addChild(LK.getAsset(itemName, {
- anchorX: 0.5,
- anchorY: 0.5,
- scaleX: 0.6,
- scaleY: 0.6
- }));
- // Add quantity text if > 1
- if (quantity > 1) {
- var qtyText = new Text2(quantity.toString(), {
- size: 20,
- fill: 0xFFFFFF
- });
- qtyText.anchor.set(1, 1);
- qtyText.x = 20;
- qtyText.y = 20;
- slot.itemDisplay.addChild(qtyText);
- }
- }
- };
- 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'];
@@ -2225,8 +1215,22 @@
// Store platform type for reference
self.platformType = selectedPlatform;
return self;
});
+var Stairs = Container.expand(function () {
+ var self = Container.call(this);
+ // Randomly choose between stairs assets
+ var stairsAsset = Math.random() > 0.5 ? 'Stairs' : 'Stairs2';
+ var stairs = self.attachAsset(stairsAsset, {
+ anchorX: 0.5,
+ anchorY: 1.0
+ });
+ // Store stairs type for reference
+ self.stairsType = stairsAsset;
+ // Make stairs interactive for climbing
+ stairs.interactive = true;
+ return self;
+});
/****
* Initialize Game
****/
@@ -2236,4297 +1240,1078 @@
/****
* Game Code
****/
-function _typeof2(o) {
- "@babel/helpers - typeof";
- return _typeof2 = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
- return typeof o;
- } : function (o) {
- return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
- }, _typeof2(o);
-}
-function _typeof(o) {
- "@babel/helpers - typeof";
- return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
- return typeof o;
- } : function (o) {
- return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
- }, _typeof(o);
-}
-function _toConsumableArray(r) {
- return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread();
-}
-function _nonIterableSpread() {
- throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
-}
-function _unsupportedIterableToArray(r, a) {
- if (r) {
- if ("string" == typeof r) {
- return _arrayLikeToArray(r, a);
- }
- var t = {}.toString.call(r).slice(8, -1);
- return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0;
- }
-}
-function _iterableToArray(r) {
- if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) {
- return Array.from(r);
- }
-}
-function _arrayWithoutHoles(r) {
- if (Array.isArray(r)) {
- return _arrayLikeToArray(r);
- }
-}
-function _arrayLikeToArray(r, a) {
- (null == a || a > r.length) && (a = r.length);
- for (var e = 0, n = Array(a); e < a; e++) {
- n[e] = r[e];
- }
- return n;
-}
game.setBackgroundColor(0x0a0a0a);
-// Core game variables
var bloodmage = null;
var platforms = [];
+var buildings = [];
var hunks = [];
-var thralls = []; // Player's captured beast-men collection
-var crystalGems = []; // Crystallized hunks for summoning
+var clouds = [];
var currentHunk = null;
var battleUI = null;
+// Removed inBattle - using proximity-based battle UI instead
var cameraX = 0;
-var cameraY = 0;
-var worldContainer = game.addChild(new Container());
-var backgroundElements = [];
-var environmentalEffects = [];
-var capturedHunkCount = storage.capturedHunkCount || 0;
-var playerItems = storage.playerItems || 0;
-var brostiaryEntries = storage.brostiaryEntries || 0;
-var generatedChunks = [];
-var currentBiome = 'city';
-var lastBiome = 'city';
-var clouds = [];
-// Initialize clouds array properly
-if (!clouds) {
- clouds = [];
-}
-var buildings = [];
-var brostiary = storage.brostiary || {};
-var unlockedBiomes = storage.unlockedBiomes || 1;
-// ENHANCED BIOME SYSTEM WITH PROPER NAMES AND POSITIONING
-var biomeData = {
- city: {
- name: 'NOCTURNE CITY',
- centerY: 1600,
- backgrounds: ['bg', 'bg2', 'bg3', 'bg4', 'nocturnecitylayout'],
- buildings: ['building', 'building2', 'building3', 'building4', 'statue'],
- neonSigns: ['neonSign', 'neonsign2'],
- doors: ['door', 'door2', 'door3'],
- interiors: ['interior', 'interior2', 'interior3', 'interior4'],
- midground: ['building3', 'neonSign', 'neonsign2', 'cloud1', 'cloud2', 'cloud3'],
- platforms: ['platform', 'platform2', 'platform3', 'platform4'],
- effects: ['cloud1', 'cloud2', 'cloud3'],
- depth: 3,
- layerSpacing: 200
- },
- cosmic: {
- name: 'the Holocosmos',
- centerY: 400,
- // Moved further north
- backgrounds: ['Galaxybg', 'galaxy2', 'galaxy3', 'galaxy4'],
- effects: ['starlight', 'starlight2'],
- platforms: ['cosmicplatform', 'cosmicplatform2'],
- midground: ['galaxy3', 'galaxy4', 'starlight2'],
- depth: 4,
- layerSpacing: 300
- },
- forest: {
- name: 'Simulimina Forest',
- centerY: 1600,
- backgrounds: ['forest2', 'forest3', 'forestbg', 'forestbg2'],
- trees: ['trees', 'trees2', 'trees3', 'trees4'],
- effects: ['foresteffect', 'foresteffect2'],
- platforms: ['mossyplatform', 'mossyplatform2'],
- midground: ['trees3', 'trees4', 'foresteffect'],
- depth: 3,
- layerSpacing: 250
- },
- sea: {
- name: 'the Infinisea',
- centerY: 1600,
- backgrounds: ['sea', 'sea2', 'sea3', 'sea5'],
- effects: ['seaeffect'],
- overlay: ['caveoverlay'],
- platforms: ['platform', 'platform2'],
- midground: ['sea3', 'caveoverlay'],
- depth: 3,
- layerSpacing: 180
- },
- under: {
- name: 'the Underdeep',
- centerY: 2800,
- // Kept in south
- backgrounds: ['underbg', 'underbg2', 'underbg3', 'underbg4', 'cavern', 'cavern2'],
- floors: ['cavefloor', 'cavefloor2'],
- overlay: ['underoverlay', 'underoverlay2'],
- effects: ['undereffect', 'undereffect2'],
- interiors: ['interior5', 'interior6', 'interior7', 'interior8'],
- platforms: ['caveoverlay', 'underoverlay'],
- // Use cave overlay platforms
- midground: ['underoverlay', 'cavern'],
- depth: 4,
- layerSpacing: 160
- }
-};
-// Beast-men data with leather themes
-var beastMenData = {
- 0: {
- // Mushroom Hunk - Leather Daddy
- name: 'SPORE MASTER',
- title: 'Leather Daddy of the Fungi Realm',
- description: 'A POWERFUL MYCELIAL BEING WRAPPED IN STUDDED LEATHER, COMMANDING SPORES WITH HYPNOTIC DOMINANCE',
- resistance: 120,
- attacks: ['LEATHER SPORE BURST', 'DOMINANT MIND MELD', 'FUNGAL HARNESS BIND'],
- dialogue: ['SUBMIT TO MY SPORES, BOY...', 'LEATHER AND FUNGUS... PERFECT COMBINATION', 'YOU\'LL LOVE BEING MY MUSHROOM SLAVE']
- },
- 1: {
- // Cyber Hunk - Tech Leather
- name: 'CYBERNETIC DOM',
- title: 'Digital Leather Master',
- description: 'A CHROME-PLATED BEAST IN ELECTRIC BLUE LEATHER, MERGING TECHNOLOGY WITH BDSM AESTHETICS',
- resistance: 100,
- attacks: ['ELECTRIC SHOCK COLLAR', 'DATA DRAIN WHIP', 'CYBER BONDAGE PROTOCOL'],
- dialogue: ['CONNECTING TO YOUR DESIRES...', 'PREPARE FOR DIGITAL DOMINATION', 'YOUR FIREWALL MEANS NOTHING TO ME']
- },
- 2: {
- // Mega Hunk - Bear Leather
- name: 'ALPHA BEAR',
- title: 'Massive Leather Bear',
- description: 'AN ENORMOUS HAIRY BEAST IN BLACK LEATHER HARNESS, RADIATING PRIMAL MASCULINE ENERGY',
- resistance: 150,
- attacks: ['BEAR HUG SQUEEZE', 'LEATHER PADDLE SLAM', 'DOMINANT GROWL'],
- dialogue: ['COME HERE, CUB...', 'TIME TO SHOW YOU WHO\'S DADDY', 'YOU BELONG IN MY LEATHER DEN']
- },
- 3: {
- // Minotaur - Bull Leather
- name: 'TAURUS MASTER',
- title: 'Bull Leather Warrior',
- description: 'A BULL-HEADED WARRIOR IN STUDDED LEATHER CHAPS, WIELDING ANCIENT POWER WITH MODERN KINK',
- resistance: 130,
- attacks: ['HORNED CHARGE', 'LEATHER LASH WHIP', 'BULL RING CONTROL'],
- dialogue: ['FEEL THE POWER OF THE BULL!', 'MY LEATHER WILL BIND YOUR SOUL', 'SUBMIT TO YOUR TAURUS MASTER']
- }
-};
-function getBiomeForPosition(x, y) {
- // Enhanced biome determination with cosmic north, underground south positioning
- var cityRadius = 1500; // Reduced city radius for better biome separation
- var distanceFromCenter = Math.sqrt(x * x + (y - 1600) * (y - 1600));
- // City center - primary starting area
- if (distanceFromCenter < cityRadius) {
- return 'city';
- }
- // Directional biomes with cosmic assets to the north, underground to the south
- if (y < 600) {
- return 'cosmic';
- } // North - the Holocosmos (cosmic assets appear north of city)
- if (y > 2400) {
- return 'under';
- } // South - the Underdeep (underground themed assets appear south)
- if (x > 2000) {
- return 'forest';
- } // East - Simulimina Forest
- if (x < -2000) {
- return 'sea';
- } // West - the Infinisea
- return 'city'; // Default fallback
-}
-function generateInfiniteWorld(centerX, centerY) {
- var chunkId = Math.floor(centerX / 2500) + '_' + Math.floor(centerY / 1500);
- if (generatedChunks.indexOf(chunkId) !== -1) {
- return;
- }
- generatedChunks.push(chunkId);
- var biome = getBiomeForPosition(centerX, centerY);
- var data = biomeData[biome];
- if (!data) {
- return;
- }
- // Generate atmospheric backgrounds
- generateAtmosphericBackgrounds(centerX, centerY, biome, data);
- // Create traversable platforms
- generateBiomePlatforms(centerX, centerY, biome, data);
- // Add environmental atmosphere
- generateBiomeAtmosphere(centerX, centerY, biome, data);
- // Spawn beast-men encounters (30% chance)
- if (Math.random() < 0.3) {
- spawnBeastMan(centerX, centerY, biome);
- }
- // City-specific shops and doors
- if (biome === 'city' && Math.random() < 0.4) {
- generateCityStructures(centerX, centerY, data);
- }
-}
-function generateCityStructures(centerX, centerY, data) {
- // Generate enhanced city-specific interactive structures
- if (!data) {
- return;
- }
- // Multiple shops with different types and enhanced animations
- var _loop = function _loop() {
- if (Math.random() > 0.2) {
- // Enhanced shop sign floating animation
- var _animateShopSign = function animateShopSign() {
- tween(shopSign, {
- y: centerY - 400,
- rotation: 0.15,
- scaleX: shopSign.scaleX * 1.1,
- scaleY: shopSign.scaleY * 1.1
- }, {
- duration: 2500 + Math.random() * 1500,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- tween(shopSign, {
- y: centerY - 250,
- rotation: -0.15,
- scaleX: shopSign.scaleX / 1.1,
- scaleY: shopSign.scaleY / 1.1
- }, {
- duration: 2500 + Math.random() * 1500,
- easing: tween.easeInOut,
- onFinish: _animateShopSign
- });
- }
- });
- };
- shopAsset = shopIndex === 0 ? 'shop' : 'shop2';
- shop = worldContainer.attachAsset(shopAsset, {
- anchorX: 0.5,
- anchorY: 1.0,
- x: centerX - 1200 + shopIndex * 600,
- y: centerY,
- scaleX: 1.0 + Math.random() * 0.4,
- scaleY: 1.0 + Math.random() * 0.4
- });
- shop.interactive = true;
- shop.shopType = shopIndex;
- shop.down = function () {
- if (this.shopType === 0) {
- enterShop();
- } else {
- // Show different interior for shop2 with enhanced variety
- var interiorOptions = ['interior2', 'interior3', 'interior4', 'interior5', 'interior6'];
- var selectedInterior = interiorOptions[Math.floor(Math.random() * interiorOptions.length)];
- showInterior(selectedInterior);
- }
- };
- backgroundElements.push(shop);
- // Enhanced animated shop sign with glow effects
- shopSign = worldContainer.attachAsset('hidesign', {
- anchorX: 0.5,
- anchorY: 1.0,
- x: centerX - 1200 + shopIndex * 600,
- y: centerY - 300,
- scaleX: 3.0,
- scaleY: 3.0
- });
- shopSign.interactive = true;
- shopSign.shopType = shopIndex;
- shopSign.tint = [0xFF00FF, 0x00FFFF, 0xFFFF00, 0xFF0088][shopIndex % 4];
- shopSign.down = function () {
- if (this.shopType === 0) {
- enterShop();
- } else {
- var interiorOptions = ['interior2', 'interior3', 'interior4', 'interior5', 'interior6'];
- var selectedInterior = interiorOptions[Math.floor(Math.random() * interiorOptions.length)];
- showInterior(selectedInterior);
- }
- };
- _animateShopSign();
- backgroundElements.push(shopSign);
- }
- },
- shopAsset,
- shop,
- shopSign;
- for (var shopIndex = 0; shopIndex < 5; shopIndex++) {
- _loop();
- }
- // Enhanced doors using proper door, door2, door3 assets with interior mapping
- var doorAssetTypes = ['door', 'door2', 'door3'];
- var doorInteriorMap = {
- 'door': ['interior', 'interior2', 'interior3'],
- 'door2': ['interior4', 'interior5', 'interior6'],
- 'door3': ['interior7', 'interior8']
- };
- var _loop3 = function _loop3() {
- if (Math.random() > 0.3) {
- var _animateDoorGlow = function animateDoorGlow() {
- tween(door, {
- tint: 0xAAAAFF,
- scaleX: door.scaleX * 1.05,
- scaleY: door.scaleY * 1.05
- }, {
- duration: 3500 + Math.random() * 2000,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- tween(door, {
- tint: originalTint,
- scaleX: door.scaleX / 1.05,
- scaleY: door.scaleY / 1.05
- }, {
- duration: 3500 + Math.random() * 2000,
- easing: tween.easeInOut,
- onFinish: _animateDoorGlow
- });
- }
- });
- };
- doorAsset = doorAssetTypes[i % doorAssetTypes.length];
- door = worldContainer.attachAsset(doorAsset, {
- anchorX: 0.5,
- anchorY: 1.0,
- x: centerX - 900 + i * 350,
- y: centerY,
- scaleX: 1.0,
- scaleY: 1.0
- });
- door.interactive = true;
- door.doorAssetType = doorAsset;
- door.doorIndex = i;
- door.down = function () {
- // Use proper interior mapping for each door type
- var interiorOptions = doorInteriorMap[this.doorAssetType] || ['interior'];
- var interior = interiorOptions[Math.floor(Math.random() * interiorOptions.length)];
- // Add zoom effect before showing interior
- var zoomOverlay = game.addChild(new Container());
- var zoomDoor = zoomOverlay.attachAsset(this.doorAssetType, {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 1024,
- y: 1366,
- scaleX: 0.1,
- scaleY: 0.1,
- alpha: 0.8
- });
- tween(zoomDoor, {
- scaleX: 8.0,
- scaleY: 8.0,
- alpha: 0.95
- }, {
- duration: 800,
- easing: tween.easeOut,
- onFinish: function onFinish() {
- zoomOverlay.destroy();
- showInterior(interior);
- }
- });
- };
- // Enhanced door glow animation with pulsing
- originalTint = 0xFFFFFF;
- _animateDoorGlow();
- backgroundElements.push(door);
- }
- },
- doorAsset,
- door,
- originalTint;
- for (var i = 0; i < 6; i++) {
- _loop3();
- }
- // Enhanced buildings with better variety, sizing, and animations
- if (data.buildings && data.buildings.length > 0) {
- var _loop4 = function _loop4() {
- buildingAsset = data.buildings[Math.floor(Math.random() * data.buildings.length)];
- building = worldContainer.attachAsset(buildingAsset, {
- anchorX: 0.5,
- anchorY: 1.0,
- x: centerX - 1400 + b * 400,
- y: centerY + 100 + Math.random() * 300,
- scaleX: 1.2 + Math.random() * 0.8,
- scaleY: 1.2 + Math.random() * 0.8
- });
- building.alpha = 0.7 + Math.random() * 0.3;
- building.tint = 0x666666 + Math.floor(Math.random() * 0x666666);
- // Enhanced building sway animation with depth
- swayIntensity = 0.01 + Math.random() * 0.02;
- function buildingSway() {
- tween(building, {
- rotation: swayIntensity,
- y: building.y - 5
- }, {
- duration: 5000 + Math.random() * 3000,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- tween(building, {
- rotation: -swayIntensity,
- y: building.y + 10
- }, {
- duration: 5000 + Math.random() * 3000,
- easing: tween.easeInOut,
- onFinish: buildingSway
- });
- }
- });
- }
- buildingSway();
- backgroundElements.push(building);
- },
- buildingAsset,
- building,
- swayIntensity;
- for (var b = 0; b < 8; b++) {
- _loop4();
- }
- }
- // Add city-specific decorative elements
- var decorativeElements = ['statue', 'crystal', 'artefact', 'crystalheart'];
- var _loop5 = function _loop5() {
- decorAsset = decorativeElements[d % decorativeElements.length];
- decoration = worldContainer.attachAsset(decorAsset, {
- anchorX: 0.5,
- anchorY: 1.0,
- x: centerX - 800 + d * 500,
- y: centerY + Math.random() * 200,
- scaleX: 1.5 + Math.random() * 0.5,
- scaleY: 1.5 + Math.random() * 0.5,
- alpha: 0.8
- });
- decoration.tint = [0xFFFFFF, 0xDDDDFF, 0xFFDDDD, 0xDDFFDD][d % 4];
- // Add gentle floating animation
- floatDistance = 20 + Math.random() * 30;
- function decorFloat() {
- tween(decoration, {
- y: decoration.y - floatDistance
- }, {
- duration: 3000 + Math.random() * 2000,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- tween(decoration, {
- y: decoration.y + floatDistance
- }, {
- duration: 3000 + Math.random() * 2000,
- easing: tween.easeInOut,
- onFinish: decorFloat
- });
- }
- });
- }
- decorFloat();
- backgroundElements.push(decoration);
- },
- decorAsset,
- decoration,
- floatDistance;
- for (var d = 0; d < 4; d++) {
- _loop5();
- }
-}
-function generateAtmosphericBackgrounds(centerX, centerY, biome, data) {
- // Generate multiple layered backgrounds with proper depth and parallax
- var numLayers = Math.min(data.depth || 4, data.backgrounds.length);
- var layerSpacing = data.layerSpacing || 250;
- var _loop6 = function _loop6() {
- bgAsset = data.backgrounds[layer % data.backgrounds.length];
- parallaxFactor = 0.08 + layer * 0.06;
- depthOffset = layer * layerSpacing;
- scaleReduction = layer * 0.15;
- bg = worldContainer.attachAsset(bgAsset, {
- anchorX: 0.5,
- anchorY: 0.5,
- x: centerX + layer * 400,
- y: data.centerY - depthOffset,
- scaleX: 4.0 - scaleReduction,
- scaleY: 4.0 - scaleReduction,
- alpha: 0.95 - layer * 0.12
- });
- bg.parallaxSpeed = parallaxFactor;
- bg.baseX = bg.x;
- bg.baseY = bg.y;
- bg.biome = biome;
- bg.layerDepth = layer;
- // Enhanced biome-specific atmospheric tinting and animations
- if (biome === 'cosmic') {
- var _cosmicPulse = function cosmicPulse() {
- tween(bg, {
- alpha: originalAlpha * 1.3,
- scaleX: bg.scaleX * 1.05,
- scaleY: bg.scaleY * 1.05
- }, {
- duration: 4000 + Math.random() * 3000,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- tween(bg, {
- alpha: originalAlpha,
- scaleX: bg.scaleX / 1.05,
- scaleY: bg.scaleY / 1.05
- }, {
- duration: 4000 + Math.random() * 3000,
- easing: tween.easeInOut,
- onFinish: _cosmicPulse
- });
- }
- });
- };
- bg.tint = 0xDDDDFF; // Cool cosmic blue
- // Add cosmic glow animation with improved timing
- originalAlpha = bg.alpha;
- _cosmicPulse();
- } else if (biome === 'forest') {
- var _forestSway = function forestSway() {
- tween(bg, {
- x: bg.baseX + swayDistance,
- rotation: 0.05
- }, {
- duration: 5000 + Math.random() * 2000,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- tween(bg, {
- x: bg.baseX - swayDistance,
- rotation: -0.05
- }, {
- duration: 5000 + Math.random() * 2000,
- easing: tween.easeInOut,
- onFinish: _forestSway
- });
- }
- });
- };
- bg.tint = 0xCCFFCC; // Mystical forest green
- // Add gentle swaying with improved amplitude
- swayDistance = 30 + layer * 10;
- _forestSway();
- } else if (biome === 'sea') {
- bg.tint = 0xCCEEFF; // Deep ocean blue
- // Add wave motion with enhanced flow
- bg.waveOffset = Math.random() * Math.PI * 2;
- bg.waveSpeed = 0.001 + layer * 0.0005;
- bg.waveAmplitude = 15 + layer * 8;
- } else if (biome === 'under') {
- bg.tint = 0xFFCCCC; // Warm underground glow
- // Add flickering effect with enhanced intensity
- if (Math.random() < 0.4) {
- flickerTimer = LK.setInterval(function () {
- if (bg && !bg.destroyed) {
- var flickerIntensity = 0.6 + Math.random() * 0.3;
- tween(bg, {
- alpha: bg.alpha * flickerIntensity
- }, {
- duration: 150,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- tween(bg, {
- alpha: bg.alpha / flickerIntensity
- }, {
- duration: 150,
- easing: tween.easeInOut
- });
- }
- });
- } else {
- LK.clearInterval(flickerTimer);
- }
- }, 1500 + Math.random() * 2500);
- }
- } else if (biome === 'city') {
- bg.tint = 0xAAAACC; // Urban atmospheric tint
- }
- backgroundElements.push(bg);
- worldContainer.setChildIndex(bg, layer);
- },
- bgAsset,
- parallaxFactor,
- depthOffset,
- scaleReduction,
- bg,
- originalAlpha,
- swayDistance,
- flickerTimer;
- for (var layer = 0; layer < numLayers; layer++) {
- _loop6();
- }
-}
-function generateBiomeMidground(centerX, centerY, biome, biomeData) {
- // Generate environmental animated effects in midground layer - no platforms
- var effectCount = 8 + Math.floor(Math.random() * 4);
- var midgroundEffects = [];
- // Biome-specific environmental effects for midground
- if (biome === 'city') {
- // Clouds drifting and neon blinking in the city - use proper city assets
- midgroundEffects = ['cloud1', 'cloud2', 'cloud3'];
- // Add neon blinking effects
- var _loop7 = function _loop7() {
- neonType = Math.random() > 0.5 ? 'neonSign' : 'neonsign2';
- neon = worldContainer.attachAsset(neonType, {
- anchorX: 0.5,
- anchorY: 0.5,
- x: centerX - 400 + n * 400 + Math.random() * 200,
- y: centerY + (Math.random() - 0.5) * 300,
- scaleX: 0.8 + Math.random() * 0.4,
- scaleY: 0.8 + Math.random() * 0.4
- });
- neon.tint = [0xFF00FF, 0x00FFFF, 0xFFFF00, 0xFF0088][Math.floor(Math.random() * 4)];
- // Animate neon blinking
- function animateNeonBlink() {
- tween(neon, {
- alpha: 0.2
- }, {
- duration: 1000 + Math.random() * 2000,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- tween(neon, {
- alpha: 0.8
- }, {
- duration: 1000 + Math.random() * 2000,
- easing: tween.easeInOut,
- onFinish: animateNeonBlink
- });
- }
- });
- }
- animateNeonBlink();
- environmentalEffects.push(neon);
- },
- neonType,
- neon;
- for (var n = 0; n < 3; n++) {
- _loop7();
- }
- } else if (biome === 'cosmic') {
- // Galaxies swirling in cosmic
- midgroundEffects = ['galaxy3', 'galaxy4', 'starlight', 'starlight2'];
- } else if (biome === 'forest') {
- midgroundEffects = ['foresteffect', 'foresteffect2', 'trees3', 'trees4'];
- } else if (biome === 'sea') {
- midgroundEffects = ['seaeffect', 'caveoverlay'];
- } else if (biome === 'under') {
- midgroundEffects = ['undereffect', 'undereffect2', 'underoverlay'];
- }
- if (midgroundEffects.length === 0) {
- return;
- }
- for (var i = 0; i < effectCount; i++) {
- var effectAsset = midgroundEffects[Math.floor(Math.random() * midgroundEffects.length)];
- var effect = worldContainer.attachAsset(effectAsset, {
- anchorX: 0.5,
- anchorY: 0.5,
- x: centerX - 800 + i * 400 + Math.random() * 200,
- y: centerY + (Math.random() - 0.5) * 300,
- scaleX: 1.0 + Math.random() * 0.8,
- scaleY: 1.0 + Math.random() * 0.8,
- alpha: 0.7 + Math.random() * 0.3
- });
- effect.parallaxSpeed = 0.15;
- effect.baseX = effect.x;
- effect.baseY = effect.y;
- effect.biome = biome;
- effect.driftSpeed = 0.5 + Math.random() * 1.0;
- // Enhanced biome-specific animations
- if (biome === 'city') {
- // Drifting clouds and blinking neon
- if (effectAsset.indexOf('cloud') !== -1) {
- effect.driftSpeed = 1.2 + Math.random() * 0.8;
- // Add enhanced cloud drift animation with proper size variation
- effect.driftSpeed = 1.2 + Math.random() * 0.8;
- effect.scaleX = 0.8 + Math.random() * 0.6;
- effect.scaleY = 0.8 + Math.random() * 0.6;
- effect.alpha = 0.6 + Math.random() * 0.3;
- var cloudDrift = function cloudDrift() {
- effect.x += effect.driftSpeed;
- // Wrap around when off screen with proper spacing
- if (effect.x > centerX + 2500) {
- effect.x = centerX - 2500;
- effect.y = centerY + (Math.random() - 0.5) * 400;
- }
- };
- // Start cloud movement
- LK.setInterval(cloudDrift, 50);
- // Add to clouds array for proper tracking
- clouds.push(effect);
- } else if (effectAsset.indexOf('neon') !== -1) {
- effect.tint = [0xFF00FF, 0x00FFFF, 0xFFFF00, 0xFF0088][Math.floor(Math.random() * 4)];
- // Enhanced neon blinking animation
- var animateNeonBlink = function animateNeonBlink() {
- tween(effect, {
- alpha: 0.2
- }, {
- duration: 1000 + Math.random() * 2000,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- tween(effect, {
- alpha: 0.8
- }, {
- duration: 1000 + Math.random() * 2000,
- easing: tween.easeInOut,
- onFinish: animateNeonBlink
- });
- }
- });
- };
- animateNeonBlink();
- }
- } else if (biome === 'cosmic') {
- // Enhanced swirling galaxies
- effect.rotationSpeed = (Math.random() - 0.5) * 0.02;
- effect.tint = 0xDDDDFF;
- var cosmicSwirl = function cosmicSwirl() {
- // Add continuous rotation
- effect.rotation += effect.rotationSpeed;
- tween(effect, {
- scaleX: effect.scaleX * 1.2,
- scaleY: effect.scaleY * 1.2,
- alpha: effect.alpha * 1.3
- }, {
- duration: 3000 + Math.random() * 2000,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- tween(effect, {
- scaleX: effect.scaleX / 1.2,
- scaleY: effect.scaleY / 1.2,
- alpha: effect.alpha / 1.3
- }, {
- duration: 3000 + Math.random() * 2000,
- easing: tween.easeInOut,
- onFinish: cosmicSwirl
- });
- }
- });
- };
- cosmicSwirl();
- } else if (biome === 'forest') {
- // Forest swaying and blinking effects
- effect.tint = 0xCCFFCC;
- if (effectAsset.indexOf('effect') !== -1) {
- // Enhanced blinking forest effects
- effect.blinkTimer = Math.random() * 3000;
- var forestBlink = function forestBlink() {
- if (Date.now() % effect.blinkTimer < 100) {
- effect.alpha = 0.3;
- } else {
- effect.alpha = 0.7;
- }
- };
- LK.setInterval(forestBlink, 100);
- }
- } else if (biome === 'under') {
- // Enhanced underground floating effects
- effect.tint = 0xFFCCCC;
- effect.floatAmplitude = 30 + Math.random() * 60;
- effect.floatSpeed = 0.01 + Math.random() * 0.02;
- var underFloat = function underFloat() {
- effect.y += Math.sin(Date.now() * effect.floatSpeed) * 0.5;
- };
- LK.setInterval(underFloat, 50);
- }
- environmentalEffects.push(effect);
- backgroundElements.push(effect);
- // Clamp index to valid range
- var targetIndex = Math.min(8 + i, worldContainer.children.length - 1);
- if (targetIndex >= 0 && targetIndex < worldContainer.children.length) {
- worldContainer.setChildIndex(effect, targetIndex);
- }
- }
-}
-function generateBiomePlatforms(centerX, centerY, biome, biomeDat) {
- var platformCount = 10 + Math.floor(Math.random() * 6);
- var currentBiomeData = biomeDat || biomeData[biome] || {};
- var platformAssets = currentBiomeData.platforms || ['platform', 'platform2', 'platform3'];
- var _loop2 = function _loop2() {
- platform = new Platform();
- platform.x = centerX - 1200 + i * 280;
- // Enhanced biome-specific platform layouts
- if (biome === 'cosmic') {
- platform.y = centerY - 300 - i * 60; // Steeper ascending
- } else if (biome === 'under') {
- platform.y = centerY + 150 + i * 40; // Steeper descending
- } else if (biome === 'sea') {
- platform.y = centerY + Math.sin(i * 0.7) * 150; // Enhanced wave pattern
- } else if (biome === 'forest') {
- platform.y = centerY - i % 4 * 120; // Enhanced tree levels
- } else {
- platform.y = centerY - i % 5 * 90; // Enhanced city building levels
- }
- platform.biome = biome;
- platform.originalX = platform.x;
- platform.originalY = platform.y;
- platforms.push(platform);
- worldContainer.addChild(platform);
- // Enhanced visual platform representation with proper biome-specific assets
- if (platformAssets.length > 0) {
- var platAsset;
- if (biome === 'under') {
- // Use cave overlay platforms in underground sections as specified
- platAsset = ['caveoverlay', 'underoverlay'][Math.floor(Math.random() * 2)];
- } else if (biome === 'forest') {
- // Use forest platforms in forest section as specified
- platAsset = ['mossyplatform', 'mossyplatform2'][Math.floor(Math.random() * 2)];
- } else {
- // Use standard platforms for other biomes
- platAsset = platformAssets[Math.floor(Math.random() * platformAssets.length)];
- }
- platVisual = worldContainer.attachAsset(platAsset, {
- anchorX: 0.5,
- anchorY: 0.5,
- x: platform.x,
- y: platform.y - 20,
- scaleX: 1.4,
- scaleY: 1.4,
- alpha: 0.95
- });
- platform.visual = platVisual;
- // Place platforms on consistent even planes rather than random heights
- var planeHeight = 200; // Height between planes
- var planesPerBiome = Math.floor((platform.y - (centerY - 400)) / planeHeight);
- var targetPlane = Math.max(0, Math.min(3, planesPerBiome)); // 4 consistent planes
- platform.y = centerY - 400 + targetPlane * planeHeight;
- // Prevent platform overlap with proper spacing
- var minDistance = 350; // Increased minimum distance
- var validPosition = false;
- var attempts = 0;
- while (!validPosition && attempts < 10) {
- validPosition = true;
- for (var p = 0; p < platforms.length - 1; p++) {
- var existingPlatform = platforms[p];
- var distance = Math.sqrt(Math.pow(platform.x - existingPlatform.x, 2) + Math.pow(platform.y - existingPlatform.y, 2));
- if (distance < minDistance) {
- validPosition = false;
- // Move platform to next available position on same plane
- platform.x += minDistance;
- break;
- }
- }
- attempts++;
- }
- // Improved platform animations - approximately 1 in 3 platforms move, full screen movement
- animationType = Math.random();
- if (animationType < 0.33) {
- var _animateVertical = function animateVertical() {
- tween(platform, {
- y: platform.originalY + 600 // Full screen vertical movement
- }, {
- duration: 4000,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- tween(platform, {
- y: platform.originalY - 600 // Back and forth across screen
- }, {
- duration: 4000,
- easing: tween.easeInOut,
- onFinish: _animateVertical
- });
- }
- });
- if (platVisual) {
- tween(platVisual, {
- y: platVisual.y + 600
- }, {
- duration: 4000,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- tween(platVisual, {
- y: platVisual.y - 1200 // Match platform movement
- }, {
- duration: 4000,
- easing: tween.easeInOut
- });
- }
- });
- }
- };
- LK.setTimeout(_animateVertical, i * 500);
- } else if (animationType < 0.66) {
- var _animateHorizontal = function animateHorizontal() {
- tween(platform, {
- x: platform.originalX + 1024 // Full screen horizontal movement
- }, {
- duration: 5000,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- tween(platform, {
- x: platform.originalX - 1024 // Back and forth across screen
- }, {
- duration: 5000,
- easing: tween.easeInOut,
- onFinish: _animateHorizontal
- });
- }
- });
- if (platVisual) {
- tween(platVisual, {
- x: platVisual.x + 1024
- }, {
- duration: 5000,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- tween(platVisual, {
- x: platVisual.x - 2048 // Match platform movement
- }, {
- duration: 5000,
- easing: tween.easeInOut
- });
- }
- });
- }
- };
- LK.setTimeout(_animateHorizontal, i * 600);
- } else {
- // Stationary platform - no movement for 1 in 3 platforms
- platform.circularOffset = 0;
- platform.circularRadius = 0;
- platform.circularSpeed = 0;
- }
- // Enhanced visual effects for platforms
- if (platVisual) {
- backgroundElements.push(platVisual);
- // Add glow effect for cosmic platforms
- if (biome === 'cosmic') {
- var _cosmicGlow = function cosmicGlow() {
- tween(platVisual, {
- alpha: originalAlpha * 1.3,
- tint: 0xEEEEFF
- }, {
- duration: 3000 + Math.random() * 2000,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- tween(platVisual, {
- alpha: originalAlpha,
- tint: 0xDDDDFF
- }, {
- duration: 3000 + Math.random() * 2000,
- easing: tween.easeInOut,
- onFinish: _cosmicGlow
- });
- }
- });
- };
- platVisual.tint = 0xDDDDFF;
- var originalAlpha = platVisual.alpha;
- _cosmicGlow();
- }
- // Ensure platVisual is added as child before setting index
- worldContainer.addChild(platVisual);
- // Ensure platVisual is added as child before setting index
- if (platVisual && !platVisual.parent) {
- worldContainer.addChild(platVisual);
- }
- // Safe index calculation to prevent out of bounds error
- var targetIndex = 25 + i;
- var maxIndex = worldContainer.children.length - 1;
- var safeIndex = Math.max(0, Math.min(targetIndex, maxIndex));
- // Only set index if platVisual exists, is a child, and index is valid
- if (platVisual && platVisual.parent === worldContainer && worldContainer.children.length > 0) {
- var currentIndex = worldContainer.getChildIndex(platVisual);
- if (safeIndex >= 0 && safeIndex < worldContainer.children.length && safeIndex !== currentIndex) {
- worldContainer.setChildIndex(platVisual, safeIndex);
- }
- }
- }
- }
- },
- platform,
- platAsset,
- platVisual,
- animationType,
- moveDistance,
- moveDuration,
- moveDistance,
- moveDuration,
- radius,
- speed,
- targetIndex;
- for (var i = 0; i < platformCount; i++) {
- _loop2();
- }
-}
-function generateBiomeAtmosphere(centerX, centerY, biome, data) {
- // Generate atmospheric effects for the current biome
- if (!data || !data.effects) {
- return;
- }
- var effectCount = 3 + Math.floor(Math.random() * 3);
- for (var i = 0; i < effectCount; i++) {
- var effectAsset = data.effects[Math.floor(Math.random() * data.effects.length)];
- var effect = worldContainer.attachAsset(effectAsset, {
- anchorX: 0.5,
- anchorY: 0.5,
- x: centerX - 600 + Math.random() * 1200,
- y: centerY - 400 + Math.random() * 800,
- scaleX: 0.6 + Math.random() * 0.8,
- scaleY: 0.6 + Math.random() * 0.8,
- alpha: 0.5 + Math.random() * 0.4
- });
- effect.biome = biome;
- effect.driftSpeed = 0.3 + Math.random() * 0.7;
- // Biome-specific animations
- if (biome === 'city') {
- // Clouds drift left to right
- clouds.push(effect);
- } else if (biome === 'cosmic') {
- // Cosmic elements pulse
- effect.rotationSpeed = (Math.random() - 0.5) * 0.02;
- } else if (biome === 'forest') {
- // Forest effects blink
- effect.blinkTimer = Math.random() * 3000;
- }
- environmentalEffects.push(effect);
- worldContainer.setChildIndex(effect, 8 + i);
- }
-}
-function generateBiomeEffects(centerX, centerY, biome, biomeData) {
- if (!biomeData.effects) {
- return;
- }
- var effectCount = 3 + Math.floor(Math.random() * 3);
- for (var i = 0; i < effectCount; i++) {
- var effectAsset = biomeData.effects[Math.floor(Math.random() * biomeData.effects.length)];
- var effect = worldContainer.attachAsset(effectAsset, {
- anchorX: 0.5,
- anchorY: 0.5,
- x: centerX - 600 + Math.random() * 1200,
- y: centerY - 400 + Math.random() * 800,
- scaleX: 0.6 + Math.random() * 0.8,
- scaleY: 0.6 + Math.random() * 0.8,
- alpha: 0.5 + Math.random() * 0.4
- });
- effect.biome = biome;
- effect.driftSpeed = 0.3 + Math.random() * 0.7;
- // Biome-specific animations
- if (biome === 'city') {
- // Clouds drift left to right
- clouds.push(effect);
- } else if (biome === 'cosmic') {
- // Cosmic elements pulse
- effect.rotationSpeed = (Math.random() - 0.5) * 0.02;
- } else if (biome === 'forest') {
- // Forest effects blink
- effect.blinkTimer = Math.random() * 3000;
- }
- environmentalEffects.push(effect);
- worldContainer.setChildIndex(effect, 8 + i);
- }
-}
-function spawnBeastMan(centerX, centerY, biome) {
- // Create a powerful beast-man with leather aesthetic
- var beastMan = new Hunk();
- beastMan.x = centerX + (Math.random() - 0.5) * 600;
- beastMan.y = centerY - 100;
- beastMan.biome = biome;
- // Enhanced stats for beast-men
- var beastData = beastMenData[beastMan.hunkType];
- if (beastData) {
- beastMan.resistance = beastData.resistance;
- beastMan.maxResistance = beastData.resistance;
- beastMan.name = beastData.name;
- beastMan.isLeatherBeast = true;
- }
- hunks.push(beastMan);
- worldContainer.addChild(beastMan);
- // Add leather-themed entrance effect
- var leatherGlow = worldContainer.attachAsset('effect2', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: beastMan.x,
- y: beastMan.y - 100,
- scaleX: 2.0,
- scaleY: 2.0,
- alpha: 0.8
- });
- // Animate entrance with leather dominance theme
- tween(leatherGlow, {
- alpha: 0,
- scaleX: 4.0,
- scaleY: 4.0,
- tint: 0x660000 // Deep leather red
- }, {
- duration: 1500,
- easing: tween.easeOut,
- onFinish: function onFinish() {
- leatherGlow.destroy();
- }
- });
- // Ensure proper layering
- var targetIndex = Math.max(15, worldContainer.children.length - 2);
- if (targetIndex < worldContainer.children.length) {
- worldContainer.setChildIndex(beastMan, targetIndex);
- }
-}
-function generateCityInteractables(centerX, centerY, biomeData) {
- // Shop
- if (Math.random() > 0.7) {
- // Animate shop sign
- var _animateSign = function animateSign() {
- tween(shopSign, {
- y: centerY - 350
- }, {
- duration: 2000,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- tween(shopSign, {
- y: centerY - 300
- }, {
- duration: 2000,
- easing: tween.easeInOut,
- onFinish: _animateSign
- });
- }
- });
- };
- var shop = worldContainer.attachAsset('shop', {
- anchorX: 0.5,
- anchorY: 1.0,
- x: centerX,
- y: centerY,
- scaleX: 0.8,
- scaleY: 0.8
- });
- shop.interactive = true;
- shop.down = function () {
- enterShop();
- };
- var shopSign = worldContainer.attachAsset('hidesign', {
- anchorX: 0.5,
- anchorY: 1.0,
- x: centerX,
- y: centerY - 300,
- scaleX: 2.5,
- scaleY: 2.5
- });
- shopSign.interactive = true;
- shopSign.down = function () {
- enterShop();
- };
- _animateSign();
- backgroundElements.push(shop);
- backgroundElements.push(shopSign);
- }
- // Doors
- if (biomeData.doors && Math.random() > 0.5) {
- for (var i = 0; i < 2; i++) {
- var doorAsset = biomeData.doors[Math.floor(Math.random() * biomeData.doors.length)];
- var door = worldContainer.attachAsset(doorAsset, {
- anchorX: 0.5,
- anchorY: 1.0,
- x: centerX - 400 + i * 800,
- y: centerY,
- scaleX: 1.0,
- scaleY: 1.0
- });
- door.interactive = true;
- door.down = function () {
- var interiorAssets = biomeData.interiors || ['interior'];
- var interior = interiorAssets[Math.floor(Math.random() * interiorAssets.length)];
- showInterior(interior);
- };
- backgroundElements.push(door);
- worldContainer.setChildIndex(door, 12 + i);
- }
- }
-}
-// Initialize the world - only generate city assets at start
-function initializeWorld() {
- // Generate only Nocturne City assets in proper layers as specified
- // Layer 4: bg bg2 bg3 bg4 nocturnecitylayout
- var cityBg1 = worldContainer.attachAsset('bg', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 1024,
- y: 1366,
- scaleX: 3.0,
- scaleY: 3.0
- });
- var cityBg2 = worldContainer.attachAsset('bg2', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 1024,
- y: 1366,
- scaleX: 3.0,
- scaleY: 3.0
- });
- var cityBg3 = worldContainer.attachAsset('bg3', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 1024,
- y: 1366,
- scaleX: 3.0,
- scaleY: 3.0
- });
- var cityBg4 = worldContainer.attachAsset('bg4', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 1024,
- y: 1366,
- scaleX: 3.0,
- scaleY: 3.0
- });
- var cityLayout = worldContainer.attachAsset('nocturnecitylayout', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 1024,
- y: 1366,
- scaleX: 2.5,
- scaleY: 2.5
- });
- backgroundElements.push(cityBg1, cityBg2, cityBg3, cityBg4, cityLayout);
- worldContainer.setChildIndex(cityBg1, 0);
- worldContainer.setChildIndex(cityBg2, 1);
- worldContainer.setChildIndex(cityBg3, 2);
- worldContainer.setChildIndex(cityBg4, 3);
- worldContainer.setChildIndex(cityLayout, 4);
- // Layer 3: building building2 Building2 building4 statue
- var building1 = worldContainer.attachAsset('building', {
- anchorX: 0.5,
- anchorY: 1.0,
- x: 700,
- y: 1800,
- scaleX: 1.2,
- scaleY: 1.2
- });
- var building2 = worldContainer.attachAsset('building2', {
- anchorX: 0.5,
- anchorY: 1.0,
- x: 1400,
- y: 1800,
- scaleX: 1.0,
- scaleY: 1.0
- });
- var Building2 = worldContainer.attachAsset('Building2', {
- anchorX: 0.5,
- anchorY: 1.0,
- x: 2100,
- y: 1800,
- scaleX: 0.8,
- scaleY: 0.8
- });
- var building4 = worldContainer.attachAsset('building4', {
- anchorX: 0.5,
- anchorY: 1.0,
- x: 2800,
- y: 1800,
- scaleX: 1.1,
- scaleY: 1.1
- });
- var statue = worldContainer.attachAsset('statue', {
- anchorX: 0.5,
- anchorY: 1.0,
- x: 2000,
- y: 1800,
- scaleX: 1.0,
- scaleY: 1.0
- });
- backgroundElements.push(building1, building2, Building2, building4, statue);
- worldContainer.setChildIndex(building1, 5);
- worldContainer.setChildIndex(building2, 6);
- worldContainer.setChildIndex(Building2, 7);
- worldContainer.setChildIndex(building4, 8);
- worldContainer.setChildIndex(statue, 9);
- // Layer 2: building3 neonSign neonsign2 cloud1-cloud3
- var building3 = worldContainer.attachAsset('building3', {
- anchorX: 0.5,
- anchorY: 1.0,
- x: 1000,
- y: 1600,
- scaleX: 0.9,
- scaleY: 0.9
- });
- var neonSign1 = worldContainer.attachAsset('neonSign', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 1200,
- y: 1300,
- scaleX: 1.0,
- scaleY: 1.0
- });
- var neonsign2 = worldContainer.attachAsset('neonsign2', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 2500,
- y: 1300,
- scaleX: 1.0,
- scaleY: 1.0
- });
- // Add neon blinking animation
- neonSign1.tint = 0xFF00FF;
- neonsign2.tint = 0x00FFFF;
- function animateNeon(neon) {
- tween(neon, {
- alpha: 0.3
- }, {
- duration: 1500,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- tween(neon, {
- alpha: 0.9
- }, {
- duration: 1500,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- animateNeon(neon);
- }
- });
- }
- });
- }
- animateNeon(neonSign1);
- animateNeon(neonsign2);
- // Generate plenty of clouds drifting left to right in different sizes
- var cloudTypes = ['cloud1', 'cloud2', 'cloud3'];
- for (var c = 0; c < 10; c++) {
- var cloudType = cloudTypes[Math.floor(Math.random() * cloudTypes.length)];
- var cloud = worldContainer.attachAsset(cloudType, {
- anchorX: 0.5,
- anchorY: 0.5,
- x: Math.random() * 4000,
- y: 800 + Math.random() * 400,
- scaleX: 0.6 + Math.random() * 0.8,
- scaleY: 0.6 + Math.random() * 0.8
- });
- cloud.driftSpeed = 0.8 + Math.random() * 0.6;
- cloud.alpha = 0.5 + Math.random() * 0.4;
- clouds.push(cloud);
- }
- backgroundElements.push(building3, neonSign1, neonsign2);
- backgroundElements = backgroundElements.concat(clouds);
- worldContainer.setChildIndex(building3, 10);
- worldContainer.setChildIndex(neonSign1, 11);
- worldContainer.setChildIndex(neonsign2, 12);
- // Set cloud indices
- for (var c = 0; c < clouds.length; c++) {
- worldContainer.setChildIndex(clouds[c], 13 + c);
- }
- // Layer 1: platform platform2 platform3 platform4 stairs stairs2 door-door3
- // Create platforms on consistent even planes
- var platformLayout = [{
- x: 600,
- y: 1800
- },
- // Starting platform - platform2
- {
- x: 900,
- y: 1650
- }, {
- x: 1200,
- y: 1500
- }, {
- x: 1500,
- y: 1350
- }, {
- x: 1800,
- y: 1200
- }, {
- x: 2100,
- y: 1200
- }, {
- x: 2400,
- y: 1200
- }, {
- x: 2700,
- y: 1350
- }, {
- x: 3000,
- y: 1500
- }];
- var platformAssets = ['platform', 'platform2', 'platform3', 'platform4'];
- for (var p = 0; p < platformLayout.length; p++) {
- var platform = new Platform();
- platform.x = platformLayout[p].x;
- platform.y = platformLayout[p].y;
- platforms.push(platform);
- worldContainer.addChild(platform);
- // Use platform2 for the starting platform specifically
- var platAsset = p === 0 ? 'platform2' : platformAssets[p % platformAssets.length];
- var platVisual = worldContainer.attachAsset(platAsset, {
- anchorX: 0.5,
- anchorY: 0.5,
- x: platform.x,
- y: platform.y - 20,
- scaleX: 1.2,
- scaleY: 1.2
- });
- backgroundElements.push(platVisual);
- }
- // Add stairs between platforms
- var stairs1 = worldContainer.attachAsset('stairs', {
- anchorX: 0.5,
- anchorY: 1.0,
- x: 1050,
- y: 1725,
- scaleX: 0.8,
- scaleY: 0.8
- });
- var stairs2 = worldContainer.attachAsset('stairs2', {
- anchorX: 0.5,
- anchorY: 1.0,
- x: 2250,
- y: 1275,
- scaleX: 0.9,
- scaleY: 0.9
- });
- backgroundElements.push(stairs1, stairs2);
- worldContainer.setChildIndex(stairs1, 35);
- worldContainer.setChildIndex(stairs2, 36);
- // Add doors paired with platforms as specified
- var door = worldContainer.attachAsset('door', {
- anchorX: 0.5,
- anchorY: 1.0,
- x: 1800,
- y: 1180,
- scaleX: 0.8,
- scaleY: 0.8
- });
- door.interactive = true;
- door.down = function () {
- enterShop();
- };
- var door2 = worldContainer.attachAsset('door2', {
- anchorX: 0.5,
- anchorY: 1.0,
- x: 2700,
- y: 1330,
- scaleX: 1.0,
- scaleY: 1.0
- });
- door2.interactive = true;
- door2.down = function () {
- var interiorTypes = ['interior2', 'interior3', 'interior4'];
- var selectedInterior = interiorTypes[Math.floor(Math.random() * interiorTypes.length)];
- showInterior(selectedInterior);
- };
- var door3 = worldContainer.attachAsset('door3', {
- anchorX: 0.5,
- anchorY: 1.0,
- x: 900,
- y: 1630,
- scaleX: 1.2,
- scaleY: 1.2
- });
- door3.interactive = true;
- door3.down = function () {
- var interiorTypes = ['interior5', 'interior6', 'interior7', 'interior8'];
- var selectedInterior = interiorTypes[Math.floor(Math.random() * interiorTypes.length)];
- showInterior(selectedInterior);
- };
- backgroundElements.push(door, door2, door3);
- worldContainer.setChildIndex(door, 37);
- worldContainer.setChildIndex(door2, 38);
- worldContainer.setChildIndex(door3, 39);
- // Store door references
- doorAsset = door;
- window.door2Asset = door2;
- window.door3Asset = door3;
- // Initialize player on platform2 (the starting platform) with stable idle animation
- bloodmage = new Bloodmage();
- bloodmage.x = 600; // Position on platform2 (first platform in layout)
- bloodmage.y = 1780; // Standing properly on platform2
- // CRITICAL: Force stable ground state to prevent falling animation glitch
- bloodmage.grounded = true;
- bloodmage.velocityY = 0;
- bloodmage.velocityX = 0;
- bloodmage.isMoving = false;
- bloodmage.isJumping = false;
- bloodmage.isFlying = false;
- bloodmage.currentAnimationState = 'idle';
- bloodmage.currentIdleFrame = 0;
- bloodmage.idleAnimationDirection = 1;
- // Add to world container
- worldContainer.addChild(bloodmage);
- worldContainer.setChildIndex(bloodmage, worldContainer.children.length - 1);
- // FIXED: Immediately show idle state to prevent falling animation
- if (bloodmage.idleFrames && bloodmage.idleFrames.length > 0) {
- // Clear all animation states first
- bloodmage.clearAllAnimations();
- // Force idle frame visible immediately
- bloodmage.idleFrames[0].alpha = 1;
- // Start proper idle animation loop with delay
- LK.setTimeout(function () {
- if (bloodmage.grounded && !bloodmage.isMoving && !bloodmage.isJumping && !bloodmage.isFlying) {
- bloodmage.currentAnimationState = 'idle';
- bloodmage.startIdleAnimation();
- }
- }, 100);
- }
-}
-// Initialize the world
-initializeWorld();
-// Remove duplicate worldSystem definition - keep the original one with isInTransitionZone method
-// Game state variables
+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;
+var doubleTapThreshold = 300; // milliseconds for double tap detection
var isFlying = false;
-var jumpButtonHeld = false;
+var flyFrames = [];
+var currentFlyFrame = 0;
+var flyAnimationTimer = 0;
+var flyAnimationDirection = 1;
var jumpHoldStartTime = 0;
-var spellProjectiles = [];
-var isCasting = false;
-// Enhanced Inventory and Thrall Management System
-var inventorySystem = {
- items: storage.inventory || {},
- thralls: storage.thrallStorage || {},
- maxSlots: 50,
- maxThralls: 20,
- addItem: function addItem(itemName, quantity) {
- quantity = quantity || 1;
- this.items[itemName] = (this.items[itemName] || 0) + quantity;
- storage.inventory = this.items;
- this.showItemNotification(itemName, quantity);
- },
- removeItem: function removeItem(itemName, quantity) {
- quantity = quantity || 1;
- if (this.items[itemName]) {
- this.items[itemName] -= quantity;
- if (this.items[itemName] <= 0) {
- delete this.items[itemName];
- }
- storage.inventory = this.items;
- return true;
- }
- return false;
- },
- hasItem: function hasItem(itemName, quantity) {
- quantity = quantity || 1;
- return this.items[itemName] && this.items[itemName] >= quantity;
- },
- addThrall: function addThrall(thrallData) {
- var thrallId = 'thrall_' + Object.keys(this.thralls).length;
- this.thralls[thrallId] = {
- type: thrallData.hunkType,
- name: thrallData.name || 'Unnamed Thrall',
- level: 1,
- loyalty: 100,
- captureDate: Date.now(),
- stats: thrallData.stats || {
- hp: 100,
- power: 25,
- defense: 20,
- speed: 15
- }
- };
- storage.thrallStorage = this.thralls;
- this.showThrallNotification(thrallData.name || 'New Thrall');
- },
- showItemNotification: function showItemNotification(itemName, quantity) {
- var notification = game.addChild(new Container());
- var notifBg = notification.attachAsset('expobox', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 1024,
- y: 200,
- scaleX: 8,
- scaleY: 2,
- alpha: 0
- });
- var itemText = new Text2('ACQUIRED: ' + itemName.toUpperCase() + ' x' + quantity, {
- size: 60,
- fill: 0x00FF00,
- fontWeight: 'bold'
- });
- itemText.anchor.set(0.5, 0.5);
- itemText.x = 1024;
- itemText.y = 200;
- notification.addChild(itemText);
- tween(notification, {
- alpha: 1
- }, {
- duration: 500,
- easing: tween.easeOut,
- onFinish: function onFinish() {
- LK.setTimeout(function () {
- tween(notification, {
- alpha: 0,
- y: 100
- }, {
- duration: 300,
- easing: tween.easeIn,
- onFinish: function onFinish() {
- notification.destroy();
- }
- });
- }, 2000);
- }
- });
- },
- showThrallNotification: function showThrallNotification(thrallName) {
- var notification = game.addChild(new Container());
- var notifBg = notification.attachAsset('expobox', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 1024,
- y: 250,
- scaleX: 10,
- scaleY: 2.5,
- alpha: 0
- });
- var thrallText = new Text2('THRALL CAPTURED: ' + thrallName.toUpperCase(), {
- size: 70,
- fill: 0xFF00FF,
- fontWeight: 'bold'
- });
- thrallText.anchor.set(0.5, 0.5);
- thrallText.x = 1024;
- thrallText.y = 250;
- notification.addChild(thrallText);
- tween(notification, {
- alpha: 1
- }, {
- duration: 600,
- easing: tween.easeOut,
- onFinish: function onFinish() {
- LK.setTimeout(function () {
- tween(notification, {
- alpha: 0,
- y: 150
- }, {
- duration: 400,
- easing: tween.easeIn,
- onFinish: function onFinish() {
- notification.destroy();
- }
- });
- }, 3000);
- }
- });
- }
-};
-// Simple exposition system
-function showExposition(title, text) {
- var expoOverlay = game.addChild(new Container());
- var expoBg = expoOverlay.attachAsset('expobox', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 1024,
- y: 1366,
- scaleX: 15,
- scaleY: 8,
- alpha: 0.9
- });
- var titleText = new Text2(title, {
- size: 80,
- fill: 0xFFFFFF,
- fontWeight: 'bold'
- });
- titleText.anchor.set(0.5, 0.5);
- titleText.x = 1024;
- titleText.y = 1200;
- expoOverlay.addChild(titleText);
- var bodyText = new Text2(text, {
- size: 50,
- fill: 0xCCCCCC,
- wordWrap: true,
- wordWrapWidth: 1200
- });
- bodyText.anchor.set(0.5, 0.5);
- bodyText.x = 1024;
- bodyText.y = 1400;
- expoOverlay.addChild(bodyText);
- // Auto close after 5 seconds
- LK.setTimeout(function () {
- if (expoOverlay.parent) {
- expoOverlay.destroy();
- }
- }, 5000);
-}
-// Dialogue System for NPCs and Hunks
-var dialogueSystem = {
- showDialogue: function showDialogue(speakerName, text, responses, speakerAsset) {
- var dialogueOverlay = game.addChild(new Container());
- // Dialogue background
- var dialogueBg = dialogueOverlay.attachAsset('dialoguebox', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 1024,
- y: 2000,
- scaleX: 12,
- scaleY: 8,
- alpha: 0
- });
- // Speaker portrait if provided
- if (speakerAsset) {
- var portrait = dialogueOverlay.attachAsset(speakerAsset, {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 400,
- y: 2000,
- scaleX: 1.5,
- scaleY: 1.5,
- alpha: 0
- });
- }
- // Speaker name
- var nameText = new Text2(speakerName, {
- size: 80,
- fill: 0xFF1493,
- fontWeight: 'bold'
- });
- nameText.anchor.set(0.5, 0);
- nameText.x = 1024;
- nameText.y = 1700;
- dialogueOverlay.addChild(nameText);
- // Dialogue text
- var dialogueText = new Text2(text, {
- size: 56,
- fill: 0xFFFFFF,
- wordWrap: true,
- wordWrapWidth: 800
- });
- dialogueText.anchor.set(0.5, 0.5);
- dialogueText.x = 1024;
- dialogueText.y = 2000;
- dialogueOverlay.addChild(dialogueText);
- // Animate in
- tween(dialogueOverlay, {
- alpha: 1
- }, {
- duration: 600,
- easing: tween.easeOut
- });
- // Response buttons if provided
- if (responses && responses.length > 0) {
- for (var i = 0; i < responses.length; i++) {
- var response = responses[i];
- var responseBtn = new Text2(response.text, {
- size: 50,
- fill: 0x00FFFF,
- fontWeight: 'bold'
- });
- responseBtn.anchor.set(0.5, 0.5);
- responseBtn.x = 1024;
- responseBtn.y = 2200 + i * 80;
- responseBtn.interactive = true;
- responseBtn.response = response;
- responseBtn.down = function () {
- if (this.response.action) {
- this.response.action();
- }
- tween(dialogueOverlay, {
- alpha: 0
- }, {
- duration: 400,
- easing: tween.easeIn,
- onFinish: function onFinish() {
- dialogueOverlay.destroy();
- }
- });
- };
- dialogueOverlay.addChild(responseBtn);
- }
- } else {
- // Auto-close after time if no responses
- LK.setTimeout(function () {
- if (dialogueOverlay && dialogueOverlay.parent) {
- tween(dialogueOverlay, {
- alpha: 0
- }, {
- duration: 400,
- easing: tween.easeIn,
- onFinish: function onFinish() {
- dialogueOverlay.destroy();
- }
- });
- }
- }, 4000);
- }
- return dialogueOverlay;
- }
-};
+var jumpButtonHeld = false;
+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());
-// Infinite world generation system
-var lastGeneratedX = 0;
-var chunkSize = 2000;
-var generatedChunks = [];
-function generateWorldChunk(centerX, centerY) {
- var chunkKey = Math.floor(centerX / chunkSize) + '_' + Math.floor(centerY / chunkSize);
- if (generatedChunks.indexOf(chunkKey) !== -1) {
- return;
- }
- generatedChunks.push(chunkKey);
- // Determine biome based on position
- var biome = getBiomeFromPosition(centerX, centerY);
- // Generate background layers
- generateBiomeBackgrounds(centerX, centerY, biome);
- // Generate platforms
- generateBiomePlatforms(centerX, centerY, biome);
- // Generate characters
- if (Math.random() > 0.7) {
- generateBiomeCharacter(centerX, centerY, biome);
- }
- // Generate environmental effects
- generateBiomeEffects(centerX, centerY, biome);
- // Generate interactive elements
- generateBiomeInteractables(centerX, centerY, biome);
-}
-function getBiomeFromPosition(x, y) {
- // City is center (0,0 to 2000,2000)
- if (Math.abs(x) < 2000 && y > 1000 && y < 3000) {
- return 'city';
- }
- // Cosmic is north (y < 1000)
- if (y < 1000) {
- return 'cosmic';
- }
- // Under is south (y > 3000)
- if (y > 3000) {
- return 'under';
- }
- // Forest is east (x > 2000)
- if (x > 2000) {
- return 'forest';
- }
- // Sea is west (x < -2000)
- if (x < -2000) {
- return 'sea';
- }
- // Default to city
- return 'city';
-}
-function generateTransitionChunk(startX, regions) {
- // Create blended content between two regions
- var primaryRegion = regions[0];
- var secondaryRegion = regions[1];
- var primaryData = worldAssetMap[primaryRegion];
- var secondaryData = worldAssetMap[secondaryRegion];
- // Mix backgrounds from both regions
- var bgAsset = Math.random() > 0.5 ? primaryData.backgrounds[0] : secondaryData.backgrounds[0];
- var transitionBg = worldContainer.attachAsset(bgAsset, {
- anchorX: 0.5,
- anchorY: 0.5,
- x: startX + 1200,
- y: (primaryData.gameY + secondaryData.gameY) / 2,
- scaleX: 2.5,
- scaleY: 2.5,
- alpha: 0.6
- });
- // Blend ambient colors
- var blendedColor = blendColors(primaryData.ambientColor, secondaryData.ambientColor, 0.5);
- transitionBg.tint = blendedColor;
- backgroundElements.push(transitionBg);
- worldContainer.setChildIndex(transitionBg, 1);
- // Generate mixed platforms
- for (var i = 0; i < 4; i++) {
- var platform = new Platform();
- platform.x = startX + i * 600 + 200;
- platform.y = (primaryData.gameY + secondaryData.gameY) / 2 + (Math.random() - 0.5) * 200;
- platforms.push(platform);
- worldContainer.addChild(platform);
- }
-}
-function generateRegionBackgrounds(startX, regionName, regionData) {
- // Generate layered backgrounds with proper depth
- var backgroundLayers = Math.min(4, regionData.backgrounds.length);
- for (var layer = 0; layer < backgroundLayers; layer++) {
- var bgAsset = regionData.backgrounds[layer];
- var depth = layer / backgroundLayers;
+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: 0.5,
- x: startX + 1200 + layer * 200,
- y: regionData.gameY + layer * 100,
- scaleX: 3.0 - depth * 0.5,
- scaleY: 3.0 - depth * 0.5,
- alpha: 0.8 - depth * 0.2
+ anchorY: 1.0,
+ x: startX + 2048,
+ y: 2732,
+ scaleX: 2.0 - layer * 0.3,
+ scaleY: 2.0 - layer * 0.3
});
- bg.region = regionName;
- bg.parallaxSpeed = regionData.parallaxSpeed * (1 + depth);
- bg.baseX = bg.x;
- bg.baseY = bg.y;
- bg.tint = regionData.ambientColor;
+ bg.alpha = 0.3 + layer * 0.2;
backgroundElements.push(bg);
worldContainer.setChildIndex(bg, layer);
}
-}
-function generateRegionMidground(startX, regionName, regionData) {
- // Generate midground structures
- var midgroundCount = 6 + Math.floor(Math.random() * 4);
- for (var i = 0; i < midgroundCount; i++) {
- var midgroundAsset = regionData.midground[Math.floor(Math.random() * regionData.midground.length)];
- var midground = worldContainer.attachAsset(midgroundAsset, {
+ // Add statue as decoration
+ if (Math.random() > 0.7) {
+ var statue = worldContainer.attachAsset('statue', {
anchorX: 0.5,
anchorY: 1.0,
- x: startX + i * 400 + Math.random() * 200,
- y: regionData.gameY + (Math.random() - 0.5) * 300,
- scaleX: 1.0 + Math.random() * 0.8,
- scaleY: 1.0 + Math.random() * 0.8,
- alpha: 0.7 + Math.random() * 0.3
- });
- midground.region = regionName;
- midground.parallaxSpeed = regionData.parallaxSpeed * 1.3;
- midground.baseX = midground.x;
- midground.baseY = midground.y;
- backgroundElements.push(midground);
- worldContainer.setChildIndex(midground, 8 + i);
- }
-}
-function generateRegionPlatforms(startX, regionName, regionData) {
- // Generate region-specific platforms
- var platformCount = 10;
- var platformAssets = regionData.platforms || ['platform', 'platform2'];
- for (var i = 0; i < platformCount; i++) {
- var platform = new Platform();
- platform.x = startX + i * 300 - 200;
- // Region-specific platform layouts
- if (regionName === 'cosmic') {
- platform.y = regionData.gameY - 200 - i * 40;
- // Add cosmic platform visuals
- var cosmicAsset = platformAssets[Math.floor(Math.random() * platformAssets.length)];
- var cosmicVisual = worldContainer.attachAsset(cosmicAsset, {
- anchorX: 0.5,
- anchorY: 0.5,
- x: platform.x,
- y: platform.y - 20,
- scaleX: 1.2,
- scaleY: 1.2,
- alpha: 0.9
- });
- backgroundElements.push(cosmicVisual);
- } else if (regionName === 'forest') {
- platform.y = regionData.gameY - i % 4 * 100;
- // Add mossy platform visuals
- var mossyAsset = platformAssets[Math.floor(Math.random() * platformAssets.length)];
- var mossyVisual = worldContainer.attachAsset(mossyAsset, {
- anchorX: 0.5,
- anchorY: 0.5,
- x: platform.x,
- y: platform.y - 20,
- scaleX: 1.2,
- scaleY: 1.2,
- alpha: 0.9
- });
- backgroundElements.push(mossyVisual);
- } else if (regionName === 'under') {
- platform.y = regionData.gameY + 100 + i * 30;
- // Add cave floor visuals if available
- if (regionData.floors) {
- var floorAsset = regionData.floors[Math.floor(Math.random() * regionData.floors.length)];
- var floorVisual = worldContainer.attachAsset(floorAsset, {
- anchorX: 0.5,
- anchorY: 0.5,
- x: platform.x,
- y: platform.y - 10,
- scaleX: 1.1,
- scaleY: 1.1
- });
- backgroundElements.push(floorVisual);
- }
- } else if (regionName === 'sea') {
- platform.y = regionData.gameY + Math.sin(i * 0.5) * 150;
- } else {
- platform.y = regionData.gameY - 50 - i % 5 * 80;
- }
- platform.region = regionName;
- platforms.push(platform);
- worldContainer.addChild(platform);
- }
-}
-function generateRegionCharacters(startX, regionName, regionData) {
- // Generate region-appropriate characters
- if (Math.random() > 0.6) {
- var hunk = new Hunk();
- hunk.x = startX + 800 + Math.random() * 800;
- hunk.y = regionData.centerY || 1600;
- hunks.push(hunk);
- worldContainer.addChild(hunk);
- // Add character-specific effects
- if (regionName === 'cosmic') {
- var cosmicGlow = worldContainer.attachAsset('starlight', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: hunk.x,
- y: hunk.y - 100,
- alpha: 0.7
- });
- tween(cosmicGlow, {
- alpha: 0.3
- }, {
- duration: 2000,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- tween(cosmicGlow, {
- alpha: 0.7
- }, {
- duration: 2000,
- easing: tween.easeInOut
- });
- }
- });
- environmentalEffects.push(cosmicGlow);
- }
- }
-}
-function generateRegionInteractables(startX, regionName, regionData) {
- // Generate shops, doors, and interactive elements
- if (regionName === 'city' && Math.random() > 0.4) {
- // Generate shop
- if (regionData.shops) {
- var shopAsset = regionData.shops[0]; // 'shop'
- var shop = worldContainer.attachAsset(shopAsset, {
- anchorX: 0.5,
- anchorY: 1.0,
- x: startX + 1200,
- y: regionData.gameY,
- scaleX: 0.8,
- scaleY: 0.8
- });
- shop.interactive = true;
- shop.down = function () {
- enterShop();
- };
- backgroundElements.push(shop);
- // Add shop sign
- var shopSign = worldContainer.attachAsset('hidesign', {
- anchorX: 0.5,
- anchorY: 1.0,
- x: startX + 1200,
- y: regionData.gameY - 300,
- scaleX: 2.5,
- scaleY: 2.5
- });
- shopSign.interactive = true;
- shopSign.down = function () {
- enterShop();
- };
- backgroundElements.push(shopSign);
- }
- // Generate doors
- if (regionData.doors) {
- for (var d = 0; d < Math.min(2, regionData.doors.length); d++) {
- var doorAsset = regionData.doors[d];
- var door = worldContainer.attachAsset(doorAsset, {
- anchorX: 0.5,
- anchorY: 1.0,
- x: startX + 600 + d * 1200,
- y: regionData.gameY,
- scaleX: 1.0,
- scaleY: 1.0
- });
- door.interactive = true;
- door.down = function () {
- var interiorAsset = regionData.interiors[Math.floor(Math.random() * regionData.interiors.length)];
- showInterior(interiorAsset);
- };
- backgroundElements.push(door);
- }
- }
- }
-}
-function generateRegionEffects(startX, regionName, regionData) {
- // Generate environmental effects
- if (regionData.effects && regionData.effects.length > 0) {
- var effectCount = 4 + Math.floor(Math.random() * 3);
- for (var e = 0; e < effectCount; e++) {
- var effectAsset = regionData.effects[Math.floor(Math.random() * regionData.effects.length)];
- var effect = worldContainer.attachAsset(effectAsset, {
- anchorX: 0.5,
- anchorY: 0.5,
- x: startX + e * 500 + Math.random() * 400,
- y: regionData.gameY + (Math.random() - 0.5) * 400,
- scaleX: 0.6 + Math.random() * 0.8,
- scaleY: 0.6 + Math.random() * 0.8,
- alpha: 0.5 + Math.random() * 0.4
- });
- effect.region = regionName;
- effect.driftSpeed = 0.2 + Math.random() * 0.6;
- effect.animationType = regionName;
- // Region-specific animations
- if (regionName === 'cosmic') {
- effect.tint = 0xDDDDFF;
- effect.rotationSpeed = (Math.random() - 0.5) * 0.02;
- // Add cosmic pulsing
- tween(effect, {
- scaleX: effect.scaleX * 1.3,
- scaleY: effect.scaleY * 1.3,
- alpha: effect.alpha * 1.4
- }, {
- duration: 3000 + Math.random() * 2000,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- tween(effect, {
- scaleX: effect.scaleX / 1.3,
- scaleY: effect.scaleY / 1.3,
- alpha: effect.alpha / 1.4
- }, {
- duration: 3000 + Math.random() * 2000,
- easing: tween.easeInOut
- });
- }
- });
- } else if (regionName === 'forest') {
- effect.blinkTimer = Math.random() * 4000;
- } else if (regionName === 'under') {
- effect.floatAmplitude = 30 + Math.random() * 60;
- effect.floatSpeed = 0.01 + Math.random() * 0.02;
- }
- environmentalEffects.push(effect);
- worldContainer.setChildIndex(effect, 12 + e);
- }
- }
-}
-function generateRegionCollectibles(startX, regionName, regionData) {
- // Generate collectible items
- if (regionData.collectibles && regionData.collectibles.length > 0 && Math.random() > 0.7) {
- var collectibleAsset = regionData.collectibles[Math.floor(Math.random() * regionData.collectibles.length)];
- var collectible = worldContainer.attachAsset(collectibleAsset, {
- anchorX: 0.5,
- anchorY: 0.5,
- x: startX + 400 + Math.random() * 1600,
- y: regionData.gameY - 100 + Math.random() * 200,
+ x: startX + Math.random() * 2000,
+ y: 2000,
scaleX: 0.8,
- scaleY: 0.8,
- alpha: 0.9
+ scaleY: 0.8
});
- collectible.interactive = true;
- collectible.collectibleType = collectibleAsset;
- collectible.down = function () {
- if (bloodmage && Math.abs(bloodmage.x - collectible.x) < 200) {
- // Add to inventory
- if (!window.playerInventory) {
- window.playerInventory = new Inventory();
- }
- window.playerInventory.addItem(collectible.collectibleType, 1);
- // Visual feedback
- tween(collectible, {
- alpha: 0,
- scaleX: 2.0,
- scaleY: 2.0,
- y: collectible.y - 100
- }, {
- duration: 800,
- easing: tween.easeOut,
- onFinish: function onFinish() {
- collectible.destroy();
- }
- });
- LK.getSound('capture').play();
- }
- };
- // Floating animation
- var originalY = collectible.y;
- tween(collectible, {
- y: originalY - 20
- }, {
- duration: 1500,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- tween(collectible, {
- y: originalY + 20
- }, {
- duration: 1500,
- easing: tween.easeInOut
- });
- }
- });
- backgroundElements.push(collectible);
+ statue.tint = 0x666666;
+ backgroundElements.push(statue);
+ // Ensure statue stays behind platforms
+ var statueIndex = worldContainer.getChildIndex(statue);
+ worldContainer.setChildIndex(statue, Math.max(0, statueIndex - 10));
}
-}
-function onRegionTransition(newRegion) {
- // Handle region transition events
- var regionData = worldAssetMap[newRegion];
- if (!regionData) {
- return;
+ // 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));
}
- // Update music if different
- if (regionData.music && regionData.music !== worldSystem.currentMusic) {
- LK.playMusic(regionData.music, {
- fade: {
- start: 0.5,
- end: 1,
- duration: 2000
- }
- });
- worldSystem.currentMusic = regionData.music;
- }
- // Visual transition effect
- LK.effects.flashScreen(regionData.ambientColor, 1000, 0.3);
- // Update unlock progress
- if (storage.unlockedAreas.indexOf(newRegion) === -1) {
- storage.unlockedAreas.push(newRegion);
- }
- // Region-specific events
- if (newRegion === 'cosmic') {
- // Cosmic region unlocked message
- showRegionMessage('COSMIC REALM DISCOVERED', 'THE STARS WELCOME YOU...');
- } else if (newRegion === 'forest') {
- showRegionMessage('ANCIENT FOREST ENTERED', 'NATURE\'S SECRETS AWAIT...');
- } else if (newRegion === 'sea') {
- showRegionMessage('OCEANIC DEPTHS REACHED', 'DIVE INTO THE UNKNOWN...');
- } else if (newRegion === 'under') {
- showRegionMessage('UNDERWORLD ACCESSED', 'DARKNESS EMBRACES YOU...');
- }
-}
-function showRegionMessage(title, subtitle) {
- var messageContainer = game.addChild(new Container());
- var titleText = new Text2(title, {
- size: 80,
- fill: 0xFFFFFF,
- fontWeight: 'bold'
- });
- titleText.anchor.set(0.5, 0.5);
- titleText.x = 1024;
- titleText.y = 1200;
- titleText.alpha = 0;
- messageContainer.addChild(titleText);
- var subtitleText = new Text2(subtitle, {
- size: 50,
- fill: 0xCCCCCC
- });
- subtitleText.anchor.set(0.5, 0.5);
- subtitleText.x = 1024;
- subtitleText.y = 1300;
- subtitleText.alpha = 0;
- messageContainer.addChild(subtitleText);
- // Animate in
- tween(titleText, {
- alpha: 1
- }, {
- duration: 1000,
- easing: tween.easeOut
- });
- tween(subtitleText, {
- alpha: 1
- }, {
- duration: 1200,
- easing: tween.easeOut
- });
- // Animate out after delay
- LK.setTimeout(function () {
- tween(messageContainer, {
- alpha: 0
- }, {
- duration: 800,
- easing: tween.easeIn,
- onFinish: function onFinish() {
- messageContainer.destroy();
- }
- });
- }, 4000);
-}
-function blendColors(color1, color2, ratio) {
- var r1 = color1 >> 16 & 0xFF;
- var g1 = color1 >> 8 & 0xFF;
- var b1 = color1 & 0xFF;
- var r2 = color2 >> 16 & 0xFF;
- var g2 = color2 >> 8 & 0xFF;
- var b2 = color2 & 0xFF;
- var r = Math.floor(r1 + (r2 - r1) * ratio);
- var g = Math.floor(g1 + (g2 - g1) * ratio);
- var b = Math.floor(b1 + (b2 - b1) * ratio);
- return r << 16 | g << 8 | b;
-}
-function generateWorldChunkBackgrounds(startX, regionName, regionData) {
- if (!regionData || !regionData.backgrounds) {
- return;
- }
- // Generate multiple background layers for better coverage in all directions
- for (var layer = 0; layer < 3; layer++) {
- var bgAsset = regionData.backgrounds[layer % regionData.backgrounds.length];
- var bgY = regionData.gameY || 1500;
- // Create backgrounds extending in all directions
- for (var bgIndex = 0; bgIndex < 2; bgIndex++) {
- var bg = worldContainer.attachAsset(bgAsset, {
- anchorX: 0.5,
- anchorY: 0.5,
- x: startX + bgIndex * 1200 + 600,
- y: bgY + layer * 400 - 200,
- // Extend vertically
- scaleX: 3.0 + layer * 0.5,
- scaleY: 3.0 + layer * 0.5
- });
- bg.alpha = 0.6 - layer * 0.1;
- bg.region = regionName;
- bg.parallaxSpeed = (regionData.parallaxSpeed || 0.1) * (1 + layer * 0.2);
- bg.baseX = bg.x;
- bg.baseY = bg.y;
- // Region-specific styling
- if (regionName === 'cosmic') {
- bg.tint = 0xDDDDFF;
- } else if (regionName === 'forest') {
- bg.tint = 0xCCFFCC;
- } else if (regionName === 'under') {
- bg.tint = 0xFFCCCC;
- } else if (regionName === 'sea') {
- bg.tint = 0xCCEEFF;
- }
- backgroundElements.push(bg);
- worldContainer.setChildIndex(bg, layer * 2 + bgIndex);
- }
- }
-}
-function generateWorldChunkMidground(startX, regionName, regionData) {
- if (!regionData || !regionData.midground) {
- return;
- }
- // Generate more midground elements covering all directions
+ // Generate lower clouds (beneath platforms)
for (var i = 0; i < 6; i++) {
- var midgroundAsset = regionData.midground[Math.floor(Math.random() * regionData.midground.length)];
- var midground = worldContainer.attachAsset(midgroundAsset, {
+ var cloudAssets = ['cloud1', 'cloud2', 'cloud3'];
+ var cloudType = cloudAssets[Math.floor(Math.random() * cloudAssets.length)];
+ var cloud = worldContainer.attachAsset(cloudType, {
anchorX: 0.5,
- anchorY: 1.0,
- x: startX - 200 + i * 500,
- y: (regionData.gameY || 1800) + (i % 3 - 1) * 200,
- // Vary vertically
- scaleX: 1.0 + Math.random() * 0.8,
- scaleY: 1.0 + Math.random() * 0.8
+ anchorY: 0.5,
+ x: startX + Math.random() * 3000,
+ y: 2100 + Math.random() * 400 // Lower clouds
});
- midground.alpha = 0.7 + Math.random() * 0.2;
- midground.region = regionName;
- midground.parallaxSpeed = (regionData.parallaxSpeed || 0.1) * 1.3;
- midground.baseX = midground.x;
- midground.baseY = midground.y;
- backgroundElements.push(midground);
- worldContainer.setChildIndex(midground, 5 + i);
+ // Vary cloud sizes for depth
+ var cloudScale = 0.5 + Math.random() * 1.0;
+ cloud.scale.x = cloudScale;
+ cloud.scale.y = cloudScale;
+ // Make clouds more visible with better opacity
+ cloud.alpha = 0.6 + 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 additional midground elements for vertical coverage
- for (var v = 0; v < 4; v++) {
- var verticalAsset = regionData.midground[Math.floor(Math.random() * regionData.midground.length)];
- var verticalMid = worldContainer.attachAsset(verticalAsset, {
- anchorX: 0.5,
- anchorY: 1.0,
- x: startX + 600 + v * 700,
- y: (regionData.gameY || 1800) + (v % 2 === 0 ? -300 : 300),
- // Alternate up/down
- scaleX: 1.1 + Math.random() * 0.5,
- scaleY: 1.1 + Math.random() * 0.5
- });
- verticalMid.alpha = 0.6 + Math.random() * 0.3;
- verticalMid.region = regionName;
- verticalMid.parallaxSpeed = (regionData.parallaxSpeed || 0.1) * 1.1;
- verticalMid.baseX = verticalMid.x;
- verticalMid.baseY = verticalMid.y;
- backgroundElements.push(verticalMid);
- worldContainer.setChildIndex(verticalMid, 8 + v);
- }
- // Generate cloud effects that drift left to right in front of background assets
- var cloudAssets = ['cloud1', 'cloud2', 'cloud3'];
- for (var c = 0; c < 5; c++) {
+ // 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 - 400 + c * 600 + Math.random() * 400,
- y: 1000 + Math.random() * 800 // Extended vertical range
+ x: startX + Math.random() * 3000,
+ y: 800 + Math.random() * 600 // Upper clouds among buildings
});
- var cloudScale = 0.7 + Math.random() * 0.8;
+ // Make upper clouds larger and more translucent
+ var cloudScale = 0.8 + Math.random() * 1.5;
cloud.scale.x = cloudScale;
cloud.scale.y = cloudScale;
- cloud.alpha = 0.5 + Math.random() * 0.4;
- cloud.driftSpeed = 1.0 + Math.random() * 1.0;
- cloud.region = regionName;
+ // 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);
- backgroundElements.push(cloud);
- worldContainer.setChildIndex(cloud, Math.max(15, worldContainer.children.length - Math.max(hunks.length, 3))); // Higher layer for visibility
+ // Ensure clouds stay behind platforms but in front of backgrounds
+ var cloudIndex = worldContainer.getChildIndex(cloud);
+ worldContainer.setChildIndex(cloud, Math.max(4, cloudIndex - 5));
}
-}
-function generateWorldChunkPlatforms(startX, regionName) {
- // Generate more platforms in all directions (up, down, left, right)
- var platformCount = 12; // Increased for better coverage
- var regionData = biomeData[regionName];
- var baseY = regionData ? regionData.centerY : 1500;
- // Main horizontal platforms
- for (var i = 0; i < platformCount; i++) {
+ // 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 - 600 + i * 250; // Start further left, tighter spacing
- // Region-specific platform layouts extending in all directions
- if (regionName === 'cosmic') {
- platform.y = baseY - 400 - i * 40; // Extend higher up
- // Create cosmic platform visual overlay
- var cosmicAsset = Math.random() > 0.5 ? 'cosmicplatform' : 'cosmicplatform2';
- var cosmicVisual = worldContainer.attachAsset(cosmicAsset, {
- anchorX: 0.5,
- anchorY: 0.5,
- x: platform.x,
- y: platform.y - 20,
- scaleX: 1.2,
- scaleY: 1.2
- });
- cosmicVisual.alpha = 0.9;
- backgroundElements.push(cosmicVisual);
- worldContainer.setChildIndex(cosmicVisual, 15 + i);
- } else if (regionName === 'under') {
- platform.y = baseY + 200 + i * 60; // Extend deeper down
- // Use cave overlay platforms for underground sections
- var caveAsset = Math.random() > 0.5 ? 'caveoverlay' : 'underoverlay';
- var caveVisual = worldContainer.attachAsset(caveAsset, {
- anchorX: 0.5,
- anchorY: 0.5,
- x: platform.x,
- y: platform.y - 30,
- scaleX: 1.2,
- scaleY: 1.2
- });
- caveVisual.alpha = 0.9;
- backgroundElements.push(caveVisual);
- worldContainer.setChildIndex(caveVisual, 15 + i);
- } else if (regionName === 'forest') {
- platform.y = baseY - i % 4 * 100; // More varied heights
- // Use forest platforms for forest biome
- var forestAsset = Math.random() > 0.5 ? 'mossyplatform' : 'mossyplatform2';
- var forestVisual = worldContainer.attachAsset(forestAsset, {
- anchorX: 0.5,
- anchorY: 0.5,
- x: platform.x,
- y: platform.y - 20,
- scaleX: 1.2,
- scaleY: 1.2
- });
- forestVisual.alpha = 0.9;
- backgroundElements.push(forestVisual);
- worldContainer.setChildIndex(forestVisual, 15 + i);
- } else if (regionName === 'sea') {
- platform.y = baseY + Math.sin(i * 0.5) * 120; // Larger wave pattern
- } else {
- platform.y = baseY - 50 - i % 5 * 80; // City range with more variation
- }
- // Mark platform with region for future cleanup
- platform.region = regionName;
+ platform.x = startX + 300 + i * 500;
+ platform.y = 1600 - i % 3 * 200;
platforms.push(platform);
worldContainer.addChild(platform);
- }
- // Add vertical platform networks extending up and down
- for (var v = 0; v < 6; v++) {
- var verticalPlatform = new Platform();
- verticalPlatform.x = startX + 400 + v * 400;
- if (regionName === 'cosmic') {
- // Extend high up for cosmic exploration
- verticalPlatform.y = baseY - 600 - v * 120;
- // Add cosmic visual
- var cosmicAsset = Math.random() > 0.5 ? 'cosmicplatform' : 'cosmicplatform2';
- var cosmicVertical = worldContainer.attachAsset(cosmicAsset, {
- anchorX: 0.5,
- anchorY: 0.5,
- x: verticalPlatform.x,
- y: verticalPlatform.y - 20,
- scaleX: 1.1,
- scaleY: 1.1
- });
- cosmicVertical.alpha = 0.85;
- backgroundElements.push(cosmicVertical);
- worldContainer.setChildIndex(cosmicVertical, 16 + v);
- } else if (regionName === 'under') {
- // Extend deep down for under exploration
- verticalPlatform.y = baseY + 300 + v * 100;
- } else if (regionName === 'forest') {
- // Forest canopy levels
- verticalPlatform.y = baseY - 200 - v * 80;
- var mossyAsset = Math.random() > 0.5 ? 'mossyplatform' : 'mossyplatform2';
- var mossyVertical = worldContainer.attachAsset(mossyAsset, {
- anchorX: 0.5,
- anchorY: 0.5,
- x: verticalPlatform.x,
- y: verticalPlatform.y - 20,
- scaleX: 1.1,
- scaleY: 1.1
- });
- mossyVertical.alpha = 0.85;
- backgroundElements.push(mossyVertical);
- worldContainer.setChildIndex(mossyVertical, 16 + v);
- } else {
- verticalPlatform.y = baseY - 150 + v % 3 * 100;
+ // Add hunks on some platforms - avoid door positions
+ if (i % 2 === 1 && Math.random() > 0.3) {
+ var hunk = new Hunk();
+ // Offset hunk position to avoid doors
+ hunk.x = platform.x + (Math.random() > 0.5 ? 150 : -150);
+ hunk.y = platform.y - 20;
+ hunks.push(hunk);
+ worldContainer.addChild(hunk);
}
- verticalPlatform.region = regionName;
- platforms.push(verticalPlatform);
- worldContainer.addChild(verticalPlatform);
}
- // Add connecting platforms for endless continuation in all directions
- for (var j = 0; j < 8; j++) {
- var connectPlatform = new Platform();
- connectPlatform.x = startX + 2400 + j * 300; // Extended range
- connectPlatform.y = baseY + Math.sin(j * 0.4) * 200; // Larger varied heights
- connectPlatform.region = regionName;
- platforms.push(connectPlatform);
- worldContainer.addChild(connectPlatform);
- }
- // Generate shop and doors for city region
- if (regionName === 'city' && Math.random() > 0.6) {
- // Add main shop
- var shop = worldContainer.attachAsset('shop', {
- anchorX: 0.5,
- anchorY: 1.0,
- x: startX + 1400,
- y: 1500,
- scaleX: 0.8,
- scaleY: 0.8
- });
- shop.interactive = true;
- shop.down = function () {
- enterShop();
- };
- backgroundElements.push(shop);
- // Add floating shop sign
- var shopSign = worldContainer.attachAsset('hidesign', {
- anchorX: 0.5,
- anchorY: 1.0,
- x: startX + 1400,
- y: 1200,
- scaleX: 2.5,
- scaleY: 2.5
- });
- shopSign.interactive = true;
- shopSign.down = function () {
- enterShop();
- };
- backgroundElements.push(shopSign);
- // Add door2 and door3
- var door2 = worldContainer.attachAsset('door2', {
- anchorX: 0.5,
- anchorY: 1.0,
- x: startX + 2000,
- y: 1400,
- scaleX: 1.0,
- scaleY: 1.0
- });
- door2.interactive = true;
- door2.down = function () {
- var interiorTypes = ['interior2', 'interior3', 'interior4'];
- var selectedInterior = interiorTypes[Math.floor(Math.random() * interiorTypes.length)];
- showInterior(selectedInterior);
- };
- backgroundElements.push(door2);
- var door3 = worldContainer.attachAsset('door3', {
- anchorX: 0.5,
- anchorY: 1.0,
- x: startX + 800,
- y: 1400,
- scaleX: 1.2,
- scaleY: 1.2
- });
- door3.interactive = true;
- door3.down = function () {
- var interiorTypes = ['interior5', 'interior6', 'interior7', 'interior8'];
- var selectedInterior = interiorTypes[Math.floor(Math.random() * interiorTypes.length)];
- showInterior(selectedInterior);
- };
- backgroundElements.push(door3);
- }
-}
-function generateRegionCharacter(startX, regionName) {
- var hunk = new Hunk();
- hunk.x = startX + 1000 + Math.random() * 400;
- // Use region data for proper character positioning
- var regionData = worldAssetMapping[regionName];
- var baseY = regionData ? regionData.centerY : 1400;
- if (regionName === 'cosmic') {
- hunk.y = baseY + 200;
- } else if (regionName === 'under') {
- hunk.y = baseY - 300;
- } else {
- hunk.y = baseY - 100;
- }
- hunks.push(hunk);
- worldContainer.addChild(hunk);
-}
-// Removed complex generation functions - using clean biome system instead
-function generateInfiniteStructures(centerX, centerY, assets) {
- // Generate midground structures in expanding spiral
- var structureCount = 15;
- var zone = infiniteWorld.getZone(centerX, centerY);
- for (var i = 0; i < structureCount; i++) {
- var angle = i / structureCount * Math.PI * 2;
- var radius = 400 + i * 150;
- var posX = centerX + Math.cos(angle) * radius;
- var posY = centerY + Math.sin(angle) * radius * 0.3;
- var midgroundAsset = assets.midground[Math.floor(Math.random() * assets.midground.length)];
- var scale = 1.2 + Math.random() * 1.8;
- var structure = worldContainer.attachAsset(midgroundAsset, {
- anchorX: 0.5,
- anchorY: 1.0,
- x: posX,
- y: posY,
- scaleX: scale,
- scaleY: scale
- });
- structure.alpha = 0.7 + Math.random() * 0.3;
- structure.zone = zone;
- // Add decorative elements around structures
- if (Math.random() > 0.4 && assets.decorative) {
- var decorAsset = assets.decorative[Math.floor(Math.random() * assets.decorative.length)];
- var decoration = worldContainer.attachAsset(decorAsset, {
- anchorX: 0.5,
- anchorY: 1.0,
- x: posX + (Math.random() - 0.5) * 300,
- y: posY + (Math.random() - 0.5) * 200,
- scaleX: 0.8 + Math.random() * 1.4,
- scaleY: 0.8 + Math.random() * 1.4
- });
- decoration.alpha = 0.6 + Math.random() * 0.4;
- backgroundElements.push(decoration);
- }
- backgroundElements.push(structure);
- // Remove zoneElements.push since this function may not need it
- worldContainer.setChildIndex(structure, 8 + i % 4);
- }
-}
-function generateStructuredPlatforms(startX, zone) {
- // Create clear, logical pathways following nocturnecitylayout principles
- var platformLayouts = {
- 'City': [{
- x: 400,
- y: 1800
- }, {
- x: 800,
- y: 1600
- }, {
- x: 1200,
- y: 1400
- }, {
- x: 1600,
- y: 1200
- }, {
- x: 2000,
- y: 1500
- }, {
- x: 2400,
- y: 1300
- }],
- 'Cosmic': [{
- x: 400,
- y: 1600
- }, {
- x: 800,
- y: 1200
- }, {
- x: 1200,
- y: 800
- }, {
- x: 1600,
- y: 1000
- }, {
- x: 2000,
- y: 600
- }, {
- x: 2400,
- y: 900
- }],
- 'Forest': [{
- x: 400,
- y: 1700
- }, {
- x: 800,
- y: 1500
- }, {
- x: 1200,
- y: 1200
- }, {
- x: 1600,
- y: 1400
- }, {
- x: 2000,
- y: 1100
- }, {
- x: 2400,
- y: 1300
- }],
- 'Sea': [{
- x: 400,
- y: 1500
- }, {
- x: 800,
- y: 1700
- }, {
- x: 1200,
- y: 1400
- }, {
- x: 1600,
- y: 1600
- }, {
- x: 2000,
- y: 1300
- }, {
- x: 2400,
- y: 1500
- }],
- 'Under': [{
- x: 400,
- y: 1800
- }, {
- x: 800,
- y: 2000
- }, {
- x: 1200,
- y: 1900
- }, {
- x: 1600,
- y: 2100
- }, {
- x: 2000,
- y: 1800
- }, {
- x: 2400,
- y: 2000
- }]
- };
- var layout = platformLayouts[zone] || platformLayouts.City;
- for (var i = 0; i < layout.length; i++) {
+ // Add more platforms and hunks for extended level
+ var extendedPlatforms = [{
+ x: startX + 400,
+ y: 1500
+ }, {
+ x: startX + 900,
+ y: 1300
+ }, {
+ x: startX + 1400,
+ y: 1100
+ }, {
+ x: startX + 1900,
+ y: 1400
+ }];
+ for (var p = 0; p < extendedPlatforms.length; p++) {
var platform = new Platform();
- platform.x = startX + layout[i].x;
- platform.y = layout[i].y;
- platform.scaleX = 1.0;
- platform.scaleY = 1.0;
+ platform.x = extendedPlatforms[p].x;
+ platform.y = extendedPlatforms[p].y;
platforms.push(platform);
worldContainer.addChild(platform);
- }
-}
-function generateSingleHunk(startX, zone) {
- // Generate only ONE hunk per chunk to avoid chaos
- var hunk = new Hunk();
- hunk.x = startX + 1200; // Position in middle of chunk
- hunk.y = 1600; // Accessible height
- hunks.push(hunk);
- worldContainer.addChild(hunk);
- // Ensure hunk is visible in foreground with safe bounds checking
- var safeIndex = Math.max(0, worldContainer.children.length - 2);
- if (safeIndex < worldContainer.children.length) {
- worldContainer.setChildIndex(hunk, safeIndex);
- }
-}
-function generateMinimalDecoration(startX, zone) {
- // Add only 2-3 decorative elements that enhance rather than clutter
- var zoneDecorations = {
- 'City': ['statue', 'crystal'],
- 'Cosmic': ['starlight', 'crystal'],
- 'Forest': ['trees3', 'crystal'],
- 'Sea': ['caveoverlay', 'crystal'],
- 'Under': ['underoverlay', 'crystal']
- };
- var decorAssets = zoneDecorations[zone] || zoneDecorations.City;
- for (var i = 0; i < 2; i++) {
- var asset = decorAssets[i % decorAssets.length];
- var decoration = worldContainer.attachAsset(asset, {
- anchorX: 0.5,
- anchorY: 1.0,
- x: startX + 500 + i * 1000,
- y: 2000,
- scaleX: 1.2,
- scaleY: 1.2
- });
- decoration.alpha = 0.7;
- backgroundElements.push(decoration);
- // Ensure decoration stays behind platforms and player
- worldContainer.setChildIndex(decoration, 3 + i);
- }
-}
-function generateInfiniteGameplay(centerX, centerY) {
- // Add doors for interiors at strategic locations
- if (Math.random() > 0.7) {
- var doorTypes = ['door', 'door2', 'door3'];
- var doorAsset = doorTypes[Math.floor(Math.random() * doorTypes.length)];
- var door = worldContainer.attachAsset(doorAsset, {
- anchorX: 0.5,
- anchorY: 1.0,
- x: centerX + (Math.random() - 0.5) * 1000,
- y: centerY + (Math.random() - 0.5) * 400,
- scaleX: 0.6 + Math.random() * 0.8,
- scaleY: 0.6 + Math.random() * 0.8
- });
- door.interactive = true;
- door.down = function () {
- var interiorTypes = ['interior', 'interior2', 'interior3', 'interior4', 'interior5', 'interior6', 'interior7', 'interior8'];
- var interior = interiorTypes[Math.floor(Math.random() * interiorTypes.length)];
- showInterior(interior);
- };
- backgroundElements.push(door);
- worldContainer.setChildIndex(door, 15);
- }
-}
-function generateZoneContent(startX, zone, zoneData) {
- // Generate extensive midground elements with enhanced layering
- var midgroundCount = zone === 'Cosmic' ? 10 : zone === 'Forest' ? 8 : 6;
- for (var i = 0; i < midgroundCount; i++) {
- if (zoneData.midground && zoneData.midground.length > 0) {
- var asset = zoneData.midground[Math.floor(Math.random() * zoneData.midground.length)];
- var baseScale = zone === 'Cosmic' ? 2.2 : zone === 'Forest' ? 1.8 : zone === 'Sea' ? 1.5 : 1.2;
- var scale = baseScale * (0.7 + Math.random() * 0.8);
- // Better positioning for seamless coverage
- var xPos = startX + 200 + i * 450 + (Math.random() - 0.5) * 300;
- var yPos = zone === 'Cosmic' ? 1700 + Math.random() * 600 : 1800 + Math.random() * 600;
- var midground = worldContainer.attachAsset(asset, {
- anchorX: 0.5,
- anchorY: 1.0,
- x: xPos,
- y: yPos,
- scaleX: scale,
- scaleY: scale
- });
- midground.zone = zone;
- midground.alpha = 0.8 + Math.random() * 0.2;
- // Enhanced zone-specific midground styling
- if (zone === 'Cosmic') {
- midground.tint = 0xEEEEFF;
- midground.alpha = 0.95;
- // Add enhanced cosmic pulsing with better timing
- var originalScale = scale;
- var pulseTimer = setInterval(function () {
- if (midground && !midground.destroyed) {
- var pulseIntensity = 1.0 + Math.sin(Date.now() * 0.001 + i) * 0.15;
- tween(midground, {
- scaleX: originalScale * pulseIntensity,
- scaleY: originalScale * pulseIntensity
- }, {
- duration: 200,
- easing: tween.easeInOut
- });
- } else {
- clearInterval(pulseTimer);
- }
- }, 1500 + Math.random() * 2000);
- } else if (zone === 'Sea') {
- midground.tint = 0xDDEEFF;
- // Add wave-like motion
- midground.waveOffset = Math.random() * Math.PI * 2;
- } else if (zone === 'Under') {
- midground.tint = 0xFFDDDD;
- } else if (zone === 'Forest') {
- midground.tint = 0xDDFFDD;
- }
- backgroundElements.push(midground);
- worldContainer.setChildIndex(midground, 10 + i);
+ // Add single hunk every other extended platform
+ if (p % 2 === 1) {
+ var hunk = new Hunk();
+ hunk.x = platform.x;
+ hunk.y = platform.y - 20;
+ hunks.push(hunk);
+ worldContainer.addChild(hunk);
}
}
- // Generate extensive decorative elements with better distribution
- var decorCount = zone === 'Cosmic' ? 15 : zone === 'Forest' ? 12 : 10;
- for (var d = 0; d < decorCount; d++) {
- if (Math.random() > 0.2) {
- var decorAssets = getZoneDecorations(zone);
- var decorAsset = decorAssets[Math.floor(Math.random() * decorAssets.length)];
- // Better positioning to avoid clustering
- var xSpread = startX + d * 350 + Math.random() * 250;
- var ySpread = 1200 + Math.random() * 1000;
- // Add height variation by zone
- if (zone === 'Cosmic') {
- ySpread -= 400; // Higher placement
- } else if (zone === 'Under') {
- ySpread += 200; // Lower placement
- }
- var decoration = worldContainer.attachAsset(decorAsset, {
+ // Generate Holocosmos area north of main level (higher Y coordinates)
+ if (startX > 8000) {
+ // Generate Holocosmos beyond main city area
+ // Add galaxy backgrounds for Holocosmos
+ var galaxyBgs = ['Galaxybg', 'galaxybg2', 'galaxybg3', 'galaxybg4'];
+ for (var layer = 0; layer < galaxyBgs.length; layer++) {
+ var galaxyBg = worldContainer.attachAsset(galaxyBgs[layer], {
anchorX: 0.5,
anchorY: 1.0,
- x: xSpread,
- y: ySpread,
- scaleX: 1.0 + Math.random() * 1.8,
- scaleY: 1.0 + Math.random() * 1.8
+ x: startX + 1500,
+ y: 800 - layer * 200,
+ // Much higher than main level
+ scaleX: 2.5 - layer * 0.2,
+ scaleY: 2.5 - layer * 0.2
});
- // Enhanced zone-specific decoration styling
- decoration.zone = zone;
- decoration.alpha = 0.7 + Math.random() * 0.3;
- if (zone === 'Cosmic') {
- decoration.tint = 0xDDDDFF;
- decoration.alpha = 1.0;
- // Add cosmic rotation
- decoration.rotationSpeed = (Math.random() - 0.5) * 0.02;
- } else if (zone === 'Sea') {
- decoration.tint = 0xBBDDFF;
- } else if (zone === 'Under') {
- decoration.tint = 0xFF9999;
- } else if (zone === 'Forest') {
- decoration.tint = 0xBBDD99;
- } else {
- decoration.tint = 0xAAAA99;
- }
- backgroundElements.push(decoration);
- worldContainer.setChildIndex(decoration, 8 + d % 3);
+ galaxyBg.alpha = 0.4 + layer * 0.15;
+ backgroundElements.push(galaxyBg);
+ worldContainer.setChildIndex(galaxyBg, layer);
}
- }
-}
-function generateZoneEnvironment(startX, zone, zoneData) {
- // Generate environmental effects
- if (zoneData.environmental && zoneData.environmental.length > 0) {
- var effectCount = zone === 'Cosmic' ? 10 : 6;
- for (var i = 0; i < effectCount; i++) {
- var asset = zoneData.environmental[Math.floor(Math.random() * zoneData.environmental.length)];
- var scale = zone === 'Cosmic' ? 2.0 : 1.5;
- scale *= 0.6 + Math.random() * 0.8;
- var effect = worldContainer.attachAsset(asset, {
+ // Add galaxy midground elements
+ var galaxyMidgrounds = ['galaxy', 'starlight2', 'galaxy2'];
+ for (var i = 0; i < galaxyMidgrounds.length; i++) {
+ var midground = worldContainer.attachAsset(galaxyMidgrounds[i], {
anchorX: 0.5,
anchorY: 0.5,
- x: startX + Math.random() * 3000,
- y: zone === 'Cosmic' ? 600 + Math.random() * 1600 : 1000 + Math.random() * 1400,
- scaleX: scale,
- scaleY: scale
+ x: startX + 500 + i * 800,
+ y: 600 + Math.random() * 400,
+ scaleX: 1.5 + Math.random() * 1.0,
+ scaleY: 1.5 + Math.random() * 1.0
});
- effect.zone = zone;
- effect.animationType = zone;
- effect.driftSpeed = 0.3 + Math.random() * 1.2;
- effect.alpha = 0.6 + Math.random() * 0.4;
- // Zone-specific environmental behavior
- if (zone === 'Cosmic') {
- effect.tint = 0xEEEEFF;
- effect.rotationSpeed = (Math.random() - 0.5) * 0.03;
- effect.alpha = 0.8;
- } else if (zone === 'Forest') {
- effect.blinkTimer = Math.random() * 4000;
- } else if (zone === 'Under') {
- effect.floatAmplitude = 60 + Math.random() * 120;
- effect.floatSpeed = 0.015 + Math.random() * 0.025;
- }
- environmentalEffects.push(effect);
- worldContainer.setChildIndex(effect, 10);
+ midground.alpha = 0.6 + Math.random() * 0.3;
+ backgroundElements.push(midground);
}
- }
- // Generate zone-appropriate clouds/atmospheric elements
- if (zone === 'City' || zone === 'Sea') {
- generateAtmosphericClouds(startX, zone);
- }
-}
-function generatePlatformBridges(startX, zone) {
- // Create connecting platforms between major height differences
- var bridgeCount = zone === 'Cosmic' ? 8 : 5;
- for (var b = 0; b < bridgeCount; b++) {
- var bridgePlatform = new Platform();
- bridgePlatform.x = startX + 500 + b * 600;
- // Position bridges at intermediate heights
- if (zone === 'Cosmic') {
- bridgePlatform.y = 1400 - b * 50;
- } else if (zone === 'Under') {
- bridgePlatform.y = 1850 + b * 40;
- } else {
- bridgePlatform.y = 1550 - b % 3 * 100;
- }
- bridgePlatform.scaleX = 0.8;
- bridgePlatform.scaleY = 0.8;
- platforms.push(bridgePlatform);
- worldContainer.addChild(bridgePlatform);
- }
-}
-function generateVerticalExploration(startX, zone) {
- // Create extensive vertical exploration networks for all directions
- var explorationPlatforms = generateExplorationNetwork(startX, zone);
- // Create platforms with enhanced connectivity
- for (var p = 0; p < explorationPlatforms.length; p++) {
- var platform = new Platform();
- platform.x = explorationPlatforms[p].x;
- platform.y = explorationPlatforms[p].y;
- platform.scaleX = explorationPlatforms[p].scale || 1.0;
- platform.scaleY = explorationPlatforms[p].scale || 1.0;
- platforms.push(platform);
- worldContainer.addChild(platform);
- // Add hunks to strategic positions
- if (explorationPlatforms[p].hasHunk) {
- var hunk = new Hunk();
- hunk.x = platform.x + (Math.random() - 0.5) * 100;
- hunk.y = platform.y - 20;
- hunks.push(hunk);
- worldContainer.addChild(hunk);
- }
- }
-}
-function generateExplorationNetwork(startX, zone) {
- var network = [];
- if (zone === 'Cosmic') {
- // Extensive cosmic network with sky access
- for (var skyLevel = 0; skyLevel < 5; skyLevel++) {
- for (var skyPos = 0; skyPos < 6; skyPos++) {
- network.push({
- x: startX + 300 + skyPos * 400,
- y: 2000 - skyLevel * 350 - skyPos * 40,
- scale: 1.2 + skyLevel * 0.1,
- hasHunk: skyLevel === 2 && skyPos % 3 === 1
+ // Add swirling galaxy environmental effects
+ var _loop = function _loop() {
+ swirl = worldContainer.attachAsset('galaxy', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: startX + Math.random() * 2000,
+ y: 400 + Math.random() * 600,
+ scaleX: 0.8 + Math.random() * 1.2,
+ scaleY: 0.8 + Math.random() * 1.2
});
- }
- }
- } else if (zone === 'Under') {
- // Deep underground network
- for (var depth = 0; depth < 6; depth++) {
- for (var tunnel = 0; tunnel < 4; tunnel++) {
- network.push({
- x: startX + 400 + tunnel * 500,
- y: 1600 + depth * 250,
- scale: 1.0 - depth * 0.05,
- hasHunk: depth % 2 === 1 && tunnel % 2 === 0
- });
- }
- }
- } else if (zone === 'Forest') {
- // Canopy and ground levels
- for (var level = 0; level < 4; level++) {
- for (var branch = 0; branch < 7; branch++) {
- network.push({
- x: startX + 200 + branch * 350,
- y: level < 2 ? 1700 - level * 200 : 1300 - (level - 2) * 150,
- scale: level < 2 ? 0.8 : 1.2,
- hasHunk: level === 1 && branch % 4 === 2
- });
- }
- }
- } else if (zone === 'Sea') {
- // Surface and underwater platforms
- for (var wave = 0; wave < 5; wave++) {
- for (var current = 0; current < 5; current++) {
- var isUnderwater = wave > 2;
- network.push({
- x: startX + 300 + current * 450,
- y: isUnderwater ? 1800 + (wave - 2) * 200 : 1400 + Math.sin(current * 0.8) * 150,
- scale: isUnderwater ? 0.9 : 1.1,
- hasHunk: wave === 1 && current % 3 === 1
- });
- }
- }
- } else {
- // City network with building-hop platforms
- for (var floor = 0; floor < 4; floor++) {
- for (var building = 0; building < 8; building++) {
- network.push({
- x: startX + 250 + building * 400,
- y: 1700 - floor * 250 + building % 2 * 100,
- scale: 1.0 + floor * 0.1,
- hasHunk: floor === 1 && building % 5 === 2
- });
- }
- }
- }
- return network;
-}
-function generateVerticalPlatformNetworks(startX, zone) {
- // Legacy function - now calls enhanced exploration network
- generateVerticalExploration(startX, zone);
-}
-function generateUnusedAssets(startX, zone) {
- // Place unused non-player assets strategically throughout zones
- var decorativeAssets = getUnusedAssetsByZone(zone);
- var decorCount = zone === 'Cosmic' ? 12 : 8;
- for (var i = 0; i < decorCount; i++) {
- var asset = decorativeAssets[Math.floor(Math.random() * decorativeAssets.length)];
- var decoration = worldContainer.attachAsset(asset, {
- anchorX: 0.5,
- anchorY: 1.0,
- x: startX + i * 400 + Math.random() * 300,
- y: 1200 + Math.random() * 1000,
- scaleX: 1.2 + Math.random() * 1.8,
- scaleY: 1.2 + Math.random() * 1.8
- });
- // Zone-specific decoration behavior
- decoration.zone = zone;
- decoration.alpha = 0.7 + Math.random() * 0.3;
- if (zone === 'Cosmic') {
- decoration.tint = 0xDDDDFF;
- decoration.alpha = 0.9;
- // Add cosmic glow animation
- var originalAlpha = decoration.alpha;
- tween(decoration, {
- alpha: originalAlpha * 1.5
- }, {
- duration: 2000 + Math.random() * 3000,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- tween(decoration, {
- alpha: originalAlpha
+ swirl.alpha = 0.3 + Math.random() * 0.4;
+ // Add swirling animation
+ function animateSwirl(swirlObj) {
+ tween(swirlObj, {
+ rotation: swirlObj.rotation + Math.PI * 2
}, {
- duration: 2000 + Math.random() * 3000,
- easing: tween.easeInOut
+ duration: 3000 + Math.random() * 2000,
+ easing: tween.linear,
+ onFinish: function onFinish() {
+ animateSwirl(swirlObj);
+ }
});
}
+ animateSwirl(swirl);
+ backgroundElements.push(swirl);
+ },
+ swirl;
+ for (var i = 0; i < 5; i++) {
+ _loop();
+ }
+ // Generate cosmic platforms using starlight and galaxy assets
+ var cosmicPlatformAssets = ['starlight', 'starlight2', 'galaxy3', 'galaxy4'];
+ for (var i = 0; i < 6; i++) {
+ var platformAsset = cosmicPlatformAssets[Math.floor(Math.random() * cosmicPlatformAssets.length)];
+ var cosmicPlatform = worldContainer.attachAsset(platformAsset, {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: startX + 300 + i * 400,
+ y: 600 - i % 3 * 150,
+ // Floating cosmic platforms
+ scaleX: 3.0,
+ scaleY: 3.0
});
- } else if (zone === 'Sea') {
- decoration.tint = 0xAADDFF;
- } else if (zone === 'Under') {
- decoration.tint = 0xEE8888;
- } else if (zone === 'Forest') {
- decoration.tint = 0xAADD88;
- } else {
- decoration.tint = 0xAAAAAA;
+ // Add cosmic glow effect
+ cosmicPlatform.tint = [0x9966FF, 0x66FFFF, 0xFF66FF, 0xFFFF66][Math.floor(Math.random() * 4)];
+ cosmicPlatform.alpha = 0.8;
+ // Make platforms solid for collision
+ platforms.push({
+ x: cosmicPlatform.x,
+ y: cosmicPlatform.y,
+ width: cosmicPlatform.width * cosmicPlatform.scale.x,
+ height: cosmicPlatform.height * cosmicPlatform.scale.y,
+ scale: {
+ x: cosmicPlatform.scale.x,
+ y: cosmicPlatform.scale.y
+ },
+ intersects: function intersects(other) {
+ // Basic intersection check
+ return cosmicPlatform.intersects ? cosmicPlatform.intersects(other) : false;
+ }
+ });
+ worldContainer.addChild(cosmicPlatform);
}
- backgroundElements.push(decoration);
- worldContainer.setChildIndex(decoration, 7 + i);
- }
-}
-function getUnusedAssetsByZone(zone) {
- if (zone === 'City') {
- return ['statue', 'crystal', 'artefact', 'artefact2', 'mandroid', 'tech', 'tokurrencoin', 'skilltree', 'door2', 'door3', 'crystalheart', 'plush', 'plush2'];
- } else if (zone === 'Cosmic') {
- return ['starlight', 'galaxy3', 'crystal', 'artefact', 'starlight2', 'galaxy4', 'crystalheart', 'tech', 'tokurrencoin', 'artefact2'];
- } else if (zone === 'Forest') {
- return ['trees3', 'trees4', 'plush', 'plush2', 'plush3', 'crystal', 'artefact', 'crystalheart'];
- } else if (zone === 'Sea') {
- return ['caveoverlay', 'crystal', 'artefact2', 'underoverlay', 'crystalheart', 'plush3'];
- } else if (zone === 'Under') {
- return ['underoverlay', 'crystal', 'crystalheart', 'caveoverlay', 'artefact', 'tech'];
- }
- return ['crystal', 'artefact', 'crystalheart']; // Fallback
-}
-function getZoneDecorations(zone) {
- return getUnusedAssetsByZone(zone);
-}
-function generateAtmosphericClouds(startX, zone) {
- var cloudCount = zone === 'Sea' ? 8 : 6;
- var cloudAssets = ['cloud1', 'cloud2', 'cloud3'];
- for (var i = 0; i < cloudCount; i++) {
- 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: i < cloudCount / 2 ? 2200 + Math.random() * 400 : 900 + Math.random() * 600
- });
- var cloudScale = 0.6 + Math.random() * 1.2;
- cloud.scale.x = cloudScale;
- cloud.scale.y = cloudScale;
- cloud.alpha = i < cloudCount / 2 ? 0.7 + Math.random() * 0.3 : 0.3 + Math.random() * 0.4;
- cloud.driftSpeed = 0.4 + Math.random() * 1.0;
- // Zone-specific cloud styling
- if (zone === 'Sea') {
- cloud.tint = 0xCCEEFF;
- cloud.alpha *= 1.2;
- }
- clouds.push(cloud);
- worldContainer.setChildIndex(cloud, 7);
- }
- // Enhanced vertical platform networks with better connectivity
- var verticalPlatforms = [];
- if (zone === 'Cosmic') {
- // Cosmic zone: Multi-tier ascending spirals with connection platforms
- verticalPlatforms = [
- // Lower tier
- {
- x: startX + 300,
- y: 1600
+ // Add HOLOCOSMOS title using alphabet assets
+ var holocosmosLetters = [{
+ asset: 'h',
+ x: startX + 200
}, {
- x: startX + 600,
- y: 1500
+ asset: 'o',
+ x: startX + 300
}, {
- x: startX + 900,
- y: 1400
- },
- // Mid tier - ascending spiral
- {
- x: startX + 1200,
- y: 1200
+ asset: 'l',
+ x: startX + 400
}, {
- x: startX + 1500,
- y: 1000
+ asset: 'o',
+ x: startX + 500
}, {
- x: startX + 1800,
- y: 800
- },
- // Upper tier - sky access
- {
- x: startX + 2100,
- y: 600
+ asset: 'c',
+ x: startX + 600
}, {
- x: startX + 2400,
- y: 400
+ asset: 'o',
+ x: startX + 700
}, {
- x: startX + 2700,
- y: 200
- },
- // Connecting bridges
- {
- x: startX + 750,
- y: 1350
+ asset: 's',
+ x: startX + 800
}, {
- x: startX + 1650,
- y: 900
+ asset: 'm',
+ x: startX + 900
}, {
- x: startX + 2550,
- y: 500
- }];
- } else if (zone === 'Under') {
- // Underground: Descending cave system with multiple levels
- verticalPlatforms = [
- // Entry level
- {
- x: startX + 400,
- y: 1600
+ asset: 'o',
+ x: startX + 1000
}, {
- x: startX + 700,
- y: 1700
- },
- // Mid descent
- {
- x: startX + 1000,
- y: 1900
- }, {
- x: startX + 1300,
- y: 2100
- },
- // Deep level
- {
- x: startX + 1600,
- y: 2300
- }, {
- x: startX + 1900,
- y: 2200
- },
- // Return path
- {
- x: startX + 2200,
- y: 2000
- }, {
- x: startX + 2500,
- y: 1800
+ asset: 's',
+ x: startX + 1100
}];
- } else if (zone === 'Sea') {
- // Sea zone: Wave-like platform arrangement with diving platforms
- verticalPlatforms = [
- // Surface waves
- {
- x: startX + 400,
- y: 1400
- }, {
- x: startX + 700,
- y: 1500
- }, {
- x: startX + 1000,
- y: 1300
- },
- // Diving platforms
- {
- x: startX + 1300,
- y: 1600
- }, {
- x: startX + 1600,
- y: 1800
- }, {
- x: startX + 1900,
- y: 1900
- },
- // Surfacing platforms
- {
- x: startX + 2200,
- y: 1700
- }, {
- x: startX + 2500,
- y: 1500
- }];
- } else if (zone === 'Forest') {
- // Forest zone: Tree canopy levels
- verticalPlatforms = [
- // Ground level
- {
- x: startX + 400,
- y: 1700
- }, {
- x: startX + 700,
- y: 1600
- },
- // Canopy level
- {
- x: startX + 1000,
- y: 1200
- }, {
- x: startX + 1300,
- y: 1100
- }, {
- x: startX + 1600,
- y: 1000
- },
- // Treetop level
- {
- x: startX + 1900,
- y: 800
- }, {
- x: startX + 2200,
- y: 900
- }, {
- x: startX + 2500,
- y: 1100
- }];
- } else {
- // City zone: Building-hop platforms with varied heights
- verticalPlatforms = [
- // Street level
- {
- x: startX + 400,
- y: 1800
- }, {
- x: startX + 700,
- y: 1700
- },
- // Mid-rise level
- {
- x: startX + 1000,
- y: 1400
- }, {
- x: startX + 1300,
- y: 1300
- }, {
- x: startX + 1600,
- y: 1200
- },
- // High-rise level
- {
- x: startX + 1900,
- y: 900
- }, {
- x: startX + 2200,
- y: 1000
- }, {
- x: startX + 2500,
- y: 1100
- }];
- }
- for (var p = 0; p < verticalPlatforms.length; p++) {
- var platform = new Platform();
- platform.x = verticalPlatforms[p].x;
- platform.y = verticalPlatforms[p].y;
- // Scale platforms based on zone and height for better visibility
- var heightRatio = (2000 - platform.y) / 1000;
- platform.scaleX = 1.0 + heightRatio * 0.3;
- platform.scaleY = 1.0;
- platforms.push(platform);
- worldContainer.addChild(platform);
- // Add connection platforms between major height differences
- if (p > 0) {
- var prevPlatform = verticalPlatforms[p - 1];
- var heightDiff = Math.abs(platform.y - prevPlatform.y);
- if (heightDiff > 300) {
- var midPlatform = new Platform();
- midPlatform.x = (platform.x + prevPlatform.x) / 2;
- midPlatform.y = (platform.y + prevPlatform.y) / 2;
- midPlatform.scaleX = 0.8;
- platforms.push(midPlatform);
- worldContainer.addChild(midPlatform);
- }
+ for (var i = 0; i < holocosmosLetters.length; i++) {
+ var letter = worldContainer.attachAsset(holocosmosLetters[i].asset, {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: holocosmosLetters[i].x,
+ y: 300,
+ scaleX: 2.5,
+ scaleY: 2.5
+ });
+ letter.tint = 0x9966FF;
+ letter.alpha = 0.9;
+ // Add floating animation to letters
+ (function (letterObj, index) {
+ function floatLetter() {
+ tween(letterObj, {
+ y: 250 + Math.sin(Date.now() * 0.001 + index) * 30
+ }, {
+ duration: 2000 + Math.random() * 1000,
+ easing: tween.easeInOut,
+ onFinish: floatLetter
+ });
+ }
+ floatLetter();
+ })(letter, i);
+ backgroundElements.push(letter);
}
- // Add hunks to strategic vertical positions
- if (p % 3 === 1 && Math.random() > 0.4) {
- var hunk = new Hunk();
- hunk.x = platform.x + (Math.random() - 0.5) * 100;
- hunk.y = platform.y - 20;
- hunks.push(hunk);
- worldContainer.addChild(hunk);
- }
}
// Update last generated position
lastGeneratedX = startX + 2500;
}
-function determineZone(x, y) {
- // Use infinite world system for zone determination
- if (y === undefined && bloodmage) {
- y = bloodmage.y;
- }
- return infiniteWorld.getZone(x, y || 1800);
-}
-function generateEnvironmentalEffects(startX, zone) {
- var zoneData = zones[zone];
- if (!zoneData || !zoneData.environmental) {
- return;
- }
- // Zone-specific effect count and sizing
- var effectCount = zone === 'Cosmic' ? 8 : 4; // More cosmic effects
- var baseScale = zone === 'Cosmic' ? 1.5 : zone === 'Forest' ? 1.2 : 1.0;
- // Generate animated environmental effects
- for (var i = 0; i < effectCount; i++) {
- var asset = zoneData.environmental[Math.floor(Math.random() * zoneData.environmental.length)];
- var layeredScale = baseScale * (0.7 + Math.random() * 0.8);
- var layerDepth = Math.random() * 3; // For varied layering
- var effect = worldContainer.attachAsset(asset, {
- anchorX: 0.5,
- anchorY: 0.5,
- x: startX + Math.random() * 2500,
- y: zone === 'Cosmic' ? 800 + Math.random() * 1400 : 1000 + Math.random() * 1200,
- // Higher cosmic range
- scaleX: layeredScale,
- scaleY: layeredScale
- });
- effect.zone = zone;
- effect.animationType = zone; // Store for animation behavior
- effect.driftSpeed = zone === 'Cosmic' ? 0.2 + Math.random() * 0.8 : 0.3 + Math.random() * 1.5;
- effect.alpha = zone === 'Cosmic' ? 0.7 + Math.random() * 0.3 : 0.6 + Math.random() * 0.4;
- // Enhanced cosmic effects
- if (zone === 'Cosmic') {
- effect.tint = 0xEEEEFF;
- // Add subtle rotation for cosmic elements
- effect.rotationSpeed = (Math.random() - 0.5) * 0.02;
+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);
}
- // Zone-specific animation setup
- if (zone === 'City' || zone === 'Sea') {
- // Drifting clouds/effects
- effect.driftDirection = Math.random() * Math.PI * 2;
- } else if (zone === 'Forest') {
- // Blinking forest effects
- effect.blinkTimer = Math.random() * 3000;
- } else if (zone === 'Under') {
- // Floating underworld effects
- effect.floatAmplitude = 50 + Math.random() * 100;
- effect.floatSpeed = 0.02 + Math.random() * 0.03;
- }
- environmentalEffects.push(effect);
- zoneElements.push(effect);
- worldContainer.setChildIndex(effect, 6);
}
-}
-function cleanupDistantElements() {
- if (!bloodmage) {
- return;
- }
- var playerX = bloodmage.x;
- var playerY = bloodmage.y;
- var cleanupDistance = 6000; // Much larger cleanup radius for infinite world
- // Clean up elements that are too far from player
- var elementArrays = [backgroundElements, environmentalEffects, buildings, platforms.filter(function (p) {
- return !p.permanent;
- }),
- // Don't cleanup important platforms
- hunks.filter(function (h) {
- return h.captured;
- }),
- // Only cleanup captured hunks
- clouds];
- for (var arrayIndex = 0; arrayIndex < elementArrays.length; arrayIndex++) {
- var elementArray = elementArrays[arrayIndex];
- for (var i = elementArray.length - 1; i >= 0; i--) {
- var element = elementArray[i];
- if (element && element.x !== undefined && element.y !== undefined) {
- var distance = Math.sqrt(Math.pow(element.x - playerX, 2) + Math.pow(element.y - playerY, 2));
- if (distance > cleanupDistance) {
- element.destroy();
- elementArray.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);
}
}
-}
-// Legacy function for compatibility
-function cleanupOldElements() {
- cleanupDistantElements();
-}
-function createLevel() {
- // Create world template-based level using 'world' asset as primary template
- createWorldBasedLevel();
-}
-function createWorldBasedLevel() {
- // Step 1: Place primary world template as background reference
- initializeWorldTemplate();
- // Step 2: Generate region-based backgrounds with parallax
- generateWorldBasedBackgrounds();
- // Step 3: Create platforms matching world layout
- generateWorldMatchedPlatforms();
- // Step 4: Place assets according to world template positions
- generateWorldPositionedAssets();
- // Step 5: Add environmental effects with proper layering
- generateWorldEnvironmentalEffects();
- // Step 6: Initialize player and ensure proper layering
- initializePlayerAndLayering();
-}
-function initializeWorldTemplate() {
- // Place world asset as primary background template
- worldTemplate = worldContainer.attachAsset('world', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 0,
- y: 1366,
- scaleX: 4.0,
- scaleY: 3.8
- });
- worldTemplate.alpha = 0.3; // Semi-transparent template
- backgroundElements.push(worldTemplate);
- worldContainer.setChildIndex(worldTemplate, 0);
-}
-function generateWorldBasedBackgrounds() {
- // Generate backgrounds for each region using world template positioning
- var regions = ['cosmic', 'city', 'forest', 'sea', 'under'];
- for (var i = 0; i < regions.length; i++) {
- var regionName = regions[i];
- var regionData = worldTemplate[regionName];
- if (!regionData) {
- continue;
+ // Cleanup old platforms
+ for (var i = platforms.length - 1; i >= 0; i--) {
+ if (platforms[i].x < cleanupThreshold) {
+ platforms[i].destroy();
+ platforms.splice(i, 1);
}
- // Use world template coordinates for proper positioning
- var gameX = regionData.gameX;
- var gameY = regionData.gameY;
- // Primary background for region
- var primaryBg = regionData.backgrounds[0];
- var bgAsset = worldContainer.attachAsset(primaryBg, {
- anchorX: 0.5,
- anchorY: 0.5,
- x: gameX,
- y: gameY,
- scaleX: 4.0,
- scaleY: 3.0
- });
- bgAsset.alpha = 0.6;
- bgAsset.parallaxSpeed = regionData.parallaxSpeed;
- bgAsset.region = regionName;
- bgAsset.baseX = gameX;
- bgAsset.baseY = gameY;
- // Region-specific tinting
- if (regionName === 'cosmic') {
- bgAsset.tint = 0xDDDDFF;
- } else if (regionName === 'forest') {
- bgAsset.tint = 0xDDFFDD;
- } else if (regionName === 'sea') {
- bgAsset.tint = 0xCCEEFF;
- } else if (regionName === 'under') {
- bgAsset.tint = 0xFFDDDD;
- }
- backgroundElements.push(bgAsset);
- worldContainer.setChildIndex(bgAsset, 1 + i);
- // Secondary background for depth
- if (regionData.backgrounds.length > 1) {
- var secondaryBg = worldContainer.attachAsset(regionData.backgrounds[1], {
- anchorX: 0.5,
- anchorY: 0.5,
- x: gameX + 300,
- y: gameY - 200,
- scaleX: 3.0,
- scaleY: 2.0
- });
- secondaryBg.alpha = 0.4;
- secondaryBg.parallaxSpeed = regionData.parallaxSpeed * 0.7;
- secondaryBg.region = regionName;
- secondaryBg.baseX = gameX + 300;
- secondaryBg.baseY = gameY - 200;
- backgroundElements.push(secondaryBg);
- // Safely set child index with bounds checking
- var targetIndex = Math.min(5 + i, worldContainer.children.length - 1);
- if (targetIndex >= 0 && targetIndex < worldContainer.children.length) {
- worldContainer.setChildIndex(secondaryBg, targetIndex);
- }
- }
}
-}
-function generateWorldMatchedPlatforms() {
- // Create platforms that follow the world template structure
- var platformConfigs = [
- // Cosmic region - ascending platforms
- {
- x: -2000,
- y: 800,
- region: 'cosmic'
- }, {
- x: -1600,
- y: 700,
- region: 'cosmic'
- }, {
- x: -1200,
- y: 600,
- region: 'cosmic'
- }, {
- x: -800,
- y: 500,
- region: 'cosmic'
- },
- // City region - building-level platforms
- {
- x: -400,
- y: 1200,
- region: 'city'
- }, {
- x: 0,
- y: 1100,
- region: 'city'
- }, {
- x: 400,
- y: 1000,
- region: 'city'
- }, {
- x: 800,
- y: 1100,
- region: 'city'
- }, {
- x: 1200,
- y: 1200,
- region: 'city'
- }, {
- x: 1600,
- y: 1150,
- region: 'city'
- },
- // Forest region - canopy platforms
- {
- x: 2000,
- y: 1300,
- region: 'forest'
- }, {
- x: 2400,
- y: 1200,
- region: 'forest'
- }, {
- x: 2800,
- y: 1100,
- region: 'forest'
- }, {
- x: 3200,
- y: 1250,
- region: 'forest'
- },
- // Under region - cave platforms
- {
- x: -400,
- y: 2400,
- region: 'under'
- }, {
- x: 0,
- y: 2500,
- region: 'under'
- }, {
- x: 400,
- y: 2450,
- region: 'under'
- }, {
- x: 800,
- y: 2600,
- region: 'under'
- }];
- for (var i = 0; i < platformConfigs.length; i++) {
- var config = platformConfigs[i];
- var platform = new Platform();
- platform.x = config.x;
- platform.y = config.y;
- platform.region = config.region;
- // Region-specific platform scaling
- if (config.region === 'cosmic') {
- platform.scaleX = 1.2;
- platform.scaleY = 1.2;
- } else if (config.region === 'under') {
- platform.scaleX = 1.5;
- platform.scaleY = 1.0;
+ // 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);
}
- platforms.push(platform);
- worldContainer.addChild(platform);
}
-}
-function generateWorldPositionedAssets() {
- // Place midground and decorative assets based on world template regions
- var regions = ['cosmic', 'city', 'forest', 'under'];
- for (var i = 0; i < regions.length; i++) {
- var regionName = regions[i];
- var regionData = biomeData[regionName];
- if (!regionData) {
- continue;
- } // Skip undefined regions instead of returning
- var gameX = 0; // Use simple positioning since biomeData structure is different
- var gameY = regionData.centerY || 1600;
- // Place midground assets - check if midground exists and has elements
- if (regionData.backgrounds && regionData.backgrounds.length > 0) {
- for (var m = 0; m < Math.min(3, regionData.backgrounds.length); m++) {
- var midgroundAsset = regionData.backgrounds[m];
- var offsetX = (m - 1) * 600; // Spread across region
- var offsetY = (Math.random() - 0.5) * 200;
- var midground = worldContainer.attachAsset(midgroundAsset, {
- anchorX: 0.5,
- anchorY: 1.0,
- x: gameX + offsetX,
- y: gameY + offsetY,
- scaleX: 1.5 + Math.random() * 0.5,
- scaleY: 1.5 + Math.random() * 0.5
- });
- midground.alpha = 0.9;
- midground.region = regionName;
- backgroundElements.push(midground);
- worldContainer.setChildIndex(midground, 10 + i * 3 + m);
- }
+ // 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);
}
- // Place decorative assets using available biome assets
- var decorativeAssets = [];
- if (regionData.buildings) {
- decorativeAssets = decorativeAssets.concat(regionData.buildings);
- }
- if (regionData.neonSigns) {
- decorativeAssets = decorativeAssets.concat(regionData.neonSigns);
- }
- if (regionData.effects) {
- decorativeAssets = decorativeAssets.concat(regionData.effects);
- }
- if (decorativeAssets.length > 0) {
- for (var d = 0; d < 2; d++) {
- var decorAsset = decorativeAssets[d % decorativeAssets.length];
- var decorX = gameX + (d - 0.5) * 800;
- var decorY = gameY + Math.random() * 100;
- var decoration = worldContainer.attachAsset(decorAsset, {
- anchorX: 0.5,
- anchorY: 1.0,
- x: decorX,
- y: decorY,
- scaleX: 1.0 + Math.random() * 0.8,
- scaleY: 1.0 + Math.random() * 0.8
- });
- decoration.alpha = 0.8;
- decoration.region = regionName;
- // Add blinking effects for certain assets
- if (decorAsset === 'neonSign' || decorAsset === 'neonsign2') {
- decoration.tint = [0xFF00FF, 0x00FFFF, 0xFFFF00][Math.floor(Math.random() * 3)];
- animateNeonBlink(decoration);
- }
- backgroundElements.push(decoration);
- worldContainer.setChildIndex(decoration, 8);
- }
- }
}
}
-function generateWorldEnvironmentalEffects() {
- // Add animated environmental effects based on world regions
- var regions = ['cosmic', 'city', 'forest', 'under'];
- for (var i = 0; i < regions.length; i++) {
- var regionName = regions[i];
- var regionData = biomeData[regionName];
- if (regionData && regionData.effects && regionData.effects.length > 0) {
- var gameX = 0; // Use simple positioning since biomeData structure is different
- var gameY = regionData.centerY || 1600;
- for (var e = 0; e < 4; e++) {
- var effectAsset = regionData.effects[Math.floor(Math.random() * regionData.effects.length)];
- var effectX = gameX + (Math.random() - 0.5) * 1200;
- var effectY = gameY + (Math.random() - 0.5) * 400;
- var effect = worldContainer.attachAsset(effectAsset, {
- anchorX: 0.5,
- anchorY: 0.5,
- x: effectX,
- y: effectY,
- scaleX: 0.8 + Math.random() * 1.0,
- scaleY: 0.8 + Math.random() * 1.0
- });
- effect.alpha = 0.6 + Math.random() * 0.4;
- effect.region = regionName;
- effect.driftSpeed = 0.5 + Math.random() * 1.0;
- effect.animationType = regionName;
- // Region-specific effects
- if (regionName === 'cosmic') {
- effect.tint = 0xDDDDFF;
- effect.rotationSpeed = (Math.random() - 0.5) * 0.02;
- animateCosmicGlow(effect);
- } else if (regionName === 'forest') {
- effect.blinkTimer = Math.random() * 3000;
- } else if (regionName === 'under') {
- effect.floatAmplitude = 30 + Math.random() * 60;
- effect.floatSpeed = 0.01 + Math.random() * 0.02;
- }
- environmentalEffects.push(effect);
- worldContainer.setChildIndex(effect, 6);
- }
- }
- }
-}
-function animateNeonBlink(neonAsset) {
- var originalAlpha = neonAsset.alpha;
- var animDuration = 1000 + Math.random() * 2000;
- function blinkCycle() {
- tween(neonAsset, {
- alpha: 0.2
- }, {
- duration: animDuration,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- tween(neonAsset, {
- alpha: originalAlpha
- }, {
- duration: animDuration,
- easing: tween.easeInOut,
- onFinish: blinkCycle
- });
- }
- });
- }
- blinkCycle();
-}
-function animateCosmicGlow(cosmicAsset) {
- var originalScale = cosmicAsset.scaleX;
- var originalAlpha = cosmicAsset.alpha;
- function glowCycle() {
- tween(cosmicAsset, {
- scaleX: originalScale * 1.3,
- scaleY: originalScale * 1.3,
- alpha: originalAlpha * 1.5
- }, {
- duration: 2000 + Math.random() * 3000,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- tween(cosmicAsset, {
- scaleX: originalScale,
- scaleY: originalScale,
- alpha: originalAlpha
- }, {
- duration: 2000 + Math.random() * 3000,
- easing: tween.easeInOut,
- onFinish: glowCycle
- });
- }
- });
- }
- glowCycle();
-}
-function generateCleanBackgroundLayers() {
- // Primary background layer - nocturnecitylayout as reference
- var nocturneCityBg = worldContainer.attachAsset('nocturnecitylayout', {
+function createLevel() {
+ // Add nocturnecity as the main side background layer to prevent player going behind elements
+ var nocturneCityBg = worldContainer.attachAsset('nocturnecity', {
anchorX: 0.5,
anchorY: 1.0,
+ x: 2500,
+ y: 2732,
+ scaleX: 2.5,
+ scaleY: 2.5
+ });
+ // Ensure nocturnecity stays at the very back
+ worldContainer.setChildIndex(nocturneCityBg, 0);
+ // 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.2,
+ scaleX: 2.0,
scaleY: 2.0
});
- nocturneCityBg.alpha = 0.8;
- backgroundElements.push(nocturneCityBg);
- worldContainer.setChildIndex(nocturneCityBg, 0);
- // Secondary background for depth
- var bg2 = worldContainer.attachAsset('bg2', {
+ background2.alpha = 0.7;
+ // Add main background layer on top
+ var background = worldContainer.attachAsset('bg', {
anchorX: 0.5,
anchorY: 1.0,
x: 2048,
y: 2732,
- scaleX: 3.0,
- scaleY: 3.0
+ scaleX: 0.8,
+ scaleY: 0.8
});
- bg2.alpha = 0.4;
- backgroundElements.push(bg2);
- worldContainer.setChildIndex(bg2, 1);
- // Add atmospheric clouds
- for (var i = 0; i < 6; i++) {
+ background.alpha = 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: 500 + i * 600,
- y: 2400 + Math.random() * 200
+ x: Math.random() * 4096 - 1024,
+ // Spread across wider area
+ y: 2100 + Math.random() * 400 // Position below starting platform (1800-2000)
});
- var cloudScale = 0.8 + Math.random() * 0.4;
+ // Vary cloud sizes for depth
+ var cloudScale = 0.5 + Math.random() * 1.0;
cloud.scale.x = cloudScale;
cloud.scale.y = cloudScale;
- cloud.alpha = 0.6 + Math.random() * 0.3;
- cloud.driftSpeed = 0.3 + Math.random() * 0.7;
+ // Make clouds more visible with better opacity
+ cloud.alpha = 0.8 + Math.random() * 0.2;
+ // Store initial position and drift speed for animation
+ cloud.initialX = cloud.x;
+ cloud.driftSpeed = 0.5 + Math.random() * 1.5;
clouds.push(cloud);
- backgroundElements.push(cloud);
- worldContainer.setChildIndex(cloud, 2 + i);
+ // Put clouds behind platforms but in front of backgrounds
+ worldContainer.setChildIndex(cloud, 4 + i);
}
-}
-function generateLogicalPlatformPathways() {
- // Create clear pathways based on nocturnecitylayout structure
- var platformLayout = [
- // Left side ascending path - STARTING PLATFORM positioned exactly where player spawns
- {
- x: 600,
+ // Create more buildings with varied positioning to fill the midground
+ for (var i = 0; i < 15; i++) {
+ var building = new Building();
+ building.x = 100 + i * 400;
+ building.y = 2000; // Position at ground level so buildings meet platforms
+ building.scale.x = 0.6 + Math.random() * 0.8; // More varied building sizes
+ building.scale.y = 0.6 + Math.random() * 0.8;
+ buildings.push(building);
+ worldContainer.addChild(building);
+ }
+ // Add additional statues for better edge concealment
+ for (var s = 0; s < 8; s++) {
+ var statue = worldContainer.attachAsset('statue', {
+ anchorX: 0.5,
+ anchorY: 1.0,
+ x: 500 + s * 800,
+ y: 2000,
+ scaleX: 0.7 + Math.random() * 0.6,
+ scaleY: 0.7 + Math.random() * 0.6
+ });
+ statue.tint = 0x555555 + Math.floor(Math.random() * 0x333333);
+ backgroundElements.push(statue);
+ // Ensure statues stay behind platforms
+ var statueIndex = worldContainer.getChildIndex(statue);
+ worldContainer.setChildIndex(statue, Math.max(0, statueIndex - 5));
+ }
+ // Add additional neon signs for better visual coverage
+ for (var n = 0; n < 15; n++) {
+ var neonAsset = Math.random() > 0.5 ? 'neonSign' : 'neonsign2';
+ var neonSign = worldContainer.attachAsset(neonAsset, {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: 200 + n * 450,
+ y: 1300 + Math.random() * 600,
+ scaleX: 0.6 + Math.random() * 0.8,
+ scaleY: 0.6 + Math.random() * 0.8
+ });
+ neonSign.alpha = 0.5 + Math.random() * 0.4;
+ neonSign.tint = [0xFF00FF, 0x00FFFF, 0xFFFF00, 0xFF0088, 0x88FF00][Math.floor(Math.random() * 5)];
+ backgroundElements.push(neonSign);
+ }
+ // Add more vertical decorative elements to fill gaps
+ for (var v = 0; v < 12; v++) {
+ var decorAssets = ['crystal', 'artefact', 'skilltree'];
+ var decorAsset = decorAssets[Math.floor(Math.random() * decorAssets.length)];
+ var decoration = worldContainer.attachAsset(decorAsset, {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: 400 + v * 500,
+ y: 1000 + Math.random() * 800,
+ scaleX: 1.5 + Math.random() * 1.0,
+ scaleY: 1.5 + Math.random() * 1.0
+ });
+ decoration.alpha = 0.4 + Math.random() * 0.3;
+ decoration.tint = 0x666666 + Math.floor(Math.random() * 0x999999);
+ backgroundElements.push(decoration);
+ var decorIndex = worldContainer.getChildIndex(decoration);
+ worldContainer.setChildIndex(decoration, Math.max(0, decorIndex - 8));
+ }
+ var ground = new Platform();
+ ground.x = 1024;
+ ground.y = 2000;
+ ground.scale.x = 10;
+ platforms.push(ground);
+ worldContainer.addChild(ground);
+ // Create repeating bottom platform foundation
+ for (var b = 0; b < 15; b++) {
+ var bottomPlatform = new Platform();
+ bottomPlatform.x = 300 + b * 400;
+ bottomPlatform.y = 2000; // Ground level
+ bottomPlatform.scale.x = 1.2;
+ bottomPlatform.scale.y = 0.8;
+ platforms.push(bottomPlatform);
+ worldContainer.addChild(bottomPlatform);
+ }
+ // Create platform layout based on nocturnecitylayout guide
+ var platformPositions = [{
+ x: 400,
y: 1800
},
// Starting platform
{
- x: 900,
- y: 1650
+ x: 800,
+ y: 1600
},
- // Step up
+ // Lower left area
{
x: 1200,
y: 1500
},
- // Continue up
+ // Lower mid
{
- x: 1500,
- y: 1350
+ x: 1600,
+ y: 1600
},
- // Higher level
- // Central plateau area
+ // Shop door platform
{
- x: 1800,
- y: 1200
+ x: 2000,
+ y: 1400
},
- // Central high platform
+ // Mid level ascending
{
- x: 2100,
- y: 1200
- },
- // Extended plateau
- {
x: 2400,
y: 1200
},
- // Plateau continues
- // Right side descending path
+ // Mid upper
{
- x: 2700,
- y: 1350
+ x: 2800,
+ y: 1000
},
- // Start descent
+ // Upper mid
{
- x: 3000,
- y: 1500
+ x: 3200,
+ y: 1100
},
- // Down
+ // Plateau area
{
- x: 3300,
- y: 1650
- },
- // Further down
- {
x: 3600,
- y: 1800
- },
- // Back to ground level
- // Additional connecting platforms
- {
- x: 1050,
- y: 1725
- },
- // Left connector
- {
- x: 1350,
- y: 1575
- },
- // Mid connector
- {
- x: 2250,
y: 1300
},
- // Central connector
+ // Right mid
{
- x: 2850,
- y: 1425
+ x: 4000,
+ y: 1500
},
- // Right connector
- // Ground level foundation
+ // Right lower
{
- x: 400,
- y: 2000
+ x: 4400,
+ y: 1200
},
- // Left ground
+ // Far right upper
{
- x: 800,
- y: 2000
+ x: 4800,
+ y: 1000
},
- //
+ // Far right peak
{
- x: 1200,
- y: 2000
+ x: 5200,
+ y: 1300
},
- // Central ground
+ // Extended plateau
{
- x: 1600,
- y: 2000
+ x: 5600,
+ y: 1400
},
- //
+ // Final ascent
{
- x: 2000,
- y: 2000
+ x: 6000,
+ y: 1100
+ } // End platform
+ ];
+ // Door positions based on layout guide
+ var doorPositions = [{
+ platformIndex: 2,
+ isShop: true
},
- //
+ // Bottom left shop door
{
- x: 2400,
- y: 2000
+ platformIndex: 5,
+ isShop: false
},
- //
+ // Mid level door
{
- x: 2800,
- y: 2000
- },
- //
- {
- x: 3200,
- y: 2000
- },
- //
- {
- x: 3600,
- y: 2000
- },
- // Right ground
- {
- x: 4000,
- y: 2000
- } // Extended right
+ platformIndex: 8,
+ isShop: false
+ } // Upper right door
];
- for (var i = 0; i < platformLayout.length; i++) {
+ for (var i = 0; i < platformPositions.length; i++) {
var platform = new Platform();
- platform.x = platformLayout[i].x;
- platform.y = platformLayout[i].y;
- platform.scaleX = 1.0 + (i < 10 ? 0.1 : 0); // Slightly larger for main path
- platform.scaleY = 1.0;
+ platform.x = platformPositions[i].x;
+ platform.y = platformPositions[i].y;
platforms.push(platform);
worldContainer.addChild(platform);
+ // Ensure platform appears in foreground
+ var platformIndex = worldContainer.getChildIndex(platform);
+ worldContainer.setChildIndex(platform, worldContainer.children.length - 1);
+ // Check if this platform should have a door
+ var doorInfo = doorPositions.find(function (d) {
+ return d.platformIndex === i;
+ });
+ if (doorInfo) {
+ // Add platform beneath door for proper standing surface
+ var doorPlatform = new Platform();
+ doorPlatform.x = platform.x;
+ doorPlatform.y = platform.y + 50; // Slightly below main platform
+ doorPlatform.scale.x = 1.2;
+ platforms.push(doorPlatform);
+ worldContainer.addChild(doorPlatform);
+ // Ensure door platform is in foreground
+ var doorPlatformIndex = worldContainer.getChildIndex(doorPlatform);
+ worldContainer.setChildIndex(doorPlatform, worldContainer.children.length - 1);
+ 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;
+ door.isShop = doorInfo.isShop;
+ // Ensure door appears in front of platforms
+ var doorIndex = worldContainer.getChildIndex(door);
+ worldContainer.setChildIndex(door, worldContainer.children.length - 1);
+ if (doorInfo.isShop) {
+ doorAsset = door; // Store shop door reference
+ // Add hidesign floating over shop door
+ var hideSign = worldContainer.attachAsset('hidesign', {
+ anchorX: 0.5,
+ anchorY: 1.0,
+ x: platform.x,
+ y: platform.y - 600,
+ scaleX: 4,
+ scaleY: 4
+ });
+ hideSign.interactive = true;
+ hideSign.down = function (x, y, obj) {
+ enterShop();
+ };
+ // 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();
+ } else {
+ // Non-shop doors get random interior
+ door.interiorAsset = 'interior' + (Math.floor(Math.random() * 8) + 1);
+ door.down = function () {
+ showInterior(this.interiorAsset);
+ };
+ }
+ }
}
-}
-function generateSingleFocusedCharacters() {
- // Add only ONE character per strategic area to maintain focus
+ // Add single hunks at strategic positions - positioned away from doors
var hunkPositions = [{
- x: 1200,
- y: 1480
+ x: 1000,
+ y: 1480,
+ platformIndex: 1
},
- // Left area hunk
+ // First hunk on safe platform
{
- x: 2100,
- y: 1180
+ x: 3400,
+ y: 980,
+ platformIndex: 7
},
- // Central plateau hunk
+ // Mid level hunk - away from doors
{
- x: 3300,
- y: 1630
- } // Right area hunk
+ x: 5400,
+ y: 1280,
+ platformIndex: 13
+ } // Final hunk - clear area
];
- for (var i = 0; i < hunkPositions.length; i++) {
+ for (var h = 0; h < hunkPositions.length; h++) {
var hunk = new Hunk();
- hunk.x = hunkPositions[i].x;
- hunk.y = hunkPositions[i].y;
+ hunk.x = hunkPositions[h].x;
+ hunk.y = hunkPositions[h].y;
hunks.push(hunk);
worldContainer.addChild(hunk);
}
- // Add main shop door at central location
- var door = worldContainer.attachAsset('door', {
- anchorX: 0.5,
- anchorY: 1.0,
+ // Add stairs to connect platforms at different heights
+ var stairsPositions = [{
+ x: 600,
+ y: 1700,
+ connectsTo: {
+ x: 800,
+ y: 1600
+ }
+ }, {
+ x: 1000,
+ y: 1550,
+ connectsTo: {
+ x: 1200,
+ y: 1500
+ }
+ }, {
x: 1800,
- y: 1180,
- scaleX: 0.8,
- scaleY: 0.8
- });
- door.interactive = true;
- door.down = function () {
- enterShop();
- };
- doorAsset = door;
- // Add floating shop sign
- var hideSign = worldContainer.attachAsset('hidesign', {
- anchorX: 0.5,
- anchorY: 1.0,
- x: 1800,
- y: 900,
- scaleX: 3.5,
- scaleY: 3.5
- });
- hideSign.interactive = true;
- hideSign.down = function () {
- enterShop();
- };
- // Animate shop sign floating
- function animateShopSign() {
- tween(hideSign, {
- y: 850
- }, {
- duration: 2000,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- tween(hideSign, {
- y: 900
- }, {
- duration: 2000,
- easing: tween.easeInOut,
- onFinish: animateShopSign
- });
- }
- });
- }
- animateShopSign();
- // Add door2 and door3 with interior spaces
- var door2 = worldContainer.attachAsset('door2', {
- anchorX: 0.5,
- anchorY: 1.0,
- x: 2800,
- y: 1200,
- scaleX: 1.0,
- scaleY: 1.0
- });
- door2.interactive = true;
- door2.down = function () {
- var interiorTypes = ['interior2', 'interior3', 'interior4'];
- var selectedInterior = interiorTypes[Math.floor(Math.random() * interiorTypes.length)];
- showInterior(selectedInterior);
- };
- var door3 = worldContainer.attachAsset('door3', {
- anchorX: 0.5,
- anchorY: 1.0,
- x: 900,
- y: 1650,
- scaleX: 1.2,
- scaleY: 1.2
- });
- door3.interactive = true;
- door3.down = function () {
- var interiorTypes = ['interior5', 'interior6', 'interior7', 'interior8'];
- var selectedInterior = interiorTypes[Math.floor(Math.random() * interiorTypes.length)];
- showInterior(selectedInterior);
- };
- // Store door references globally for interaction detection
- window.door2Asset = door2;
- window.door3Asset = door3;
-}
-function generateMinimalAestheticElements() {
- // Add only essential decorative elements that enhance without cluttering
- var aestheticElements = [{
- asset: 'building',
- x: 700,
- y: 2000,
- scale: 1.0
+ y: 1450,
+ connectsTo: {
+ x: 2000,
+ y: 1400
+ }
}, {
- asset: 'building3',
- x: 1400,
- y: 2000,
- scale: 0.8
+ x: 2200,
+ y: 1250,
+ connectsTo: {
+ x: 2400,
+ y: 1200
+ }
}, {
- asset: 'statue',
- x: 2000,
- y: 2000,
- scale: 1.2
+ x: 2600,
+ y: 1050,
+ connectsTo: {
+ x: 2800,
+ y: 1000
+ }
}, {
- asset: 'building4',
- x: 2800,
- y: 2000,
- scale: 0.9
+ x: 3400,
+ y: 1150,
+ connectsTo: {
+ x: 3600,
+ y: 1300
+ }
}, {
- asset: 'crystal',
- x: 1800,
+ x: 4200,
+ y: 1350,
+ connectsTo: {
+ x: 4400,
+ y: 1200
+ }
+ }, {
+ x: 4600,
+ y: 1050,
+ connectsTo: {
+ x: 4800,
+ y: 1000
+ }
+ }];
+ for (var i = 0; i < stairsPositions.length; i++) {
+ var stairs = new Stairs();
+ stairs.x = stairsPositions[i].x;
+ stairs.y = stairsPositions[i].y;
+ // Scale stairs based on height difference
+ var heightDiff = Math.abs(stairsPositions[i].y - stairsPositions[i].connectsTo.y);
+ stairs.scale.x = 0.8;
+ stairs.scale.y = 0.6 + heightDiff / 300 * 0.4;
+ // Rotate stairs to point toward connected platform
+ var dx = stairsPositions[i].connectsTo.x - stairsPositions[i].x;
+ if (dx < 0) {
+ stairs.scale.x = -0.8; // Flip stairs if going left
+ }
+ worldContainer.addChild(stairs);
+ // Ensure stairs appear behind platforms but in front of backgrounds
+ var stairsIndex = worldContainer.getChildIndex(stairs);
+ worldContainer.setChildIndex(stairs, Math.max(10, stairsIndex - 20));
+ }
+ // Add hunks inside interiors for immersion
+ var interiorHunks = [{
+ x: 2400,
y: 1000,
- scale: 1.5
+ interior: true
}, {
- asset: 'neonSign',
- x: 1000,
- y: 1400,
- scale: 0.7
- }, {
- asset: 'neonsign2',
- x: 3000,
- y: 1400,
- scale: 0.7
+ x: 4200,
+ y: 900,
+ interior: true
}];
- for (var i = 0; i < aestheticElements.length; i++) {
- var elem = aestheticElements[i];
- var aesthetic = worldContainer.attachAsset(elem.asset, {
- anchorX: 0.5,
- anchorY: 1.0,
- x: elem.x,
- y: elem.y,
- scaleX: elem.scale,
- scaleY: elem.scale
- });
- aesthetic.alpha = 0.7 + Math.random() * 0.2;
- backgroundElements.push(aesthetic);
- worldContainer.setChildIndex(aesthetic, 3);
+ for (var ih = 0; ih < interiorHunks.length; ih++) {
+ var interiorHunk = new Hunk();
+ interiorHunk.x = interiorHunks[ih].x;
+ interiorHunk.y = interiorHunks[ih].y;
+ interiorHunk.isInterior = true;
+ hunks.push(interiorHunk);
+ worldContainer.addChild(interiorHunk);
}
-}
-function initializePlayerAndLayering() {
- // Initialize player character
bloodmage = new Bloodmage();
- bloodmage.x = 600; // Start on first platform
+ bloodmage.x = 400; // Start on first platform
bloodmage.y = 1780;
- // CRITICAL: Set player on platform immediately to prevent falling
- bloodmage.grounded = true;
- bloodmage.velocityY = 0;
- bloodmage.velocityX = 0;
- bloodmage.isMoving = false;
- bloodmage.isJumping = false;
- bloodmage.isFlying = false;
+ bloodmage.grounded = true; // Ensure character starts on ground
+ bloodmage.isMoving = false; // Ensure character is not moving
+ bloodmage.isJumping = false; // Ensure character is not jumping
+ bloodmage.isFlying = false; // Ensure character is not flying
worldContainer.addChild(bloodmage);
- // FIXED: Force idle state immediately to prevent falling animation
+ // CRITICAL: Ensure player appears in front of ALL background elements
+ var playerIndex = worldContainer.getChildIndex(bloodmage);
+ worldContainer.setChildIndex(bloodmage, worldContainer.children.length - 1);
+ // COMPLETELY REBUILT ANIMATION INITIALIZATION
+ // Set initial state
bloodmage.currentAnimationState = 'idle';
bloodmage.currentIdleFrame = 0;
bloodmage.idleAnimationDirection = 1;
- // Clear all other animations and show only idle
+ bloodmage.isMoving = false;
+ bloodmage.isJumping = false;
+ bloodmage.isFlying = false;
+ // Clear ALL animations and timers
bloodmage.clearAllAnimations();
- // Immediately show first idle frame before any other animation can start
- if (bloodmage.idleFrames && bloodmage.idleFrames.length > 0) {
+ // Verify idle frames exist and are properly set up (playeridle to playeridle12)
+ if (bloodmage.idleFrames.length >= 6) {
+ // Show ONLY the first idle frame (playeridle)
bloodmage.idleFrames[0].alpha = 1;
- // Start idle animation in next frame to ensure proper state
+ bloodmage.currentIdleFrame = 0;
+ // Start proper idle animation immediately
LK.setTimeout(function () {
- if (bloodmage.grounded && !bloodmage.isMoving) {
- bloodmage.startIdleAnimation();
- }
- }, 50);
+ bloodmage.startIdleAnimation();
+ }, 300); // Slight delay to ensure everything is initialized
}
- // Ensure proper layering hierarchy
- ensureProperLayering();
- // Set generation tracking
- lastGeneratedX = 4500;
+ // Generate initial Holocosmos area north of Nocturne City
+ generateLevelChunk(8000); // Generate Holocosmos area beyond main city
+ // Track initial generation position
+ lastGeneratedX = 10500; // Extended to accommodate Holocosmos area
}
-// Use assetmanager as the only asset management UI/tools for asset placement
-var globalAssetsManager = null;
-function showAssetsManager() {
- if (globalAssetsManager && globalAssetsManager.isActive) {
- return;
+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;
}
- globalAssetsManager = new AssetsManager();
- globalAssetsManager.init();
- globalAssetsManager.show();
-}
-// Show assetmanager immediately on game start
-globalAssetsManager = new AssetsManager();
-globalAssetsManager.init();
-globalAssetsManager.show();
-// Initialize player inventory
-window.playerInventory = new Inventory();
-function showInventory() {
- if (inventoryShowing || battleMenuVisible || bropageShowing || shopShowing) {
- return;
- }
- inventoryShowing = true;
- inventoryOverlay = game.addChild(new Container());
- // Create inventory background
- var invBg = inventoryOverlay.attachAsset('brostiarybox', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 1024,
- y: 1366,
- scaleX: 15,
- scaleY: 20,
- alpha: 0.9
- });
- // Add title
- var titleText = new Text2('INVENTORY', {
- size: 100,
- fill: 0xFFFFFF,
- fontWeight: 'bold'
- });
- titleText.anchor.set(0.5, 0.5);
- titleText.x = 1024;
- titleText.y = 500;
- inventoryOverlay.addChild(titleText);
- // Create inventory grid
- var itemNames = Object.keys(window.playerInventory.items);
- var slotsPerRow = 5;
- var slotSize = 120;
- var startX = 1024 - slotsPerRow * slotSize / 2;
- var startY = 800;
- for (var row = 0; row < 4; row++) {
- for (var col = 0; col < slotsPerRow; col++) {
- var slotIndex = row * slotsPerRow + col;
- var slotX = startX + col * slotSize;
- var slotY = startY + row * slotSize;
- // Create slot background
- var slot = inventoryOverlay.attachAsset('platshelf', {
+ trackpadThumb.x = 200;
+ trackpadThumb.y = -200;
+};
+jumpBtn.down = function () {
+ if (bloodmage && !battleMenuVisible && !bropageShowing && !shopShowing) {
+ jumpButtonHeld = true;
+ jumpHoldStartTime = Date.now();
+ var _animateButtonBlink = function animateButtonBlink() {
+ if (currentBlinkFrame < blinkFrames.length) {
+ var frameAsset = LK.getAsset(blinkFrames[currentBlinkFrame], {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ 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;
+ 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();
+ }
+ }
+ });
+ }
+ });
+ }
+ };
+ var blinkFrames = ['buttonblink', 'buttonblink2', 'buttonblink3', 'buttonblink4'];
+ var currentBlinkFrame = 0;
+ _animateButtonBlink();
+ var currentTime = Date.now();
+ var timeSinceLastJump = currentTime - bloodmage.lastJumpTime;
+ // Check for double tap timing - but only if finger held down on second tap
+ if (timeSinceLastJump < doubleTapThreshold && bloodmage.jumpCount === 1) {
+ // Double tap detected - check if this is being held for flight
+ // Start flight mode immediately on double tap detection
+ bloodmage.isFlying = true;
+ isFlying = true;
+ // Strong initial upward boost for flight initiation
+ bloodmage.velocityY = -12; // Stronger boost to feel responsive
+ bloodmage.grounded = false;
+ bloodmage.startFlyAnimation();
+ LK.getSound('jump').play();
+ bloodmage.jumpCount = 0;
+ // Add visual flight initiation effect
+ var flightEffect = worldContainer.attachAsset('spell2', {
anchorX: 0.5,
anchorY: 0.5,
- x: slotX,
- y: slotY,
- scaleX: 1.5,
- scaleY: 1.5,
- alpha: 0.7
+ x: bloodmage.x,
+ y: bloodmage.y - 10,
+ alpha: 0.9,
+ scaleX: 0.8,
+ scaleY: 0.8
});
- // Add item if available
- if (slotIndex < itemNames.length) {
- var itemName = itemNames[slotIndex];
- var quantity = window.playerInventory.items[itemName];
- var itemAsset = inventoryOverlay.attachAsset(itemName, {
- anchorX: 0.5,
- anchorY: 0.5,
- x: slotX,
- y: slotY,
- scaleX: 0.8,
- scaleY: 0.8
- });
- // Add quantity text
- if (quantity > 1) {
- var qtyText = new Text2(quantity.toString(), {
- size: 30,
- fill: 0xFFFF00,
- fontWeight: 'bold'
- });
- qtyText.anchor.set(0.5, 0.5);
- qtyText.x = slotX + 40;
- qtyText.y = slotY + 40;
- inventoryOverlay.addChild(qtyText);
+ tween(flightEffect, {
+ alpha: 0,
+ scaleX: 2.0,
+ scaleY: 2.0
+ }, {
+ duration: 600,
+ easing: tween.easeOut,
+ onFinish: function onFinish() {
+ flightEffect.destroy();
}
+ });
+ } else {
+ // Normal jump attempt - record this as first tap
+ var jumpSuccess = bloodmage.jump();
+ if (jumpSuccess) {
+ bloodmage.lastJumpTime = currentTime;
+ bloodmage.jumpCount = 1; // Mark as first jump for double-tap detection
}
}
}
- // Add close button
- var closeBtn = inventoryOverlay.attachAsset('x', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 1700,
- y: 400,
- scaleX: 2,
- scaleY: 2
- });
- closeBtn.interactive = true;
- closeBtn.down = function () {
- closeInventory();
- };
-}
-function closeInventory() {
- if (!inventoryShowing || !inventoryOverlay) {
- return;
+};
+jumpBtn.up = function () {
+ if (jumpButtonHeld && isFlying && bloodmage) {
+ // Release flight mode with graceful descent
+ jumpButtonHeld = false;
+ isFlying = false;
+ bloodmage.isFlying = false;
+ bloodmage.stopFlyAnimation();
+ bloodmage.startFallAnimation();
+ // Apply realistic falling physics with parabolic arc
+ var currentUpwardVelocity = Math.min(bloodmage.velocityY, 0);
+ bloodmage.velocityY = Math.max(currentUpwardVelocity, 3); // Gentle fall start
+ // Maintain some horizontal momentum for natural arc
+ bloodmage.velocityX *= 0.7; // Slight air resistance
+ // Add falling visual effect
+ var fallEffect = worldContainer.attachAsset('spell', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: bloodmage.x,
+ y: bloodmage.y - 20,
+ alpha: 0.6,
+ scaleX: 1.5,
+ scaleY: 0.8
+ });
+ tween(fallEffect, {
+ alpha: 0,
+ y: bloodmage.y + 50,
+ scaleX: 0.8,
+ scaleY: 1.2
+ }, {
+ duration: 800,
+ easing: tween.easeIn,
+ onFinish: function onFinish() {
+ fallEffect.destroy();
+ }
+ });
}
- inventoryShowing = false;
- inventoryOverlay.destroy();
- inventoryOverlay = null;
-}
-var inventoryShowing = false;
-var inventoryOverlay = null;
+ jumpButtonHeld = false;
+};
+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();
+ }
+ }
+};
+// Score text removed - using Brostiary for hunk tracking instead
+// 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;
@@ -6567,11 +2352,9 @@
description: 'LEGENDARY HEART OF POWER',
useDisplay: true
}];
function showBropage() {
- if (bropageShowing || battleMenuVisible) {
- return;
- }
+ if (bropageShowing || battleMenuVisible) return;
bropageShowing = true;
currentBropageIndex = 0;
// Create overlay container
bropageOverlay = game.addChild(new Container());
@@ -6761,11 +2544,9 @@
// Display first entry
_displayHunkEntry();
}
function closeBropage() {
- if (!bropageShowing || !bropageOverlay) {
- return;
- }
+ if (!bropageShowing || !bropageOverlay) return;
bropageShowing = false;
bropageOverlay.destroy();
bropageOverlay = null;
}
@@ -6788,11 +2569,9 @@
};
}
}
function enterShop() {
- if (shopShowing || battleMenuVisible) {
- return;
- }
+ if (shopShowing || battleMenuVisible) return;
shopShowing = true;
currentShopPage = 0;
// Create transition overlay
var transitionOverlay = game.addChild(new Container());
@@ -7038,10 +2817,10 @@
}, {
duration: 600,
easing: tween.easeOut
});
- // Add currency display using simple counter
- var currencyText = new Text2('GOLD: ' + capturedHunkCount * 10, {
+ // Add currency display using gold coins instead
+ var currencyText = new Text2('GOLD: ' + capturedHunks.length * 10, {
size: 100,
fill: 0xFFD700,
fontWeight: 'bold'
});
@@ -7245,37 +3024,47 @@
enterShop();
}
function purchaseItem(itemIndex) {
var item = shopItems[itemIndex];
- var goldAmount = capturedHunkCount * 10;
+ var goldAmount = capturedHunks.length * 10;
if (goldAmount >= item.price) {
- // Deduct from captured hunk count
+ // Calculate how many hunks to remove based on price
var hunksToRemove = Math.ceil(item.price / 10);
- capturedHunkCount = Math.max(0, capturedHunkCount - hunksToRemove);
- storage.capturedHunkCount = capturedHunkCount;
- // Add to inventory
- playerItems++;
- storage.playerItems = playerItems;
+ for (var i = 0; i < hunksToRemove && capturedHunks.length > 0; i++) {
+ capturedHunks.pop();
+ }
+ storage.capturedHunks = capturedHunks;
+ // Score text was removed, no need to update
// 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;
- }
+ if (!shopShowing || !shopOverlay) return;
shopShowing = false;
shopOverlay.destroy();
shopOverlay = null;
}
function castPlayerSpell() {
- if (!bloodmage || isCasting) {
- return;
- }
+ if (!bloodmage || isCasting) return;
isCasting = true;
LK.getSound('spell').play();
// Stop all animations first
bloodmage.stopIdleAnimation();
@@ -7380,100 +3169,52 @@
if (bloodmage) {
var targetX = -bloodmage.x + 1024;
var targetY = -bloodmage.y + 1366;
cameraX += (targetX - cameraX) * 0.1;
- cameraY += (targetY - cameraY) * 0.1;
+ // Add vertical camera tracking for flight mode
+ var currentCameraY = worldContainer.y || 0;
+ currentCameraY += (targetY - currentCameraY) * 0.1;
worldContainer.x = cameraX;
- worldContainer.y = cameraY;
- // Apply subtle parallax effects
- var isPlayerMoving = Math.abs(bloodmage.velocityX) > 0.1 || Math.abs(bloodmage.velocityY) > 0.5;
- if (isPlayerMoving) {
- for (var i = 0; i < backgroundElements.length; i++) {
- var element = backgroundElements[i];
- if (element.parallaxSpeed !== undefined && element.baseX !== undefined) {
- var parallaxX = cameraX * element.parallaxSpeed * 0.05;
- var parallaxY = cameraY * element.parallaxSpeed * 0.02;
- element.x += (element.baseX + parallaxX - element.x) * 0.01;
- element.y += (element.baseY + parallaxY - element.y) * 0.005;
- }
- }
- }
+ worldContainer.y = currentCameraY;
}
}
function checkCollisions() {
- if (!bloodmage) {
- return;
- }
+ if (!bloodmage) return;
bloodmage.grounded = false;
- var playerWidth = 80;
- var playerHeight = 120;
for (var i = 0; i < platforms.length; i++) {
var platform = platforms[i];
- // Enhanced platform collision detection with proper bounds
- var platWidth = platform.width || 500;
- var platHeight = platform.height || 50;
- var platScale = platform.scaleX || 1.0;
- var platLeft = platform.x - platWidth * platScale / 2;
- var platRight = platform.x + platWidth * platScale / 2;
- var platTop = platform.y - platHeight / 2;
- var platBottom = platform.y + platHeight / 2;
- var mageLeft = bloodmage.x - playerWidth / 2;
- var mageRight = bloodmage.x + playerWidth / 2;
- var mageTop = bloodmage.y - playerHeight;
+ 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;
- // Enhanced collision detection for landing on platforms
- if (mageRight > platLeft && mageLeft < platRight && mageBottom >= platTop && mageTop < platBottom) {
- // Only land if falling down onto the platform
- if (bloodmage.velocityY >= 0 && mageBottom - bloodmage.velocityY <= platTop + 10) {
+ 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
- bloodmage.doubleJumpAvailable = true; // Reset double jump when landing
- // Stop fall animation and return to appropriate state
- if (bloodmage.currentAnimationState === 'fall') {
- bloodmage.stopFallAnimation();
- bloodmage.currentAnimationState = 'idle';
- bloodmage.startIdleAnimation();
- }
- break; // Exit loop once landed
}
}
}
- // Enhanced collision detection for animated platforms
- for (var i = 0; i < platforms.length; i++) {
- var platform = platforms[i];
- if (platform.visual && platform.visual.x !== undefined) {
- // Use visual position for animated platforms
- var platLeft = platform.visual.x - 250;
- var platRight = platform.visual.x + 250;
- var platTop = platform.visual.y - 25;
- var platBottom = platform.visual.y + 25;
- 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 + 10) {
- bloodmage.y = platTop;
- bloodmage.velocityY = 0;
- bloodmage.grounded = true;
- bloodmage.jumpCount = 0;
- break;
- }
- }
- }
+ 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;
- }
+ if (battleMenuVisible || !currentHunk) return;
battleMenuVisible = true;
// Create combat menu properly positioned and sized between trackpad and buttons
combatMenuUI = game.attachAsset('combatmenu', {
anchorX: 0.5,
@@ -7516,11 +3257,9 @@
window.currentCombatMenu = combatMenuUI;
window.currentCursor = cursorUI;
}
function hideBattleUI() {
- if (!battleMenuVisible) {
- return;
- }
+ if (!battleMenuVisible) return;
battleMenuVisible = false;
if (combatMenuUI) {
combatMenuUI.destroy();
combatMenuUI = null;
@@ -7537,11 +3276,9 @@
currentHunk = hunk;
battleHunk = hunk;
}
function castSpell(damage) {
- if (!currentHunk) {
- return;
- }
+ 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);
@@ -7566,97 +3303,37 @@
}
});
}
function attemptCapture() {
- if (!currentHunk) {
- return;
- }
+ if (!currentHunk) return;
if (currentHunk.resistance < 30) {
LK.getSound('capture').play();
- // Dramatic transformation into crystal gem
- var beastData = beastMenData[currentHunk.hunkType];
- var gemColors = [0xFF00FF, 0x00FFFF, 0xFFFF00, 0xFF0088]; // Kinky neon colors
- // Create swirling transformation effect
- var transformEffect = worldContainer.attachAsset('spell4', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: currentHunk.x,
- y: currentHunk.y,
- scaleX: 0.5,
- scaleY: 0.5,
- alpha: 0.9,
- tint: gemColors[currentHunk.hunkType]
- });
- // Transformation animation
- tween(transformEffect, {
- scaleX: 3.0,
- scaleY: 3.0,
- rotation: Math.PI * 4,
- alpha: 0.3
- }, {
- duration: 2000,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- // Create crystal gem
- var crystalGem = worldContainer.attachAsset('crystal', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: currentHunk.x,
- y: currentHunk.y - 50,
- scaleX: 2.0,
- scaleY: 2.0,
- tint: gemColors[currentHunk.hunkType]
- });
- // Floating crystal animation
- tween(crystalGem, {
- y: crystalGem.y - 200,
- rotation: Math.PI * 2,
- alpha: 0.8
- }, {
- duration: 1500,
- easing: tween.easeOut,
- onFinish: function onFinish() {
- crystalGem.destroy();
- }
- });
- transformEffect.destroy();
- }
- });
currentHunk.captured = true;
currentHunk.visible = false;
- // Add to thrall collection
- var thrallData = {
- type: currentHunk.hunkType,
- name: beastData ? beastData.name : 'MYSTERIOUS BEAST',
- gemColor: gemColors[currentHunk.hunkType],
- captureTime: Date.now()
- };
- thralls.push(thrallData);
+ // 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;
- storage.thralls = thralls;
if (!brostiary[currentHunk.hunkType]) {
brostiary[currentHunk.hunkType] = true;
storage.brostiary = brostiary;
}
- // Show dramatic capture message
- showCaptureMessage(beastData);
+ // scoreText removed - using Brostiary for hunk tracking instead
+ // Hide battle UI after capture
hideBattleUI();
currentHunk = null;
- if (capturedHunks.length >= 4) {
+ // Don't teleport player - they stay at current position
+ if (capturedHunks.length >= 10) {
LK.showYouWin();
}
} else {
- // Resistance too high - dramatic rejection
+ // Flash screen red for failed capture
LK.effects.flashScreen(0xFF0000, 500);
- showResistanceMessage();
}
}
game.down = function (x, y, obj) {
- // Don't handle game interactions if assets manager is active
- if (globalAssetsManager && globalAssetsManager.isActive) {
- return;
- }
// 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 2.8x1.8)
var menuLeft = 1024 - 350; // Full width of scaled menu (250 * 2.8 scale)
@@ -7704,45 +3381,21 @@
return;
}
return;
}
- if (bropageShowing || shopShowing) {
- 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
});
- // Check main shop door
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;
}
}
- // Check door2
- if (window.door2Asset) {
- var door2Distance = Math.sqrt(Math.pow(worldPos.x - window.door2Asset.x, 2) + Math.pow(worldPos.y - window.door2Asset.y, 2));
- if (door2Distance < 200) {
- var interiorTypes = ['interior2', 'interior3', 'interior4'];
- var selectedInterior = interiorTypes[Math.floor(Math.random() * interiorTypes.length)];
- showInterior(selectedInterior);
- return;
- }
- }
- // Check door3
- if (window.door3Asset) {
- var door3Distance = Math.sqrt(Math.pow(worldPos.x - window.door3Asset.x, 2) + Math.pow(worldPos.y - window.door3Asset.y, 2));
- if (door3Distance < 200) {
- var interiorTypes = ['interior5', 'interior6', 'interior7', 'interior8'];
- var selectedInterior = interiorTypes[Math.floor(Math.random() * interiorTypes.length)];
- showInterior(selectedInterior);
- return;
- }
- }
- // Check shop sign
if (hideSignAsset) {
var signDistance = Math.sqrt(Math.pow(worldPos.x - hideSignAsset.x, 2) + Math.pow(worldPos.y - hideSignAsset.y, 2));
if (signDistance < 150) {
enterShop();
@@ -7910,11 +3563,9 @@
showShop();
}
};
game.move = function (x, y, obj) {
- if (!trackpadPressed || battleMenuVisible || bropageShowing || shopShowing) {
- return;
- }
+ if (!trackpadPressed || battleMenuVisible || bropageShowing || shopShowing) return;
updateTrackpad(x, y);
};
game.up = function () {
// Handle jump button release for flight mode
@@ -7994,490 +3645,44 @@
bloodmage.velocityX = 0;
bloodmage.velocityY = 0;
bloodmage.grounded = false;
// Update facing direction
- if (moveX > 0) {
- bloodmage.facingDirection = -1;
- } else if (moveX < 0) {
- bloodmage.facingDirection = 1;
- }
+ if (moveX > 0) bloodmage.facingDirection = -1;else if (moveX < 0) bloodmage.facingDirection = 1;
} else {
// Ground movement - horizontal only
bloodmage.velocityX = dx / 80 * bloodmage.speed * 3.5;
}
}
}
game.update = function () {
- // Pause game updates when assets manager is active
- if (globalAssetsManager && globalAssetsManager.isActive) {
- return;
- }
- if (!battleMenuVisible && bloodmage) {
+ if (!battleMenuVisible) {
checkCollisions();
updateCamera();
- updateInfiniteWorldGeneration();
- updateEnvironmentalEffects();
- updateClouds();
- cleanupDistantElements();
- ensureProperLayering(); // Maintain visual hierarchy
- }
- // Update spell projectiles
- for (var i = spellProjectiles.length - 1; i >= 0; i--) {
- var projectile = spellProjectiles[i];
- projectile.x += projectile.velocity;
- // Remove off-screen projectiles
- var screenLeft = -cameraX - 500;
- var screenRight = -cameraX + 2548;
- if (projectile.x < screenLeft || projectile.x > screenRight) {
- projectile.destroy();
- spellProjectiles.splice(i, 1);
- continue;
+ // 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 collision with hunks
- for (var j = 0; j < hunks.length; j++) {
- var hunk = hunks[j];
- if (!hunk.captured && projectile.intersects(hunk)) {
- hunk.resistance = Math.max(0, hunk.resistance - 25);
- // Visual effect
- var effect = worldContainer.attachAsset('spell2', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: hunk.x,
- y: hunk.y - 50,
- alpha: 1
- });
- tween(effect, {
- alpha: 0,
- scaleX: 2,
- scaleY: 2,
- rotation: Math.PI * 2
- }, {
- duration: 500,
- easing: tween.easeOut,
- onFinish: function onFinish() {
- effect.destroy();
- }
- });
- LK.effects.flashObject(hunk, 0xFF00FF, 300);
- projectile.destroy();
- spellProjectiles.splice(i, 1);
- break;
- }
+ // Check if we need to generate more level
+ if (bloodmage && bloodmage.x > lastGeneratedX - 2000) {
+ generateLevelChunk(lastGeneratedX);
+ cleanupOldElements();
}
}
- function updateInfiniteWorldGeneration() {
- if (!bloodmage) {
- return;
- }
- // Only generate city content and disable other biome generation for now
- // This ensures only Nocturne City assets are visible at game start
- // Update animated platforms
- updateAnimatedPlatforms();
- // Keep biome as city only
- var currentBiome = 'city';
- if (currentBiome !== lastBiome) {
- lastBiome = currentBiome;
- }
- }
- function updateAnimatedPlatforms() {
- for (var i = 0; i < platforms.length; i++) {
- var platform = platforms[i];
- if (platform.circularSpeed && platform.circularRadius) {
- // Update circular motion platforms
- platform.circularOffset += platform.circularSpeed;
- var newX = platform.originalX + Math.cos(platform.circularOffset) * platform.circularRadius;
- var newY = platform.originalY + Math.sin(platform.circularOffset) * platform.circularRadius * 0.5;
- platform.x = newX;
- platform.y = newY;
- if (platform.visual) {
- platform.visual.x = newX;
- platform.visual.y = newY - 20;
- }
- }
- }
- }
- function onBiomeTransition(fromBiome, toBiome) {
- var biomeColors = {
- city: 0xAAAABB,
- cosmic: 0xDDDDFF,
- forest: 0xCCFFCC,
- sea: 0xCCEEFF,
- under: 0xFFDDDD
- };
- // Visual transition effect
- LK.effects.flashScreen(biomeColors[toBiome] || 0xFFFFFF, 1000);
- // Show animated biome name using NOCTURNE CITY style
- showAnimatedBiomeName(toBiome);
- }
- function showAnimatedBiomeName(biomeName) {
- var biomeNames = {
- city: 'NOCTURNE CITY',
- cosmic: 'HOLOCOSMOS',
- forest: 'SIMULIMINA FOREST',
- sea: 'INFINISEA',
- under: 'UNDERDEEP'
- };
- var displayName = biomeNames[biomeName] || biomeName.toUpperCase();
- var letters = [];
- var words = displayName.split(' '); // Split into words to handle spacing
- // Build letter array with proper word positioning
- var totalLetters = 0;
- for (var w = 0; w < words.length; w++) {
- var word = words[w];
- for (var i = 0; i < word.length; i++) {
- var _char = word[i].toLowerCase();
- if (_char >= 'a' && _char <= 'z') {
- letters.push({
- "char": _char,
- wordIndex: w,
- letterIndex: i,
- globalIndex: totalLetters
- });
- totalLetters++;
- }
- }
- // Add space between words (except after last word)
- if (w < words.length - 1) {
- totalLetters += 1; // Space between words
- }
- }
- if (letters.length === 0) {
- return;
- }
- // Create title container using NOCTURNE CITY animation style
- var titleContainer = game.addChild(new Container());
- var targetY = 600;
- var letterAssets = [];
- // Calculate positioning for each word with increased letter spacing to prevent overlap
- var wordStartPositions = [];
- var currentX = 0;
- for (var w = 0; w < words.length; w++) {
- wordStartPositions[w] = currentX;
- currentX += words[w].length * 180; // Increased from 140px to 180px per letter for proper spacing
- if (w < words.length - 1) {
- currentX += 300;
- } // Increased space between words from 200 to 300
- }
- // Center all words as a group
- var totalWidth = currentX - 300; // Remove last space
- var startX = 1024 - totalWidth / 2;
- // Create all letters starting from right side for squeeze effect
- for (var i = 0; i < letters.length; i++) {
- var letterData = letters[i];
- var wordStartX = startX + wordStartPositions[letterData.wordIndex];
- var finalX = wordStartX + letterData.letterIndex * 180; // Increased letter spacing to 180px
- var letter = titleContainer.attachAsset(letterData["char"], {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 2500,
- // Start from right side for squeeze effect
- y: targetY,
- scaleX: 0.5,
- scaleY: 0.5,
- alpha: 0
- });
- letter.finalX = finalX;
- letterAssets.push(letter);
- }
- // Animate letters with wave momentum and squeeze effect like NOCTURNE CITY
- function animateSqueezeIn() {
- for (var i = 0; i < letterAssets.length; i++) {
- var letter = letterAssets[i];
- // Each letter appears with staggered timing for wave effect
- (function (index, targetLetter) {
- LK.setTimeout(function () {
- // Fade in letter
- tween(targetLetter, {
- alpha: 1
- }, {
- duration: 200,
- easing: tween.easeOut
- });
- // Squeeze animation - expand and move to final position
- tween(targetLetter, {
- x: targetLetter.finalX,
- scaleX: 3.5,
- scaleY: 3.5
- }, {
- duration: 600,
- easing: tween.bounceOut // Wave momentum effect
- });
- }, index * 120); // Staggered timing
- })(i, letter);
- }
- // Hold for 3 seconds then slide out left to right
- LK.setTimeout(function () {
- animateLettersOut();
- }, 3500);
- }
- // Animate letters fading out from left to right
- function animateLettersOut() {
- for (var i = 0; i < letterAssets.length; i++) {
- (function (index, targetLetter) {
- LK.setTimeout(function () {
- tween(targetLetter, {
- alpha: 0,
- y: 1000,
- scaleX: 1.0,
- scaleY: 1.0
- }, {
- duration: 300,
- easing: tween.easeIn
- });
- }, index * 80);
- })(i, letterAssets[i]);
- }
- // Clean up after fade
- LK.setTimeout(function () {
- titleContainer.destroy();
- }, 2000);
- }
- // Start the squeeze animation
- animateSqueezeIn();
- }
- function updateEnvironmentalEffects() {
- for (var i = 0; i < environmentalEffects.length; i++) {
- var effect = environmentalEffects[i];
- if (!effect || effect.destroyed) {
- continue;
- }
- // Biome-specific animations
- if (effect.biome === 'cosmic' && effect.rotationSpeed) {
- effect.rotation += effect.rotationSpeed;
- } else if (effect.biome === 'sea') {
- effect.x += Math.cos(Date.now() * 0.001) * 0.3;
- effect.y += Math.sin(Date.now() * 0.0008) * 0.2;
- } else if (effect.biome === 'forest' && effect.blinkTimer) {
- if (Date.now() % effect.blinkTimer < 100) {
- effect.alpha = 0.2;
- } else {
- effect.alpha = 0.6;
- }
- }
- }
- }
- function updateClouds() {
- for (var i = 0; i < clouds.length; i++) {
- var cloud = clouds[i];
- if (!cloud || cloud.destroyed) {
- continue;
- }
- // Drift clouds left to right
- cloud.x += cloud.driftSpeed || 1.0;
- // Wrap around screen
- var screenRight = -cameraX + 2548;
- var screenLeft = -cameraX - 500;
- if (cloud.x > screenRight + 300) {
- cloud.x = screenLeft - 300;
- cloud.y = 1000 + Math.random() * 800;
- }
- }
- }
- function cleanupDistantElements() {
- if (!bloodmage) {
- return;
- }
- var playerX = bloodmage.x;
- var playerY = bloodmage.y;
- var cleanupDistance = 5000;
- // Clean up background elements
- for (var i = backgroundElements.length - 1; i >= 0; i--) {
- var element = backgroundElements[i];
- if (element && element.x !== undefined && element.y !== undefined) {
- var distance = Math.sqrt(Math.pow(element.x - playerX, 2) + Math.pow(element.y - playerY, 2));
- if (distance > cleanupDistance) {
- element.destroy();
- backgroundElements.splice(i, 1);
- }
- }
- }
- // Clean up environmental effects
- for (var i = environmentalEffects.length - 1; i >= 0; i--) {
- var effect = environmentalEffects[i];
- if (effect && effect.x !== undefined && effect.y !== undefined) {
- var distance = Math.sqrt(Math.pow(effect.x - playerX, 2) + Math.pow(effect.y - playerY, 2));
- if (distance > cleanupDistance) {
- effect.destroy();
- environmentalEffects.splice(i, 1);
- }
- }
- }
- // Clean up distant platforms (keep some for navigation)
- for (var i = platforms.length - 1; i >= 0; i--) {
- var platform = platforms[i];
- if (platform && platform.x !== undefined && platform.y !== undefined) {
- var distance = Math.sqrt(Math.pow(platform.x - playerX, 2) + Math.pow(platform.y - playerY, 2));
- if (distance > cleanupDistance) {
- platform.destroy();
- platforms.splice(i, 1);
- }
- }
- }
- // Clean up captured hunks
- for (var i = hunks.length - 1; i >= 0; i--) {
- var hunk = hunks[i];
- if (hunk && hunk.captured) {
- var distance = Math.sqrt(Math.pow(hunk.x - playerX, 2) + Math.pow(hunk.y - playerY, 2));
- if (distance > cleanupDistance) {
- hunk.destroy();
- hunks.splice(i, 1);
- }
- }
- }
- }
- function onBiomeTransition(fromBiome, toBiome) {
- var transitionColors = {
- cosmic: 0xDDDDFF,
- city: 0xAAAABB,
- forest: 0xCCFFCC,
- sea: 0xCCEEFF,
- under: 0xFFDDDD
- };
- // Visual flash effect
- LK.effects.flashScreen(transitionColors[toBiome] || 0xFFFFFF, 1000);
- // Show animated biome name using NOCTURNE CITY style
- showAnimatedBiomeName(toBiome);
- // Update storage
- unlockedBiomes = Math.max(unlockedBiomes, 5);
- storage.unlockedBiomes = unlockedBiomes;
- }
- // Animate clouds drifting consistently left to right in front of background assets
+ // Animate clouds drifting
for (var i = 0; i < clouds.length; i++) {
var cloud = clouds[i];
- // Safely ensure cloud is positioned in front of background assets - only if it's actually a child
- if (cloud && cloud.parent === worldContainer && worldContainer.children.indexOf(cloud) !== -1) {
- var targetIndex = Math.max(15, worldContainer.children.length - Math.max(hunks.length, 3));
- // Ensure target index is within valid bounds
- targetIndex = Math.min(targetIndex, worldContainer.children.length - 1);
- worldContainer.setChildIndex(cloud, targetIndex);
+ 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;
}
- // Consistent left-to-right drift
- cloud.x += cloud.driftSpeed * 1.2; // Faster, more visible drift
- // Gentle vertical floating with tween
- if (Math.random() < 0.008) {
- tween(cloud, {
- y: cloud.y + (Math.random() - 0.5) * 30,
- alpha: 0.4 + Math.random() * 0.4
- }, {
- duration: 3000 + Math.random() * 2000,
- easing: tween.easeInOut
- });
- }
- // Wrap clouds smoothly when they exit screen right
- var screenRight = -cameraX + 2548;
- var screenLeft = -cameraX - 500;
- if (cloud.x > screenRight + 300) {
- cloud.x = screenLeft - 300;
- cloud.y = 1000 + Math.random() * 800; // Mid-screen height for visibility
- cloud.alpha = 0.6 + Math.random() * 0.4; // Reset opacity
- }
}
- // Enhanced environmental effects animation system with improved tween usage
- for (var i = 0; i < environmentalEffects.length; i++) {
- var effect = environmentalEffects[i];
- if (!effect || !effect.zone || effect.destroyed) {
- continue;
- }
- // Zone-specific environmental animations with smoother tween-based effects
- if (effect.zone === 'Cosmic') {
- // Smooth cosmic rotation using tween
- if (!effect.rotationTween && effect.rotationSpeed) {
- effect.rotationTween = true;
- tween(effect, {
- rotation: effect.rotation + Math.PI * 2
- }, {
- duration: 8000,
- easing: tween.linear,
- onFinish: function onFinish() {
- effect.rotation = 0;
- effect.rotationTween = false;
- }
- });
- }
- // Gentle cosmic pulsing with tween
- if (!effect.pulseTween && Math.random() < 0.001) {
- effect.pulseTween = true;
- tween(effect, {
- scaleX: effect.scaleX * 1.2,
- scaleY: effect.scaleY * 1.2,
- alpha: effect.alpha * 1.3
- }, {
- duration: 1500,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- tween(effect, {
- scaleX: effect.scaleX / 1.2,
- scaleY: effect.scaleY / 1.2,
- alpha: effect.alpha / 1.3
- }, {
- duration: 1500,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- effect.pulseTween = false;
- }
- });
- }
- });
- }
- } else if (effect.zone === 'Forest') {
- // Smooth forest swaying with tween
- if (!effect.swayTween) {
- effect.swayTween = true;
- tween(effect, {
- rotation: 0.15
- }, {
- duration: 2000 + Math.random() * 1000,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- tween(effect, {
- rotation: -0.15
- }, {
- duration: 2000 + Math.random() * 1000,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- effect.swayTween = false;
- }
- });
- }
- });
- }
- } else if (effect.zone === 'Sea') {
- // Smooth sea wave motion
- effect.x += Math.cos(Date.now() * 0.0005) * 0.5;
- effect.y += Math.sin(Date.now() * 0.0008) * 0.3;
- } else if (effect.zone === 'Under') {
- // Gentle underground floating with tween
- if (!effect.floatTween) {
- effect.floatTween = true;
- var floatDistance = 30 + Math.random() * 40;
- tween(effect, {
- y: effect.y - floatDistance
- }, {
- duration: 3000 + Math.random() * 2000,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- tween(effect, {
- y: effect.y + floatDistance
- }, {
- duration: 3000 + Math.random() * 2000,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- effect.floatTween = false;
- }
- });
- }
- });
- }
- }
- }
- // Apply parallax movement to background elements
- for (var i = 0; i < backgroundElements.length; i++) {
- var bg = backgroundElements[i];
- if (bg.parallaxSpeed !== undefined) {
- // Parallax offset based on camera movement and layer speed
- bg.x += (cameraX - bg.x) * bg.parallaxSpeed * 0.1;
- }
- }
// Update spell projectiles
for (var i = spellProjectiles.length - 1; i >= 0; i--) {
var projectile = spellProjectiles[i];
projectile.x += projectile.velocity;
@@ -8545,11 +3750,9 @@
}
};
// Combat menu navigation functions removed - using direct touch interaction
function selectCurrentOption() {
- if (!battleMenuVisible || !currentHunk) {
- return;
- }
+ if (!battleMenuVisible || !currentHunk) return;
var selectedOption = window.currentSelectedOption;
if (selectedOption === 0) {
// Enthrall (capture function) with enhanced animations
performCaptureAnimation();
@@ -8565,11 +3768,9 @@
currentHunk = null;
}
}
function performCaptureAnimation() {
- if (!currentHunk) {
- return;
- }
+ if (!currentHunk) return;
// Store player position to prevent falling
var castX = bloodmage.x;
var castY = bloodmage.y;
var wasGrounded = bloodmage.grounded;
@@ -8635,13 +3836,14 @@
easing: tween.easeIn,
onFinish: function onFinish() {
currentHunk.captured = true;
currentHunk.visible = false;
- capturedHunkCount++;
- storage.capturedHunkCount = capturedHunkCount;
- // Simple brostiary tracking
- brostiaryEntries = Math.max(brostiaryEntries, currentHunk.hunkType + 1);
- storage.brostiaryEntries = brostiaryEntries;
+ capturedHunks.push(currentHunk.hunkType);
+ storage.capturedHunks = capturedHunks;
+ if (!brostiary[currentHunk.hunkType]) {
+ brostiary[currentHunk.hunkType] = true;
+ storage.brostiary = brostiary;
+ }
// scoreText removed - using Brostiary for hunk tracking instead
showXPMenu(true);
captureDevice.destroy();
captureEffect.destroy();
@@ -8697,11 +3899,9 @@
}
});
}
function performBattleCast() {
- if (!currentHunk) {
- return;
- }
+ if (!currentHunk) return;
// Store player position and state to prevent falling
var playerGrounded = bloodmage.grounded;
var playerX = bloodmage.x;
var playerY = bloodmage.y;
@@ -8755,25 +3955,19 @@
castSpell(25);
LK.getSound('climax').play();
// Clean up after 2 seconds
LK.setTimeout(function () {
- if (spellBehind) {
- spellBehind.destroy();
- }
- if (spellPulse) {
- spellPulse.destroy();
- }
+ if (spellBehind) spellBehind.destroy();
+ if (spellPulse) spellPulse.destroy();
// Restore player position and state
bloodmage.x = playerX;
bloodmage.y = playerY;
bloodmage.velocityY = playerGrounded ? 0 : playerVelY;
bloodmage.grounded = playerGrounded;
}, 2000);
}
function showDualDialogue() {
- if (!currentHunk) {
- return;
- }
+ if (!currentHunk) return;
// Player dialogue floating above head
var playerDialogue = worldContainer.attachAsset('dialoguebox', {
anchorX: 0.5,
anchorY: 1.0,
@@ -8852,11 +4046,9 @@
}, {
duration: 300,
easing: tween.easeIn,
onFinish: function onFinish() {
- if (playerDialogue) {
- playerDialogue.destroy();
- }
+ if (playerDialogue) playerDialogue.destroy();
}
});
tween(hunkDialogue, {
alpha: 0,
@@ -8864,263 +4056,93 @@
}, {
duration: 300,
easing: tween.easeIn,
onFinish: function onFinish() {
- if (hunkDialogue) {
- hunkDialogue.destroy();
- }
+ if (hunkDialogue) hunkDialogue.destroy();
}
});
}, 4000);
}
function showXPMenu(captureSuccess) {
- if (captureSuccess) {
- var xpOverlay = game.addChild(new Container());
- // Enhanced background with better sizing
- var xpBg = xpOverlay.attachAsset('expobox', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 1024,
- y: 1366,
- scaleX: 15,
- scaleY: 10,
- alpha: 0
- });
- // Enhanced title text
- var xpText = new Text2('THRALL CAPTURED!', {
- size: 120,
- fill: 0x00FF00,
- fontWeight: 'bold'
- });
- xpText.anchor.set(0.5, 0.5);
- xpText.x = 1024;
- xpText.y = 1200;
- xpText.alpha = 0;
- xpOverlay.addChild(xpText);
- // Experience gained text
- var expText = new Text2('EXPERIENCE GAINED: +100', {
- size: 80,
- fill: 0xFFFF00,
- fontWeight: 'bold'
- });
- expText.anchor.set(0.5, 0.5);
- expText.x = 1024;
- expText.y = 1350;
- expText.alpha = 0;
- xpOverlay.addChild(expText);
- // Brostiary updated text
- var brostiaryText = new Text2('BROSTIARY UPDATED!', {
- size: 70,
- fill: 0x00FFFF,
- fontWeight: 'bold'
- });
- brostiaryText.anchor.set(0.5, 0.5);
- brostiaryText.x = 1024;
- brostiaryText.y = 1450;
- brostiaryText.alpha = 0;
- xpOverlay.addChild(brostiaryText);
- // Continue button
- var continueBtn = new Text2('CONTINUE', {
- size: 80,
- 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 () {
- tween(xpOverlay, {
- alpha: 0
- }, {
- duration: 400,
- easing: tween.easeIn,
- onFinish: function onFinish() {
- xpOverlay.destroy();
- }
- });
- };
- xpOverlay.addChild(continueBtn);
- // Animate elements appearing in sequence
- tween(xpBg, {
- alpha: 0.9
- }, {
- duration: 600,
- easing: tween.easeOut
- });
- LK.setTimeout(function () {
- tween(xpText, {
- alpha: 1,
- scaleX: 1.1,
- scaleY: 1.1
- }, {
- duration: 500,
- easing: tween.bounceOut
- });
- }, 300);
- LK.setTimeout(function () {
- tween(expText, {
- alpha: 1
- }, {
- duration: 400,
- easing: tween.easeOut
- });
- }, 600);
- LK.setTimeout(function () {
- tween(brostiaryText, {
- alpha: 1
- }, {
- duration: 400,
- easing: tween.easeOut
- });
- }, 900);
- LK.setTimeout(function () {
- tween(continueBtn, {
- alpha: 1
- }, {
- duration: 400,
- easing: tween.easeOut
- });
- }, 1200);
- }
-}
-function showCaptureMessage(beastData) {
- var captureOverlay = game.addChild(new Container());
- // Dramatic background
- var captureBg = captureOverlay.attachAsset('expobox', {
+ // 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: 20,
- scaleY: 15,
- alpha: 0,
- tint: 0x330033 // Dark leather purple
+ scaleX: 12,
+ scaleY: 10,
+ alpha: 0
});
- tween(captureBg, {
+ tween(xpBg, {
alpha: 0.95
}, {
- duration: 800,
+ duration: 500,
easing: tween.easeOut
});
- // Transformation success message
- var transformText = new Text2('TRANSFORMATION COMPLETE!', {
- size: 120,
- fill: 0xFF00FF,
- fontWeight: 'bold'
- });
- transformText.anchor.set(0.5, 0.5);
- transformText.x = 1024;
- transformText.y = 1100;
- transformText.alpha = 0;
- captureOverlay.addChild(transformText);
- // Beast name and title
- var beastNameText = new Text2(beastData ? beastData.name : 'UNKNOWN BEAST', {
- size: 90,
- fill: 0xFFFF00,
- fontWeight: 'bold'
- });
- beastNameText.anchor.set(0.5, 0.5);
- beastNameText.x = 1024;
- beastNameText.y = 1250;
- beastNameText.alpha = 0;
- captureOverlay.addChild(beastNameText);
- // Kinky transformation description
- var descText = new Text2('CRYSTALLIZED INTO A THRALL GEM\nREADY TO SERVE YOUR DESIRES', {
- size: 70,
- fill: 0xFFFFFF,
+ // Calculate XP earned
+ var baseXP = 100;
+ var bonusXP = captureSuccess ? 50 : 0;
+ var totalXP = baseXP + bonusXP;
+ // XP text positioned within menu boundaries
+ var xpText = new Text2('EXPERIENCE GAINED: ' + totalXP, {
+ size: 60,
+ fill: 0x00FF00,
fontWeight: 'bold',
wordWrap: true,
- wordWrapWidth: 1200
+ wordWrapWidth: 600
});
- descText.anchor.set(0.5, 0.5);
- descText.x = 1024;
- descText.y = 1400;
- descText.alpha = 0;
- captureOverlay.addChild(descText);
- // Animate elements appearing
- tween(transformText, {
+ xpText.anchor.set(0.5, 0.5);
+ xpText.x = 1024;
+ xpText.y = 1300;
+ xpText.alpha = 0;
+ xpMenuOverlay.addChild(xpText);
+ tween(xpText, {
alpha: 1
}, {
duration: 600,
easing: tween.easeOut
});
- LK.setTimeout(function () {
- tween(beastNameText, {
- alpha: 1
- }, {
- duration: 600,
- easing: tween.easeOut
+ if (captureSuccess) {
+ var successText = new Text2('HUNK CAPTURED!', {
+ size: 100,
+ fill: 0xFF00FF,
+ fontWeight: 'bold'
});
- }, 300);
- LK.setTimeout(function () {
- tween(descText, {
+ successText.anchor.set(0.5, 0.5);
+ successText.x = 1024;
+ successText.y = 1400;
+ successText.alpha = 0;
+ xpMenuOverlay.addChild(successText);
+ tween(successText, {
alpha: 1
}, {
- duration: 600,
+ duration: 800,
easing: tween.easeOut
});
- }, 600);
+ }
// Continue button
- var continueBtn = new Text2('CONTINUE HUNT', {
- size: 80,
- fill: 0x00FF00,
+ 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 () {
- captureOverlay.destroy();
+ xpMenuOverlay.destroy();
+ hideBattleUI();
};
- captureOverlay.addChild(continueBtn);
- LK.setTimeout(function () {
- tween(continueBtn, {
- alpha: 1
- }, {
- duration: 600,
- easing: tween.easeOut
- });
- }, 1000);
-}
-function showResistanceMessage() {
- var resistOverlay = game.addChild(new Container());
- var resistText = new Text2('THE BEAST RESISTS YOUR DOMINANCE!', {
- size: 90,
- fill: 0xFF0000,
- fontWeight: 'bold',
- wordWrap: true,
- wordWrapWidth: 1000
- });
- resistText.anchor.set(0.5, 0.5);
- resistText.x = 1024;
- resistText.y = 1366;
- resistText.alpha = 0;
- resistOverlay.addChild(resistText);
- tween(resistText, {
- alpha: 1,
- scaleX: 1.2,
- scaleY: 1.2
+ xpMenuOverlay.addChild(continueBtn);
+ tween(continueBtn, {
+ alpha: 1
}, {
- duration: 400,
- easing: tween.easeOut,
- onFinish: function onFinish() {
- LK.setTimeout(function () {
- tween(resistText, {
- alpha: 0,
- y: 1200
- }, {
- duration: 600,
- easing: tween.easeIn,
- onFinish: function onFinish() {
- resistOverlay.destroy();
- }
- });
- }, 2000);
- }
+ duration: 1000,
+ easing: tween.easeOut
});
}
function showHunkDialogue() {
var hunkNames = ['FUNGI-GUY', 'DJINN-TONIC', 'MINO-THROBBER', 'IGUANA-THRUST'];
@@ -9297,11 +4319,9 @@
var placeholderOverlay = null;
var interiorShowing = false;
var interiorOverlay = null;
function showInterior(interiorAsset) {
- if (interiorShowing) {
- return;
- }
+ if (interiorShowing) return;
interiorShowing = true;
// Create interior overlay with door expand animation
var transitionOverlay = game.addChild(new Container());
var expandingDoor = transitionOverlay.attachAsset('door', {
@@ -9368,11 +4388,9 @@
}
});
}
function closeInterior() {
- if (!interiorShowing || !interiorOverlay) {
- return;
- }
+ if (!interiorShowing || !interiorOverlay) return;
interiorShowing = false;
// Show brostiary icon again
if (brostiaryIcon) {
brostiaryIcon.alpha = 1;
@@ -9383,11 +4401,9 @@
function showPlaceholderInterior() {
showInterior('interior');
}
function performPlayerCastAnimation() {
- if (!bloodmage || isCasting) {
- return;
- }
+ if (!bloodmage || isCasting) return;
isCasting = true;
LK.getSound('spell').play();
// Store player position to maintain it during animation
var castX = bloodmage.x;
@@ -9470,420 +4486,5 @@
}
}
}
animateCast();
-}
-function generateCleanStructuredLevel(startX, zone) {
- // Step 1: Generate clean background that stays behind player
- generateLayeredBackground(startX, zone);
- // Step 2: Create logical platform pathways
- generateLogicalPlatforms(startX, zone);
- // Step 3: Place single focused character per area
- generateSingleFocusedCharacter(startX, zone);
- // Step 4: Add minimal aesthetic elements that enhance without cluttering
- generateMinimalAesthetics(startX, zone);
- // Step 5: Ensure proper layering with player always in foreground
- ensureProperLayering();
-}
-function generateLayeredBackground(startX, zone) {
- var zoneBackgrounds = {
- 'City': ['nocturnecity', 'bg2'],
- 'Cosmic': ['galaxybg2', 'galaxy'],
- 'Forest': ['forestbg', 'forestbg2', 'forest2', 'forest3'],
- 'Sea': ['sea', 'sea2'],
- 'Under': ['underbg2', 'underbg3']
- };
- var bgAssets = zoneBackgrounds[zone] || zoneBackgrounds.City;
- // Primary background layer - properly scaled and positioned
- var primaryBg = worldContainer.attachAsset(bgAssets[0], {
- anchorX: 0.5,
- anchorY: 1.0,
- x: startX + 1200,
- y: 2732,
- scaleX: 2.0,
- scaleY: 2.0
- });
- primaryBg.alpha = 0.7;
- backgroundElements.push(primaryBg);
- worldContainer.setChildIndex(primaryBg, 0);
- // Secondary background for depth - if available
- if (bgAssets[1]) {
- var secondaryBg = worldContainer.attachAsset(bgAssets[1], {
- anchorX: 0.5,
- anchorY: 1.0,
- x: startX + 800,
- y: 2732,
- scaleX: 1.5,
- scaleY: 1.5
- });
- secondaryBg.alpha = 0.5;
- backgroundElements.push(secondaryBg);
- worldContainer.setChildIndex(secondaryBg, 1);
- }
-}
-function generateLogicalPlatforms(startX, zone) {
- // Create well-spaced platforms that fill space properly without overlap
- var platformSpacing = 450; // Increased spacing to prevent clustering
- var baseY = 1600;
- // Generate fewer, better-placed platforms
- var platformPositions = [{
- x: startX - 900,
- y: baseY + 100
- }, {
- x: startX - 450,
- y: baseY - 50
- }, {
- x: startX,
- y: baseY
- }, {
- x: startX + 450,
- y: baseY - 100
- }, {
- x: startX + 900,
- y: baseY + 50
- }, {
- x: startX + 1350,
- y: baseY - 150
- }, {
- x: startX + 1800,
- y: baseY
- }];
- // Create varied heights based on zone patterns
- for (var i = 0; i < platformPositions.length; i++) {
- var platform = new Platform();
- platform.x = platformPositions[i].x;
- var heightOffset = 0;
- if (zone === 'Cosmic') {
- heightOffset = -i * 40; // Gradual ascent
- } else if (zone === 'Under') {
- heightOffset = i * 30; // Gradual descent
- } else if (zone === 'Sea') {
- heightOffset = Math.sin(i * 0.5) * 80; // Gentle wave
- } else if (zone === 'Forest') {
- heightOffset = i % 2 * -80; // Alternating canopy levels
- } else {
- // City - building steps
- heightOffset = i % 3 * -60;
- }
- platform.y = platformPositions[i].y + heightOffset;
- platform.scaleX = 1.2; // Larger platforms for better coverage
- platform.scaleY = 1.0;
- // Smooth platform appearance with tween
- platform.alpha = 0;
- tween(platform, {
- alpha: 1
- }, {
- duration: 300 + i * 50,
- easing: tween.easeOut
- });
- platforms.push(platform);
- worldContainer.addChild(platform);
- }
-}
-function generateSingleFocusedCharacter(startX, zone) {
- // Count existing visible hunks to ensure only one is visible at a time
- var visibleHunks = 0;
- for (var i = 0; i < hunks.length; i++) {
- if (!hunks[i].captured && hunks[i].alpha > 0) {
- var distance = Math.abs(hunks[i].x - (bloodmage ? bloodmage.x : startX));
- if (distance < 2000) {
- // Within reasonable view distance
- visibleHunks++;
- }
- }
- }
- // Only generate new hunk if no others are currently visible
- if (visibleHunks === 0) {
- var hunk = new Hunk();
- hunk.x = startX + 1200; // Center of chunk
- hunk.y = 1500; // Accessible height
- // Smooth entrance animation with tween
- hunk.alpha = 0;
- hunk.scaleX = 0.1;
- hunk.scaleY = 0.1;
- hunks.push(hunk);
- worldContainer.addChild(hunk);
- // Animate hunk appearing
- tween(hunk, {
- alpha: 1,
- scaleX: 1.0,
- scaleY: 1.0
- }, {
- duration: 800,
- easing: tween.bounceOut
- });
- // Ensure hunk appears in foreground layer (but behind player) with safe bounds checking
- var safeIndex = Math.max(0, worldContainer.children.length - 2);
- if (safeIndex < worldContainer.children.length) {
- worldContainer.setChildIndex(hunk, safeIndex);
- }
- }
-}
-function generateMinimalAesthetics(startX, zone) {
- var zoneAesthetics = {
- 'City': ['building', 'neonSign'],
- 'Cosmic': ['starlight', 'galaxy3'],
- 'Forest': ['trees3', 'foresteffect'],
- 'Sea': ['caveoverlay', 'seaeffect'],
- 'Under': ['underoverlay', 'crystal']
- };
- var aesthetics = zoneAesthetics[zone] || zoneAesthetics.City;
- // Add only 2-3 carefully positioned aesthetic elements
- for (var i = 0; i < 2; i++) {
- var asset = aesthetics[i % aesthetics.length];
- var aesthetic = worldContainer.attachAsset(asset, {
- anchorX: 0.5,
- anchorY: 1.0,
- x: startX + 600 + i * 1200,
- y: 2200,
- scaleX: 1.0 + Math.random() * 0.5,
- scaleY: 1.0 + Math.random() * 0.5
- });
- aesthetic.alpha = 0.6 + Math.random() * 0.3;
- backgroundElements.push(aesthetic);
- // Ensure aesthetic stays behind platforms and characters
- worldContainer.setChildIndex(aesthetic, 2 + i);
- }
-}
-function ensureProperLayering() {
- // Critical: Maintain proper visual hierarchy with safe index bounds checking
- var totalChildren = worldContainer.children.length;
- if (totalChildren === 0) {
- return;
- } // Safety check
- // Safe index calculation helper
- function getSafeIndex(targetIndex) {
- return Math.max(0, Math.min(targetIndex, totalChildren - 1));
- }
- // 1. Background elements (bottom layer)
- for (var i = 0; i < backgroundElements.length; i++) {
- if (backgroundElements[i] && backgroundElements[i].parent === worldContainer) {
- var bgIndex = getSafeIndex(i);
- if (worldContainer.getChildIndex(backgroundElements[i]) !== bgIndex) {
- worldContainer.setChildIndex(backgroundElements[i], bgIndex);
- }
- }
- }
- // 2. Platforms (middle layer) - ensure they're visible above backgrounds
- for (var i = 0; i < platforms.length && i < 50; i++) {
- if (platforms[i] && platforms[i].parent === worldContainer) {
- var platformIndex = getSafeIndex(20 + i);
- var currentIndex = worldContainer.getChildIndex(platforms[i]);
- if (currentIndex < 20 && platformIndex < totalChildren) {
- worldContainer.setChildIndex(platforms[i], platformIndex);
- }
- }
- }
- // 3. Hunks/Characters (upper layer) - visible above platforms
- for (var i = 0; i < hunks.length && i < 20; i++) {
- if (hunks[i] && !hunks[i].captured && hunks[i].parent === worldContainer) {
- var hunkIndex = getSafeIndex(Math.min(70 + i, totalChildren - 2));
- var currentIndex = worldContainer.getChildIndex(hunks[i]);
- if (currentIndex < 70 && hunkIndex < totalChildren - 1) {
- worldContainer.setChildIndex(hunks[i], hunkIndex);
- }
- }
- }
- // 4. Player (always topmost)
- if (bloodmage && bloodmage.parent === worldContainer && totalChildren > 1) {
- var currentPlayerIndex = worldContainer.getChildIndex(bloodmage);
- if (currentPlayerIndex < totalChildren - 1) {
- worldContainer.setChildIndex(bloodmage, totalChildren - 1);
- }
- }
-}
-function generateUnderBiomeAtBottom() {
- // Generate Under biome backgrounds at bottom of screen to eliminate black line
- for (var i = 0; i < 6; i++) {
- var underBgs = ['underbg', 'underbg2', 'underbg3', 'underbg4', 'underbg5'];
- var underAsset = underBgs[Math.floor(Math.random() * underBgs.length)];
- var underBg = worldContainer.attachAsset(underAsset, {
- anchorX: 0.5,
- anchorY: 0.0,
- x: i * 800,
- y: 2732,
- // Bottom of screen
- scaleX: 2.0,
- scaleY: 2.0
- });
- underBg.alpha = 0.6;
- backgroundElements.push(underBg);
- worldContainer.setChildIndex(underBg, 1);
- }
- // Add Under midground elements
- for (var j = 0; j < 4; j++) {
- var underMidgrounds = ['underoverlay', 'caveoverlay'];
- var midgroundAsset = underMidgrounds[Math.floor(Math.random() * underMidgrounds.length)];
- var underMidground = worldContainer.attachAsset(midgroundAsset, {
- anchorX: 0.5,
- anchorY: 1.0,
- x: j * 600 + 300,
- y: 2600,
- scaleX: 1.5,
- scaleY: 1.5
- });
- underMidground.alpha = 0.7;
- backgroundElements.push(underMidground);
- worldContainer.setChildIndex(underMidground, 5);
- }
- // Add solid cave floors along bottom edge to prevent falling into void
- for (var k = 0; k < 8; k++) {
- var floorAsset = k % 2 === 0 ? 'cavefloor' : 'cavefloor2';
- var caveFloor = new Platform();
- var floorGraphic = worldContainer.attachAsset(floorAsset, {
- anchorX: 0.5,
- anchorY: 1.0,
- x: k * 500,
- y: 2700,
- scaleX: 1.2,
- scaleY: 1.2
- });
- caveFloor.x = k * 500;
- caveFloor.y = 2700;
- caveFloor.width = 500;
- caveFloor.height = 100;
- platforms.push(caveFloor);
- worldContainer.addChild(caveFloor);
- }
- // Add periodic cave floor platforms as steps throughout Under biome
- for (var step = 0; step < 12; step++) {
- if (step % 3 === 1) {
- // Every 3rd position gets a step platform
- var stepAsset = step % 2 === 0 ? 'cavefloor' : 'cavefloor2';
- var stepPlatform = new Platform();
- stepPlatform.x = 200 + step * 400;
- stepPlatform.y = 2400 + step % 4 * 50; // Varied heights for steps
- stepPlatform.scaleX = 0.8;
- stepPlatform.scaleY = 0.8;
- platforms.push(stepPlatform);
- worldContainer.addChild(stepPlatform);
- }
- }
-}
-function isInRegionBoundary(x, y, regionName) {
- // Check if the given coordinates are within the specified region's world template boundaries
- var regionData = worldTemplate[regionName];
- if (!regionData) {
- return false;
- }
- // Check boundaries using world template positioning
- var withinX = Math.abs(x - regionData.gameX) <= regionData.width / 2;
- var withinY = Math.abs(y - regionData.gameY) <= regionData.height / 2;
- return withinX && withinY;
-}
-function clearAreaElements(minX, maxX) {
- // Clear background elements in the specified area
- for (var i = backgroundElements.length - 1; i >= 0; i--) {
- var element = backgroundElements[i];
- if (element && element.x >= minX && element.x <= maxX) {
- element.destroy();
- backgroundElements.splice(i, 1);
- }
- }
- // Clear environmental effects in the area
- for (var i = environmentalEffects.length - 1; i >= 0; i--) {
- var effect = environmentalEffects[i];
- if (effect && effect.x >= minX && effect.x <= maxX) {
- effect.destroy();
- environmentalEffects.splice(i, 1);
- }
- }
-}
-function generateZoneBoundedBackgrounds(startX, zone, zoneData) {
- // Only generate backgrounds within the zone's Y range
- var bgAsset = zoneData.backgrounds[Math.floor(Math.random() * zoneData.backgrounds.length)];
- var bgY = Math.max(zoneData.yRange.min, Math.min(zoneData.yRange.max, zoneData.centerY));
- var bg = worldContainer.attachAsset(bgAsset, {
- anchorX: 0.5,
- anchorY: 1.0,
- x: startX + 1000,
- y: bgY + 500,
- // Position within zone bounds
- scaleX: 2.5,
- scaleY: 2.5
- });
- bg.alpha = 0.7;
- bg.zone = zone;
- // Zone-specific styling
- if (zone === 'Cosmic') {
- bg.tint = 0xDDDDFF;
- } else if (zone === 'Sea') {
- bg.tint = 0xCCEEFF;
- } else if (zone === 'Under') {
- bg.tint = 0xFFCCCC;
- } else if (zone === 'Forest') {
- bg.tint = 0xCCFFCC;
- }
- backgroundElements.push(bg);
- worldContainer.setChildIndex(bg, 0);
-}
-function generateZoneBoundedMidground(startX, zone, zoneData) {
- for (var i = 0; i < 3; i++) {
- var midgroundAsset = zoneData.midground[Math.floor(Math.random() * zoneData.midground.length)];
- var midgroundY = Math.max(zoneData.yRange.min, Math.min(zoneData.yRange.max, zoneData.centerY));
- var midground = worldContainer.attachAsset(midgroundAsset, {
- anchorX: 0.5,
- anchorY: 1.0,
- x: startX + 400 + i * 600,
- y: midgroundY,
- scaleX: 1.2 + Math.random() * 0.4,
- scaleY: 1.2 + Math.random() * 0.4
- });
- midground.alpha = 0.8;
- midground.zone = zone;
- if (zone === 'Cosmic') {
- midground.tint = 0xEEEEFF;
- }
- backgroundElements.push(midground);
- worldContainer.setChildIndex(midground, 5 + i);
- }
-}
-function generateZoneBoundedPlatforms(startX, zone) {
- var platformCount = 6;
- var platformSpacing = 350;
- var zoneData = biomeSystem.zones[zone];
- for (var i = 0; i < platformCount; i++) {
- var platform = new Platform();
- platform.x = startX + 200 + i * platformSpacing;
- // Keep platforms within zone Y boundaries
- var baseY = (zoneData.yRange.min + zoneData.yRange.max) / 2;
- var yVariation = (zoneData.yRange.max - zoneData.yRange.min) * 0.3;
- // Zone-specific platform layouts
- if (zone === 'Cosmic') {
- platform.y = baseY - i * 60 + Math.sin(i * 0.5) * 80;
- } else if (zone === 'Under') {
- platform.y = baseY + i * 80;
- } else if (zone === 'Sea') {
- platform.y = baseY + Math.sin(i * 0.8) * 120;
- } else if (zone === 'Forest') {
- platform.y = baseY - i % 3 * 100;
- } else {
- platform.y = baseY - i % 4 * 80;
- }
- // Clamp to zone boundaries
- platform.y = Math.max(zoneData.yRange.min, Math.min(zoneData.yRange.max, platform.y));
- platforms.push(platform);
- worldContainer.addChild(platform);
- }
- // Add Under biome cave floors only if in Under zone
- if (zone === 'Under') {
- if (zoneData.floors) {
- for (var f = 0; f < 4; f++) {
- var floorAsset = zoneData.floors[f % zoneData.floors.length];
- var floorPlatform = new Platform();
- floorPlatform.x = startX + f * 500;
- floorPlatform.y = zoneData.yRange.max - 50; // Near bottom of Under zone
- platforms.push(floorPlatform);
- worldContainer.addChild(floorPlatform);
- var floorGraphic = worldContainer.attachAsset(floorAsset, {
- anchorX: 0.5,
- anchorY: 1.0,
- x: floorPlatform.x,
- y: floorPlatform.y,
- scaleX: 1.2,
- scaleY: 1.2
- });
- backgroundElements.push(floorGraphic);
- }
- }
- }
}
\ No newline at end of file
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