Tambah karakter Bro Wo: sprite 15 state, jurus, UI, dan pendaftaran ke game
Karakter karikatur pixel art dengan tiga jurus (Pohon Sawit, Joget Gemoy, Hutan Sawit), potret, ikon, cut-in, efek, dan gambar pilih karakter. Didaftarkan di game.js, menu.js, index.html, dan style.css.
|
After Width: | Height: | Size: 1010 KiB |
|
After Width: | Height: | Size: 401 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 108 KiB |
|
After Width: | Height: | Size: 47 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 44 KiB |
|
After Width: | Height: | Size: 148 KiB |
|
|
@ -0,0 +1,35 @@
|
||||||
|
/* Shared BRO WO moves (stocky safari ranger, fists and oil-palm trees): player and AI use the same rules. */
|
||||||
|
(() => {
|
||||||
|
'use strict';
|
||||||
|
const balance = { cooldowns:{skill1:4,skill2:7,ultimate:18}, castTime:.5, forestDamage:12, basicRefund:.05 };
|
||||||
|
const names = ['TINJU SAFARI','POHON SAWIT','JOGET GEMOY','HUTAN SAWIT'];
|
||||||
|
// Safari chain: a quick jab, a wide hook, then a heavy shoulder smash with big knockback. Reach sits inside the measured
|
||||||
|
// fist tip (82/82/97 px in BROWO_METRICS.emitters).
|
||||||
|
const combo = [
|
||||||
|
{damage:6,knockback:80,reach:105,duration:.34,hitAt:.5},
|
||||||
|
{damage:8,knockback:110,reach:105,duration:.38,hitAt:.5},
|
||||||
|
{damage:12,knockback:220,reach:120,duration:.5,hitAt:.58}
|
||||||
|
];
|
||||||
|
// Pohon Sawit: BRO WO slams a palm on the floor and an oil-palm erupts `ahead` px in front; everything inside `radius`
|
||||||
|
// px of that spot on the floor is hit. He does not need to touch the rival; a jump above 150 px clears it.
|
||||||
|
const tree = { ahead:190, radius:90 };
|
||||||
|
// Joget Gemoy: a cheerful shoulder-swaying dance; leaves burst around him and everything within `radius` is hit.
|
||||||
|
const dance = { radius:125 };
|
||||||
|
// Hutan Sawit: four palms erupt one after another in front of him (spacing `trees`, every `gap` s from `at`); a rival
|
||||||
|
// standing inside `radius` of any one takes 12 (48 total if all four land). He is free after the 0.5 s cast.
|
||||||
|
const forest = { cutinDuration:.78, trees:[150,280,410,540], at:.8, gap:.34, radius:85, duration:2.6 };
|
||||||
|
function move(name,index=1) {
|
||||||
|
if(name==='attack')return {name:`attack${index}`,type:'attack',index,...combo[index-1]};
|
||||||
|
if(name==='skill1')return {name,type:name,damage:18,duration:.62,knockback:210,tree:true,reach:tree.ahead+tree.radius,hitAt:.55};
|
||||||
|
if(name==='skill2')return {name,type:name,damage:14,duration:.62,knockback:260,dance:true,reach:dance.radius,hitAt:.5};
|
||||||
|
return {name:'ultimate',type:'ultimate',duration:balance.castTime,damage:0,hitAt:1};
|
||||||
|
}
|
||||||
|
function start(a,name,index=1) {
|
||||||
|
if(a.action||a.state==='hurt'||a.state==='down'||a.state==='recover')return false;
|
||||||
|
if(name!=='attack'&&a.cooldowns[name]>0)return false;
|
||||||
|
if(name!=='attack')a.cooldowns[name]=balance.cooldowns[name];
|
||||||
|
a.action={...move(name,index),t:0,fired:false,queued:0};a.state=a.action.name;a.stateTime=0;return true;
|
||||||
|
}
|
||||||
|
function refund(a) {for(const name of Object.keys(balance.cooldowns))a.cooldowns[name]=Math.max(0,a.cooldowns[name]-balance.cooldowns[name]*balance.basicRefund);}
|
||||||
|
window.Browo={balance,names,combo,tree,dance,forest,move,start,refund};
|
||||||
|
})();
|
||||||
90
game.js
|
|
@ -16,9 +16,9 @@
|
||||||
};
|
};
|
||||||
const cooldownMax = { skill1:BALANCE.skill1.cooldown, skill2:BALANCE.skill2.cooldown, ultimate:BALANCE.ultimate.cooldown };
|
const cooldownMax = { skill1:BALANCE.skill1.cooldown, skill2:BALANCE.skill2.cooldown, ultimate:BALANCE.ultimate.cooldown };
|
||||||
const skillNames = { skill1: 'AETHER BOLT', skill2: 'SEISMIC DRIVE', ultimate: 'HELIOS SQUADRON' };
|
const skillNames = { skill1: 'AETHER BOLT', skill2: 'SEISMIC DRIVE', ultimate: 'HELIOS SQUADRON' };
|
||||||
const images = {}, F = window.Fenr, M = window.Mira && window.MIRA_MANIFEST ? window.Mira : null, C = window.Cora && window.CORA_MANIFEST ? window.Cora : null, N = window.Naja && window.NAJA_MANIFEST ? window.Naja : null, HD = window.Haldor && window.HALDOR_MANIFEST ? window.Haldor : null, Z = window.Zanni && window.ZANNI_MANIFEST ? window.Zanni : null, IS = window.Isolde && window.ISOLDE_MANIFEST ? window.Isolde : null, RH = window.Rhea && window.RHEA_MANIFEST ? window.Rhea : null, SO = window.Solan && window.SOLAN_MANIFEST ? window.Solan : null, NB = window.Nib && window.NIB_MANIFEST ? window.Nib : null, ED = window.Edda && window.EDDA_MANIFEST ? window.Edda : null;
|
const images = {}, F = window.Fenr, M = window.Mira && window.MIRA_MANIFEST ? window.Mira : null, C = window.Cora && window.CORA_MANIFEST ? window.Cora : null, N = window.Naja && window.NAJA_MANIFEST ? window.Naja : null, HD = window.Haldor && window.HALDOR_MANIFEST ? window.Haldor : null, Z = window.Zanni && window.ZANNI_MANIFEST ? window.Zanni : null, IS = window.Isolde && window.ISOLDE_MANIFEST ? window.Isolde : null, RH = window.Rhea && window.RHEA_MANIFEST ? window.Rhea : null, SO = window.Solan && window.SOLAN_MANIFEST ? window.Solan : null, NB = window.Nib && window.NIB_MANIFEST ? window.Nib : null, ED = window.Edda && window.EDDA_MANIFEST ? window.Edda : null, BW = window.Browo && window.BROWO_MANIFEST ? window.Browo : null;
|
||||||
// Kits that share one start/move/refund contract (mira.js, cora.js, naja.js, haldor.js, zanni.js, isolde.js, rhea.js, solan.js, nib.js, edda.js).
|
// Kits that share one start/move/refund contract (mira.js, cora.js, naja.js, haldor.js, zanni.js, isolde.js, rhea.js, solan.js, nib.js, edda.js).
|
||||||
const KITS = { ...(M ? { mira: M } : {}), ...(C ? { cora: C } : {}), ...(N ? { naja: N } : {}), ...(HD ? { haldor: HD } : {}), ...(Z ? { zanni: Z } : {}), ...(IS ? { isolde: IS } : {}), ...(RH ? { rhea: RH } : {}), ...(SO ? { solan: SO } : {}), ...(NB ? { nib: NB } : {}), ...(ED ? { edda: ED } : {}) };
|
const KITS = { ...(M ? { mira: M } : {}), ...(C ? { cora: C } : {}), ...(N ? { naja: N } : {}), ...(HD ? { haldor: HD } : {}), ...(Z ? { zanni: Z } : {}), ...(IS ? { isolde: IS } : {}), ...(RH ? { rhea: RH } : {}), ...(SO ? { solan: SO } : {}), ...(NB ? { nib: NB } : {}), ...(ED ? { edda: ED } : {}), ...(BW ? { browo: BW } : {}) };
|
||||||
let manifest = window.MECHA_MANIFEST || window.SPRITE_MANIFEST || null, metrics = window.MECHA_METRICS || null;
|
let manifest = window.MECHA_MANIFEST || window.SPRITE_MANIFEST || null, metrics = window.MECHA_METRICS || null;
|
||||||
let selectedCharacter = 'arco', aiEnabled = !!F, fenrCutin = null, hudIdentity = '';
|
let selectedCharacter = 'arco', aiEnabled = !!F, fenrCutin = null, hudIdentity = '';
|
||||||
const Rules = window.MatchRules;
|
const Rules = window.MatchRules;
|
||||||
|
|
@ -81,13 +81,14 @@
|
||||||
const ULTIMATE_VOICE_PATH = 'assets/audio/arco-ultimate-dylan.mp3';
|
const ULTIMATE_VOICE_PATH = 'assets/audio/arco-ultimate-dylan.mp3';
|
||||||
const FENR_VOICE_PATH = 'assets/fenr/audio/fenr-ultimate-holden.mp3';
|
const FENR_VOICE_PATH = 'assets/fenr/audio/fenr-ultimate-holden.mp3';
|
||||||
const MIRA_VOICE_PATH = 'assets/mira/audio/mira-ultimate-luna.mp3', CORA_VOICE_PATH = 'assets/cora/audio/cora-ultimate-anika.mp3', NAJA_VOICE_PATH = 'assets/naja/audio/naja-ultimate-soraya.mp3', HALDOR_VOICE_PATH = 'assets/haldor/audio/haldor-ultimate.mp3', ZANNI_VOICE_PATH = 'assets/zanni/audio/zanni-ultimate.mp3', ISOLDE_VOICE_PATH = 'assets/isolde/audio/isolde-ultimate.mp3', RHEA_VOICE_PATH = 'assets/rhea/audio/rhea-ultimate.mp3', SOLAN_VOICE_PATH = 'assets/solan/audio/solan-ultimate.mp3', NIB_VOICE_PATH = 'assets/nib/audio/nib-ultimate.mp3', EDDA_VOICE_PATH = 'assets/edda/audio/edda-ultimate.mp3';
|
const MIRA_VOICE_PATH = 'assets/mira/audio/mira-ultimate-luna.mp3', CORA_VOICE_PATH = 'assets/cora/audio/cora-ultimate-anika.mp3', NAJA_VOICE_PATH = 'assets/naja/audio/naja-ultimate-soraya.mp3', HALDOR_VOICE_PATH = 'assets/haldor/audio/haldor-ultimate.mp3', ZANNI_VOICE_PATH = 'assets/zanni/audio/zanni-ultimate.mp3', ISOLDE_VOICE_PATH = 'assets/isolde/audio/isolde-ultimate.mp3', RHEA_VOICE_PATH = 'assets/rhea/audio/rhea-ultimate.mp3', SOLAN_VOICE_PATH = 'assets/solan/audio/solan-ultimate.mp3', NIB_VOICE_PATH = 'assets/nib/audio/nib-ultimate.mp3', EDDA_VOICE_PATH = 'assets/edda/audio/edda-ultimate.mp3';
|
||||||
const VOICE_NAMES = { arco: 'Dylan', fenr: 'Holden', mira: 'Luna', cora: 'Anika', naja: 'Soraya', haldor: 'Gideon', zanni: 'Julian', isolde: 'Vesper', rhea: 'Chloe', solan: 'Xavier', nib: 'Evan', edda: 'Opal' };
|
const VOICE_NAMES = { arco: 'Dylan', fenr: 'Holden', mira: 'Luna', cora: 'Anika', naja: 'Soraya', haldor: 'Gideon', zanni: 'Julian', isolde: 'Vesper', rhea: 'Chloe', solan: 'Xavier', nib: 'Evan', edda: 'Opal', browo: 'Bro Wo' };
|
||||||
|
const BROWO_VOICE_PATH = 'assets/browo/audio/browo-ultimate.mp3';
|
||||||
const voiceBank = {};
|
const voiceBank = {};
|
||||||
let voiceKind = 'arco', voiceName = 'Dylan', voiceActor = null, voiceClock = 0;
|
let voiceKind = 'arco', voiceName = 'Dylan', voiceActor = null, voiceClock = 0;
|
||||||
let ultimateVoice = null, voiceActive = false, voiceSerial = 0, voicePlayToken = 0, voiceStarts = 0, voiceError = '';
|
let ultimateVoice = null, voiceActive = false, voiceSerial = 0, voicePlayToken = 0, voiceStarts = 0, voiceError = '';
|
||||||
try {
|
try {
|
||||||
if (typeof Audio !== 'undefined') {
|
if (typeof Audio !== 'undefined') {
|
||||||
for (const [kind, path] of [['arco', ULTIMATE_VOICE_PATH], ...(F ? [['fenr', FENR_VOICE_PATH]] : []), ...(M ? [['mira', MIRA_VOICE_PATH]] : []), ...(C ? [['cora', CORA_VOICE_PATH]] : []), ...(N ? [['naja', NAJA_VOICE_PATH]] : []), ...(HD ? [['haldor', HALDOR_VOICE_PATH]] : []), ...(Z ? [['zanni', ZANNI_VOICE_PATH]] : []), ...(IS ? [['isolde', ISOLDE_VOICE_PATH]] : []), ...(RH ? [['rhea', RHEA_VOICE_PATH]] : []), ...(SO ? [['solan', SOLAN_VOICE_PATH]] : []), ...(NB ? [['nib', NIB_VOICE_PATH]] : []), ...(ED ? [['edda', EDDA_VOICE_PATH]] : [])]) {
|
for (const [kind, path] of [['arco', ULTIMATE_VOICE_PATH], ...(F ? [['fenr', FENR_VOICE_PATH]] : []), ...(M ? [['mira', MIRA_VOICE_PATH]] : []), ...(C ? [['cora', CORA_VOICE_PATH]] : []), ...(N ? [['naja', NAJA_VOICE_PATH]] : []), ...(HD ? [['haldor', HALDOR_VOICE_PATH]] : []), ...(Z ? [['zanni', ZANNI_VOICE_PATH]] : []), ...(IS ? [['isolde', ISOLDE_VOICE_PATH]] : []), ...(RH ? [['rhea', RHEA_VOICE_PATH]] : []), ...(SO ? [['solan', SOLAN_VOICE_PATH]] : []), ...(NB ? [['nib', NIB_VOICE_PATH]] : []), ...(ED ? [['edda', EDDA_VOICE_PATH]] : []), ...(BW ? [['browo', BROWO_VOICE_PATH]] : [])]) {
|
||||||
const media = new Audio(); media.preload = 'auto'; voiceBank[kind] = media;
|
const media = new Audio(); media.preload = 'auto'; voiceBank[kind] = media;
|
||||||
media.addEventListener('ended', () => { if (ultimateVoice !== media) return; voiceActive = false; applyAudioMix(); });
|
media.addEventListener('ended', () => { if (ultimateVoice !== media) return; voiceActive = false; applyAudioMix(); });
|
||||||
media.addEventListener('error', () => { if (ultimateVoice !== media) return; voiceError = 'audio-load-failed'; voiceActive = false; applyAudioMix(); });
|
media.addEventListener('error', () => { if (ultimateVoice !== media) return; voiceError = 'audio-load-failed'; voiceActive = false; applyAudioMix(); });
|
||||||
|
|
@ -364,6 +365,7 @@
|
||||||
if(selectedCharacter==='solan'){solanStrike(hero,SO.move('attack',index));return;}
|
if(selectedCharacter==='solan'){solanStrike(hero,SO.move('attack',index));return;}
|
||||||
if(selectedCharacter==='nib'){nibStrike(hero,NB.move('attack',index));return;}
|
if(selectedCharacter==='nib'){nibStrike(hero,NB.move('attack',index));return;}
|
||||||
if(selectedCharacter==='edda'){eddaStrike(hero,ED.move('attack',index));return;}
|
if(selectedCharacter==='edda'){eddaStrike(hero,ED.move('attack',index));return;}
|
||||||
|
if(selectedCharacter==='browo'){browoStrike(hero,BW.move('attack',index));return;}
|
||||||
const reach = attackRange(index), dx = (dummy.x - hero.x) * hero.facing, y = emitter(`attack${index}`).y;
|
const reach = attackRange(index), dx = (dummy.x - hero.x) * hero.facing, y = emitter(`attack${index}`).y;
|
||||||
effects.push({ type: 'slash', x: hero.x + hero.facing * 48, y: y + 5, life: .22, maxLife: .22, facing: hero.facing, index, color: index === 3 ? '#ffe4a5' : '#cffbf0' });
|
effects.push({ type: 'slash', x: hero.x + hero.facing * 48, y: y + 5, life: .22, maxLife: .22, facing: hero.facing, index, color: index === 3 ? '#ffe4a5' : '#cffbf0' });
|
||||||
if (dx > -24 && dx < reach + 27 && Math.abs(dummy.y - hero.y) < 113) {
|
if (dx > -24 && dx < reach + 27 && Math.abs(dummy.y - hero.y) < 113) {
|
||||||
|
|
@ -387,6 +389,7 @@
|
||||||
if(selectedCharacter==='solan'){solanStrike(hero,action);return;}
|
if(selectedCharacter==='solan'){solanStrike(hero,action);return;}
|
||||||
if(selectedCharacter==='nib'){nibStrike(hero,action);return;}
|
if(selectedCharacter==='nib'){nibStrike(hero,action);return;}
|
||||||
if(selectedCharacter==='edda'){eddaStrike(hero,action);return;}
|
if(selectedCharacter==='edda'){eddaStrike(hero,action);return;}
|
||||||
|
if(selectedCharacter==='browo'){browoStrike(hero,action);return;}
|
||||||
const name = action.type, origin = emitter(name);
|
const name = action.type, origin = emitter(name);
|
||||||
if (name === 'skill1') { projectiles.push({ x: origin.x, y: origin.y, vx: hero.facing * 920, life: 1.6, facing: hero.facing }); effects.push({ type: 'muzzle', x: origin.x, y: origin.y, life: .25, maxLife: .25 }); spawnParticles(origin.x, origin.y, '#a9f8ef', 12, 140); }
|
if (name === 'skill1') { projectiles.push({ x: origin.x, y: origin.y, vx: hero.facing * 920, life: 1.6, facing: hero.facing }); effects.push({ type: 'muzzle', x: origin.x, y: origin.y, life: .25, maxLife: .25 }); spawnParticles(origin.x, origin.y, '#a9f8ef', 12, 140); }
|
||||||
if (name === 'skill2') { const x = origin.x; effects.push({ type: 'slam', x, y: CONFIG.groundY - 2, life: .8, maxLife: .8 }); spawnParticles(x, CONFIG.groundY - 8, '#c7eafd', 40, 370); trauma = Math.min(1, trauma + .35); sound('heavy'); if (Math.abs(dummy.x - x) < BALANCE.skill2.radius && dummy.y > CONFIG.groundY - 125) hitDummy(BALANCE.skill2.damage, BALANCE.skill2.knockback, '#bfe9ff', hero.x, dummy.y - 65); }
|
if (name === 'skill2') { const x = origin.x; effects.push({ type: 'slam', x, y: CONFIG.groundY - 2, life: .8, maxLife: .8 }); spawnParticles(x, CONFIG.groundY - 8, '#c7eafd', 40, 370); trauma = Math.min(1, trauma + .35); sound('heavy'); if (Math.abs(dummy.x - x) < BALANCE.skill2.radius && dummy.y > CONFIG.groundY - 125) hitDummy(BALANCE.skill2.damage, BALANCE.skill2.knockback, '#bfe9ff', hero.x, dummy.y - 65); }
|
||||||
|
|
@ -489,7 +492,7 @@
|
||||||
s.phase = s.t < P.cutinDuration ? 'cutin' : s.exploded < s.rockets.length ? 'barrage' : 'clearing';
|
s.phase = s.t < P.cutinDuration ? 'cutin' : s.exploded < s.rockets.length ? 'barrage' : 'clearing';
|
||||||
if (s.t >= P.duration) { if (s.owner === 'enemy') enemyParade = null; else parade = null; }
|
if (s.t >= P.duration) { if (s.owner === 'enemy') enemyParade = null; else parade = null; }
|
||||||
}
|
}
|
||||||
function startSummon(actor) { const id = actor === hero ? selectedCharacter : opponentCharacter; if (id === 'cora') startMurmuration(actor); else if (id === 'naja') startSerpent(actor); else if (id === 'haldor') startQuake(actor); else if (id === 'zanni') startFinale(actor); else if (id === 'isolde') startSkyfall(actor); else if (id === 'rhea') startOrrery(actor); else if (id === 'solan') startSunroar(actor); else if (id === 'nib') startDelivery(actor); else if (id === 'edda') startTortoise(actor); else startRocketParade(actor); }
|
function startSummon(actor) { const id = actor === hero ? selectedCharacter : opponentCharacter; if (id === 'cora') startMurmuration(actor); else if (id === 'naja') startSerpent(actor); else if (id === 'haldor') startQuake(actor); else if (id === 'zanni') startFinale(actor); else if (id === 'isolde') startSkyfall(actor); else if (id === 'rhea') startOrrery(actor); else if (id === 'solan' || id === 'browo') startSunroar(actor); else if (id === 'nib') startDelivery(actor); else if (id === 'edda') startTortoise(actor); else startRocketParade(actor); }
|
||||||
// CORA Night Murmuration: three raven passes sweep forward from behind her wings at three heights,
|
// CORA Night Murmuration: three raven passes sweep forward from behind her wings at three heights,
|
||||||
// one 16-damage hit each (48 total), no global hit-stop. A pass hits once, when its lead raven crosses the target.
|
// one 16-damage hit each (48 total), no global hit-stop. A pass hits once, when its lead raven crosses the target.
|
||||||
function startMurmuration(actor = hero) {
|
function startMurmuration(actor = hero) {
|
||||||
|
|
@ -674,10 +677,11 @@
|
||||||
const group = { t: 0, owner: actor === hero ? 'player' : 'enemy', facing: actor.facing, roars: 0, phase: 'cutin' };
|
const group = { t: 0, owner: actor === hero ? 'player' : 'enemy', facing: actor.facing, roars: 0, phase: 'cutin' };
|
||||||
if (actor === hero) sunroar = group; else enemySunroar = group;
|
if (actor === hero) sunroar = group; else enemySunroar = group;
|
||||||
cinematic = .9; announceTimer = 0;
|
cinematic = .9; announceTimer = 0;
|
||||||
startUltimateVoice('solan', actor);
|
startUltimateVoice((actor === hero ? selectedCharacter : opponentCharacter) === 'browo' ? 'browo' : 'solan', actor);
|
||||||
}
|
}
|
||||||
function updateSunroar(dt, s) {
|
function updateSunroar(dt, s) {
|
||||||
if (!s) return;
|
if (!s) return;
|
||||||
|
if ((s.owner === 'enemy' ? opponentCharacter : selectedCharacter) === 'browo') { updateForest(dt, s); return; }
|
||||||
const U = SO.roar, a = s.owner === 'enemy' ? dummy : hero;
|
const U = SO.roar, a = s.owner === 'enemy' ? dummy : hero;
|
||||||
s.t += dt;
|
s.t += dt;
|
||||||
while (s.roars < U.roars.length && s.t >= U.roars[s.roars]) {
|
while (s.roars < U.roars.length && s.t >= U.roars[s.roars]) {
|
||||||
|
|
@ -690,6 +694,24 @@
|
||||||
s.phase = s.t < U.cutinDuration ? 'cutin' : s.roars < U.roars.length ? 'roaring' : 'fading';
|
s.phase = s.t < U.cutinDuration ? 'cutin' : s.roars < U.roars.length ? 'roaring' : 'fading';
|
||||||
if (s.t >= U.duration && !projectiles.some(p => p.asset === 'solan-roar' && p.owner === s.owner)) { if (s.owner === 'enemy') enemySunroar = null; else sunroar = null; }
|
if (s.t >= U.duration && !projectiles.some(p => p.asset === 'solan-roar' && p.owner === s.owner)) { if (s.owner === 'enemy') enemySunroar = null; else sunroar = null; }
|
||||||
}
|
}
|
||||||
|
// BRO WO Hutan Sawit: four oil-palms erupt one after another in front of him (BW.forest.trees). The group object is the
|
||||||
|
// shared `sunroar` slot, so the pause/reset/cut-in plumbing is the same as SOLAN's; `roars` counts the trees raised.
|
||||||
|
function updateForest(dt, s) {
|
||||||
|
const U = BW.forest, a = s.owner === 'enemy' ? dummy : hero, target = s.owner === 'enemy' ? hero : dummy;
|
||||||
|
s.t += dt;
|
||||||
|
while (s.roars < U.trees.length && s.t >= U.at + s.roars * U.gap) {
|
||||||
|
const i = s.roars++, x = clamp(a.x + s.facing * U.trees[i], 70, W - 70);
|
||||||
|
effects.push({ type: 'browo-tree', x, y: CONFIG.groundY, life: .9, maxLife: .9 });
|
||||||
|
effects.push({ type: 'browo-fx', asset: 'browo-impact', x, y: CONFIG.groundY - 24, facing: 1, life: .45, maxLife: .45, size: 240 });
|
||||||
|
spawnParticles(x, CONFIG.groundY - 10, '#a47a3a', 14, 260, 'dust'); trauma = Math.min(1, trauma + .25); sound('heavy');
|
||||||
|
if (Math.abs(target.x - x) < U.radius && target.y > CONFIG.groundY - 150) {
|
||||||
|
if (s.owner === 'enemy') window.__game.receiveHit(BW.balance.forestDamage);
|
||||||
|
else hitDummy(BW.balance.forestDamage, i === U.trees.length - 1 ? 190 : 50, '#9bd05a', x, CONFIG.groundY - 90, false, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.phase = s.t < U.cutinDuration ? 'cutin' : s.roars < U.trees.length ? 'roaring' : 'fading';
|
||||||
|
if (s.t >= U.duration) { if (s.owner === 'enemy') enemySunroar = null; else sunroar = null; }
|
||||||
|
}
|
||||||
// NIB Special Delivery: three paper-plane parcels leave the satchel 0.38 s apart and home in on the rival (homing
|
// NIB Special Delivery: three paper-plane parcels leave the satchel 0.38 s apart and home in on the rival (homing
|
||||||
// projectiles with a limited turn rate, 16 each, 48 total). NIB is free after the 0.5 s cast; a late sidestep or a
|
// projectiles with a limited turn rate, 16 each, 48 total). NIB is free after the 0.5 s cast; a late sidestep or a
|
||||||
// jump makes a plane overshoot.
|
// jump makes a plane overshoot.
|
||||||
|
|
@ -818,7 +840,7 @@
|
||||||
const stride = metrics?.states?.[hero.state]?.stride_estimate || manifest?.metrics?.[hero.state === 'run' ? 'runStride' : 'walkStride'] || manifest?.locomotion?.[hero.state]?.stride_px || (hero.state === 'run' ? 184 : 148);
|
const stride = metrics?.states?.[hero.state]?.stride_estimate || manifest?.metrics?.[hero.state === 'run' ? 'runStride' : 'walkStride'] || manifest?.locomotion?.[hero.state]?.stride_px || (hero.state === 'run' ? 184 : 148);
|
||||||
hero.walkPhase += Math.abs(hero.vx) * dt / stride;
|
hero.walkPhase += Math.abs(hero.vx) * dt / stride;
|
||||||
updateDummy(dt); updateProjectiles(dt); updateSquadron(dt); updateSquadron(dt,enemySquad); updateParade(dt,parade); updateParade(dt,enemyParade); updateMurmuration(dt,flock); updateMurmuration(dt,enemyFlock); updateSerpent(dt,serpent); updateSerpent(dt,enemySerpent); updateQuake(dt,quake); updateFinale(dt,finale); updateFinale(dt,enemyFinale); updateSkyfall(dt,skyfall); updateSkyfall(dt,enemySkyfall); updateOrrery(dt,orrery); updateOrrery(dt,enemyOrrery); updateSunroar(dt,sunroar); updateSunroar(dt,enemySunroar); updateDelivery(dt,delivery); updateDelivery(dt,enemyDelivery); updateTortoise(dt,tortoise); updateTortoise(dt,enemyTortoise); updateQuake(dt,enemyQuake);
|
updateDummy(dt); updateProjectiles(dt); updateSquadron(dt); updateSquadron(dt,enemySquad); updateParade(dt,parade); updateParade(dt,enemyParade); updateMurmuration(dt,flock); updateMurmuration(dt,enemyFlock); updateSerpent(dt,serpent); updateSerpent(dt,enemySerpent); updateQuake(dt,quake); updateFinale(dt,finale); updateFinale(dt,enemyFinale); updateSkyfall(dt,skyfall); updateSkyfall(dt,enemySkyfall); updateOrrery(dt,orrery); updateOrrery(dt,enemyOrrery); updateSunroar(dt,sunroar); updateSunroar(dt,enemySunroar); updateDelivery(dt,delivery); updateDelivery(dt,enemyDelivery); updateTortoise(dt,tortoise); updateTortoise(dt,enemyTortoise); updateQuake(dt,enemyQuake);
|
||||||
if (voiceActive && (voiceKind === 'mira' || voiceKind === 'cora' || voiceKind === 'naja' || voiceKind === 'haldor' || voiceKind === 'zanni' || voiceKind === 'isolde' || voiceKind === 'rhea' || voiceKind === 'solan' || voiceKind === 'nib' || voiceKind === 'edda')) voiceClock += dt;
|
if (voiceActive && (voiceKind === 'mira' || voiceKind === 'cora' || voiceKind === 'naja' || voiceKind === 'haldor' || voiceKind === 'zanni' || voiceKind === 'isolde' || voiceKind === 'rhea' || voiceKind === 'solan' || voiceKind === 'browo' || voiceKind === 'nib' || voiceKind === 'edda')) voiceClock += dt;
|
||||||
if (voiceActive && voiceKind !== 'arco' && (!voiceRelevant() || (Number.isFinite(ultimateVoice.duration) && voiceElapsed() >= ultimateVoice.duration))) stopUltimateVoice();
|
if (voiceActive && voiceKind !== 'arco' && (!voiceRelevant() || (Number.isFinite(ultimateVoice.duration) && voiceElapsed() >= ultimateVoice.duration))) stopUltimateVoice();
|
||||||
advanceMatch(dt);
|
advanceMatch(dt);
|
||||||
}
|
}
|
||||||
|
|
@ -886,6 +908,7 @@
|
||||||
else if(selectedCharacter==='haldor') {manifest=window.HALDOR_MANIFEST;metrics=window.HALDOR_METRICS;images.hero=images.haldor;Object.assign(cooldownMax,HD.balance.cooldowns);}
|
else if(selectedCharacter==='haldor') {manifest=window.HALDOR_MANIFEST;metrics=window.HALDOR_METRICS;images.hero=images.haldor;Object.assign(cooldownMax,HD.balance.cooldowns);}
|
||||||
else if(selectedCharacter==='edda') {manifest=window.EDDA_MANIFEST;metrics=window.EDDA_METRICS;images.hero=images.edda;Object.assign(cooldownMax,ED.balance.cooldowns);}
|
else if(selectedCharacter==='edda') {manifest=window.EDDA_MANIFEST;metrics=window.EDDA_METRICS;images.hero=images.edda;Object.assign(cooldownMax,ED.balance.cooldowns);}
|
||||||
else if(selectedCharacter==='nib') {manifest=window.NIB_MANIFEST;metrics=window.NIB_METRICS;images.hero=images.nib;Object.assign(cooldownMax,NB.balance.cooldowns);}
|
else if(selectedCharacter==='nib') {manifest=window.NIB_MANIFEST;metrics=window.NIB_METRICS;images.hero=images.nib;Object.assign(cooldownMax,NB.balance.cooldowns);}
|
||||||
|
else if(selectedCharacter==='browo') {manifest=window.BROWO_MANIFEST;metrics=window.BROWO_METRICS;images.hero=images.browo;Object.assign(cooldownMax,BW.balance.cooldowns);}
|
||||||
else if(selectedCharacter==='solan') {manifest=window.SOLAN_MANIFEST;metrics=window.SOLAN_METRICS;images.hero=images.solan;Object.assign(cooldownMax,SO.balance.cooldowns);}
|
else if(selectedCharacter==='solan') {manifest=window.SOLAN_MANIFEST;metrics=window.SOLAN_METRICS;images.hero=images.solan;Object.assign(cooldownMax,SO.balance.cooldowns);}
|
||||||
else if(selectedCharacter==='rhea') {manifest=window.RHEA_MANIFEST;metrics=window.RHEA_METRICS;images.hero=images.rhea;Object.assign(cooldownMax,RH.balance.cooldowns);}
|
else if(selectedCharacter==='rhea') {manifest=window.RHEA_MANIFEST;metrics=window.RHEA_METRICS;images.hero=images.rhea;Object.assign(cooldownMax,RH.balance.cooldowns);}
|
||||||
else if(selectedCharacter==='isolde') {manifest=window.ISOLDE_MANIFEST;metrics=window.ISOLDE_METRICS;images.hero=images.isolde;Object.assign(cooldownMax,IS.balance.cooldowns);}
|
else if(selectedCharacter==='isolde') {manifest=window.ISOLDE_MANIFEST;metrics=window.ISOLDE_METRICS;images.hero=images.isolde;Object.assign(cooldownMax,IS.balance.cooldowns);}
|
||||||
|
|
@ -1094,6 +1117,37 @@
|
||||||
}
|
}
|
||||||
if(connected)sound(move.leap||move.index===3?'heavy':'hit');
|
if(connected)sound(move.leap||move.index===3?'heavy':'hit');
|
||||||
}
|
}
|
||||||
|
function browoStrike(actor,move) {
|
||||||
|
const enemy=actor===dummy,target=enemy?hero:dummy,em=window.BROWO_METRICS?.emitters?.[move.name];
|
||||||
|
const hy=clamp(actor.y+(em?.y??-95),actor.y-190,actor.y-40);
|
||||||
|
let hitX=null,inside;
|
||||||
|
if(move.tree){
|
||||||
|
// Pohon Sawit: a palm erupts BW.tree.ahead px in front; everything within the radius on the floor is hit.
|
||||||
|
hitX=actor.x+actor.facing*BW.tree.ahead;
|
||||||
|
effects.push({type:'browo-tree',x:hitX,y:CONFIG.groundY,life:.9,maxLife:.9});
|
||||||
|
effects.push({type:'browo-fx',asset:'browo-impact',x:hitX,y:CONFIG.groundY-24,facing:1,life:.45,maxLife:.45,size:240});
|
||||||
|
dust(hitX,18);spawnParticles(hitX,CONFIG.groundY-10,'#a47a3a',18,300,'dust');trauma=Math.min(1,trauma+.3);
|
||||||
|
inside=Math.abs(target.x-hitX)<BW.tree.radius&&target.y>CONFIG.groundY-150;
|
||||||
|
} else if(move.dance){
|
||||||
|
// Joget Gemoy: a leaf burst around BRO WO; everything within BW.dance.radius is hit.
|
||||||
|
hitX=actor.x;
|
||||||
|
effects.push({type:'browo-fx',asset:'browo-sunburst',x:actor.x,y:actor.y-95,facing:1,life:.5,maxLife:.5,size:300});
|
||||||
|
spawnParticles(actor.x,actor.y-95,'#8fd14f',16,260);trauma=Math.min(1,trauma+.2);
|
||||||
|
inside=Math.abs(target.x-actor.x)<BW.dance.radius&&Math.abs(target.y-actor.y)<130;
|
||||||
|
} else {
|
||||||
|
effects.push({type:'slash',x:actor.x+actor.facing*55,y:hy+5,life:.24,maxLife:.24,facing:actor.facing,index:move.index,color:move.index===3?'#ffe7a0':'#f0dba5'});
|
||||||
|
if(move.type==='attack'&&move.index===3){dust(actor.x+actor.facing*(em?.x??95),12);trauma=Math.min(1,trauma+.15);}
|
||||||
|
const dx=(target.x-actor.x)*actor.facing;
|
||||||
|
inside=dx>-22&&dx<move.reach+27&&Math.abs(target.y-actor.y)<=115;
|
||||||
|
}
|
||||||
|
if(!inside){sound(move.tree||move.dance?'heavy':'step');return;}
|
||||||
|
const connected=enemy?window.__game.receiveHit(move.damage):hitDummy(move.damage,move.knockback,move.tree||move.dance?'#cfe9a0':'#f0dba5',hitX??actor.x,hy,false,true);
|
||||||
|
if(connected&&move.type==='attack') {
|
||||||
|
if(enemy)BW.refund(dummy);
|
||||||
|
else for(const name of Object.keys(cooldownMax)){if(hero.cooldowns[name]>0)rechargePulse[name]=.22;hero.cooldowns[name]=Math.max(0,hero.cooldowns[name]-cooldownMax[name]*BALANCE.basicCooldownRefund);}
|
||||||
|
}
|
||||||
|
if(connected)sound(move.tree||move.dance||move.index===3?'heavy':'hit');
|
||||||
|
}
|
||||||
function nibStrike(actor,move) {
|
function nibStrike(actor,move) {
|
||||||
const enemy=actor===dummy,target=enemy?hero:dummy,em=window.NIB_METRICS?.emitters?.[move.name];
|
const enemy=actor===dummy,target=enemy?hero:dummy,em=window.NIB_METRICS?.emitters?.[move.name];
|
||||||
const hy=clamp(actor.y+(em?.y??-80),actor.y-170,actor.y-40);
|
const hy=clamp(actor.y+(em?.y??-80),actor.y-170,actor.y-40);
|
||||||
|
|
@ -1160,6 +1214,7 @@
|
||||||
if(opponentCharacter==='solan'){solanStrike(dummy,a);return;}
|
if(opponentCharacter==='solan'){solanStrike(dummy,a);return;}
|
||||||
if(opponentCharacter==='nib'){nibStrike(dummy,a);return;}
|
if(opponentCharacter==='nib'){nibStrike(dummy,a);return;}
|
||||||
if(opponentCharacter==='edda'){eddaStrike(dummy,a);return;}
|
if(opponentCharacter==='edda'){eddaStrike(dummy,a);return;}
|
||||||
|
if(opponentCharacter==='browo'){browoStrike(dummy,a);return;}
|
||||||
const em=window.MECHA_METRICS.emitters[a.name],x=dummy.x+dummy.facing*em.x,y=dummy.y+em.y,dx=(hero.x-dummy.x)*dummy.facing;
|
const em=window.MECHA_METRICS.emitters[a.name],x=dummy.x+dummy.facing*em.x,y=dummy.y+em.y,dx=(hero.x-dummy.x)*dummy.facing;
|
||||||
if(a.type==='skill1'){projectiles.push({x,y,vx:dummy.facing*920,life:1.6,facing:dummy.facing,owner:'enemy',damage:16});effects.push({type:'muzzle',x,y,life:.25,maxLife:.25});sound('cast');}
|
if(a.type==='skill1'){projectiles.push({x,y,vx:dummy.facing*920,life:1.6,facing:dummy.facing,owner:'enemy',damage:16});effects.push({type:'muzzle',x,y,life:.25,maxLife:.25});sound('cast');}
|
||||||
else if(a.type==='skill2'){effects.push({type:'slam',x,y:CONFIG.groundY-2,life:.8,maxLife:.8});sound('heavy');if(Math.abs(hero.x-x)<220&&Math.abs(hero.y-CONFIG.groundY)<125)window.__game.receiveHit(24);}
|
else if(a.type==='skill2'){effects.push({type:'slam',x,y:CONFIG.groundY-2,life:.8,maxLife:.8});sound('heavy');if(Math.abs(hero.x-x)<220&&Math.abs(hero.y-CONFIG.groundY)<125)window.__game.receiveHit(24);}
|
||||||
|
|
@ -1378,7 +1433,7 @@
|
||||||
dummy.aiThink = pick || dist < 260 ? Math.min(P.reaction, 1 / 60) : P.reaction * .5;
|
dummy.aiThink = pick || dist < 260 ? Math.min(P.reaction, 1 / 60) : P.reaction * .5;
|
||||||
}
|
}
|
||||||
function opponentPose() {
|
function opponentPose() {
|
||||||
const m=opponentCharacter==='arco'?window.MECHA_MANIFEST:opponentCharacter==='mira'?window.MIRA_MANIFEST:opponentCharacter==='cora'?window.CORA_MANIFEST:opponentCharacter==='naja'?window.NAJA_MANIFEST:opponentCharacter==='haldor'?window.HALDOR_MANIFEST:opponentCharacter==='zanni'?window.ZANNI_MANIFEST:opponentCharacter==='isolde'?window.ISOLDE_MANIFEST:opponentCharacter==='rhea'?window.RHEA_MANIFEST:opponentCharacter==='solan'?window.SOLAN_MANIFEST:opponentCharacter==='nib'?window.NIB_MANIFEST:opponentCharacter==='edda'?window.EDDA_MANIFEST:dummy.form==='wolf'?window.FENR_WOLF_MANIFEST:window.FENR_HUMAN_MANIFEST;
|
const m=opponentCharacter==='arco'?window.MECHA_MANIFEST:opponentCharacter==='mira'?window.MIRA_MANIFEST:opponentCharacter==='cora'?window.CORA_MANIFEST:opponentCharacter==='naja'?window.NAJA_MANIFEST:opponentCharacter==='haldor'?window.HALDOR_MANIFEST:opponentCharacter==='zanni'?window.ZANNI_MANIFEST:opponentCharacter==='isolde'?window.ISOLDE_MANIFEST:opponentCharacter==='rhea'?window.RHEA_MANIFEST:opponentCharacter==='solan'?window.SOLAN_MANIFEST:opponentCharacter==='nib'?window.NIB_MANIFEST:opponentCharacter==='edda'?window.EDDA_MANIFEST:opponentCharacter==='browo'?window.BROWO_MANIFEST:dummy.form==='wolf'?window.FENR_WOLF_MANIFEST:window.FENR_HUMAN_MANIFEST;
|
||||||
const name=m?.frame_layout?.rows?.[dummy.state]?dummy.state:'idle',list=m?.frame_layout?.rows?.[name]||[];
|
const name=m?.frame_layout?.rows?.[dummy.state]?dummy.state:'idle',list=m?.frame_layout?.rows?.[name]||[];
|
||||||
let index=0;
|
let index=0;
|
||||||
// Projectile casts that release at 50% show wind-up -> thrust -> full extension, like the player's pose.
|
// Projectile casts that release at 50% show wind-up -> thrust -> full extension, like the player's pose.
|
||||||
|
|
@ -1476,7 +1531,9 @@
|
||||||
}
|
}
|
||||||
for (const e of effects) {
|
for (const e of effects) {
|
||||||
const t = 1 - e.life / e.maxLife; ctx.save(); ctx.translate(Math.round(e.x), Math.round(e.y)); ctx.globalAlpha = Math.min(1, e.life / e.maxLife * 2); ctx.lineCap = 'square';
|
const t = 1 - e.life / e.maxLife; ctx.save(); ctx.translate(Math.round(e.x), Math.round(e.y)); ctx.globalAlpha = Math.min(1, e.life / e.maxLife * 2); ctx.lineCap = 'square';
|
||||||
if((e.type==='fenr-fx'||e.type==='mira-fx'||e.type==='cora-fx'||e.type==='naja-fx'||e.type==='haldor-fx'||e.type==='zanni-fx'||e.type==='isolde-fx'||e.type==='rhea-fx'||e.type==='solan-fx'||e.type==='nib-fx'||e.type==='edda-fx') && images['fx-'+e.asset]){ctx.scale(e.facing||1,1);const size=e.size*(.75+t*.4);ctx.drawImage(images['fx-'+e.asset],-size/2,-size/2,size,size);}
|
if((e.type==='fenr-fx'||e.type==='mira-fx'||e.type==='cora-fx'||e.type==='naja-fx'||e.type==='haldor-fx'||e.type==='zanni-fx'||e.type==='isolde-fx'||e.type==='rhea-fx'||e.type==='solan-fx'||e.type==='nib-fx'||e.type==='edda-fx'||e.type==='browo-fx') && images['fx-'+e.asset]){ctx.scale(e.facing||1,1);const size=e.size*(.75+t*.4);ctx.drawImage(images['fx-'+e.asset],-size/2,-size/2,size,size);}
|
||||||
|
// BRO WO's palm erupts from the floor (clipped at ground level), holds, then sinks back as it fades.
|
||||||
|
if(e.type==='browo-tree'&&images['fx-browo-sawit']){const im=images['fx-browo-sawit'],k=Math.min(1,t*7)*(t>.7?1-(t-.7)/.3:1),h=im.height*.62,w=im.width*.62;ctx.globalAlpha=1;ctx.beginPath();ctx.rect(-w,-h-10,w*2,h+10);ctx.clip();ctx.drawImage(im,-w/2,-h*k+ (1-k)*0,w,h);}
|
||||||
// EDDA's tortoise spirit keeps one size; it fades in and out and lifts before each stomp.
|
// EDDA's tortoise spirit keeps one size; it fades in and out and lifts before each stomp.
|
||||||
if(e.type==='edda-spirit'&&images['fx-'+e.asset]){ctx.globalAlpha=Math.min(1,t*6,(1-t)*5)*.92;ctx.scale(e.facing||1,1);ctx.drawImage(images['fx-'+e.asset],-e.size/2,-e.size-e.lift,e.size,e.size);}
|
if(e.type==='edda-spirit'&&images['fx-'+e.asset]){ctx.globalAlpha=Math.min(1,t*6,(1-t)*5)*.92;ctx.scale(e.facing||1,1);ctx.drawImage(images['fx-'+e.asset],-e.size/2,-e.size-e.lift,e.size,e.size);}
|
||||||
if (e.type === 'slash') { ctx.scale(e.facing, 1); ctx.rotate(e.index === 2 ? -.5 : .15); ctx.strokeStyle = e.color; ctx.lineWidth = 9 * (1 - t) + 2; ctx.beginPath(); ctx.arc(10, 4, 55 + e.index * 10, -1.2 + t * .3, 1.0 + t * .4); ctx.stroke(); ctx.strokeStyle = '#ffffffaa'; ctx.lineWidth = 3; ctx.beginPath(); ctx.arc(4, 4, 46 + e.index * 10, -.85, .7); ctx.stroke(); }
|
if (e.type === 'slash') { ctx.scale(e.facing, 1); ctx.rotate(e.index === 2 ? -.5 : .15); ctx.strokeStyle = e.color; ctx.lineWidth = 9 * (1 - t) + 2; ctx.beginPath(); ctx.arc(10, 4, 55 + e.index * 10, -1.2 + t * .3, 1.0 + t * .4); ctx.stroke(); ctx.strokeStyle = '#ffffffaa'; ctx.lineWidth = 3; ctx.beginPath(); ctx.arc(4, 4, 46 + e.index * 10, -.85, .7); ctx.stroke(); }
|
||||||
|
|
@ -1592,6 +1649,7 @@
|
||||||
if(id==='cora')return {name:'CORA',cls:'DEMI-HUMAN',deck:'CORA',title:'SKY DANCER',portrait:'assets/cora/ui/portrait.webp',names:C.names,icons:['basic','skill1','skill2','ultimate'].map(s=>'assets/cora/ui/icon-'+s+'.webp')};
|
if(id==='cora')return {name:'CORA',cls:'DEMI-HUMAN',deck:'CORA',title:'SKY DANCER',portrait:'assets/cora/ui/portrait.webp',names:C.names,icons:['basic','skill1','skill2','ultimate'].map(s=>'assets/cora/ui/icon-'+s+'.webp')};
|
||||||
if(id==='edda')return {name:'EDDA',cls:'DEMI-HUMAN',deck:'EDDA',title:'SHELL SAGE',portrait:'assets/edda/ui/portrait.webp',names:ED.names,icons:['basic','skill1','skill2','ultimate'].map(s=>'assets/edda/ui/icon-'+s+'.webp')};
|
if(id==='edda')return {name:'EDDA',cls:'DEMI-HUMAN',deck:'EDDA',title:'SHELL SAGE',portrait:'assets/edda/ui/portrait.webp',names:ED.names,icons:['basic','skill1','skill2','ultimate'].map(s=>'assets/edda/ui/icon-'+s+'.webp')};
|
||||||
if(id==='nib')return {name:'NIB',cls:'DEMI-HUMAN',deck:'NIB',title:'ROOFTOP POST',portrait:'assets/nib/ui/portrait.webp',names:NB.names,icons:['basic','skill1','skill2','ultimate'].map(s=>'assets/nib/ui/icon-'+s+'.webp')};
|
if(id==='nib')return {name:'NIB',cls:'DEMI-HUMAN',deck:'NIB',title:'ROOFTOP POST',portrait:'assets/nib/ui/portrait.webp',names:NB.names,icons:['basic','skill1','skill2','ultimate'].map(s=>'assets/nib/ui/icon-'+s+'.webp')};
|
||||||
|
if(id==='browo')return {name:'BRO WO',cls:'HUMAN',deck:'BRO WO',title:'PALM RANGER',portrait:'assets/browo/ui/portrait.webp',names:BW.names,icons:['basic','skill1','skill2','ultimate'].map(s=>'assets/browo/ui/icon-'+s+'.webp')};
|
||||||
if(id==='solan')return {name:'SOLAN',cls:'DEMI-HUMAN',deck:'SOLAN',title:'SUNMANE',portrait:'assets/solan/ui/portrait.webp',names:SO.names,icons:['basic','skill1','skill2','ultimate'].map(s=>'assets/solan/ui/icon-'+s+'.webp')};
|
if(id==='solan')return {name:'SOLAN',cls:'DEMI-HUMAN',deck:'SOLAN',title:'SUNMANE',portrait:'assets/solan/ui/portrait.webp',names:SO.names,icons:['basic','skill1','skill2','ultimate'].map(s=>'assets/solan/ui/icon-'+s+'.webp')};
|
||||||
if(id==='rhea')return {name:'RHEA',cls:'MECHA',deck:'RHEA',title:'LITTLE ORRERY',portrait:'assets/rhea/ui/portrait.webp',names:RH.names,icons:['basic','skill1','skill2','ultimate'].map(s=>'assets/rhea/ui/icon-'+s+'.webp')};
|
if(id==='rhea')return {name:'RHEA',cls:'MECHA',deck:'RHEA',title:'LITTLE ORRERY',portrait:'assets/rhea/ui/portrait.webp',names:RH.names,icons:['basic','skill1','skill2','ultimate'].map(s=>'assets/rhea/ui/icon-'+s+'.webp')};
|
||||||
if(id==='isolde')return {name:'ISOLDE',cls:'MECHA',deck:'ISOLDE',title:'WHITE STRIDER',portrait:'assets/isolde/ui/portrait.webp',names:IS.names,icons:['basic','skill1','skill2','ultimate'].map(s=>'assets/isolde/ui/icon-'+s+'.webp')};
|
if(id==='isolde')return {name:'ISOLDE',cls:'MECHA',deck:'ISOLDE',title:'WHITE STRIDER',portrait:'assets/isolde/ui/portrait.webp',names:IS.names,icons:['basic','skill1','skill2','ultimate'].map(s=>'assets/isolde/ui/icon-'+s+'.webp')};
|
||||||
|
|
@ -1614,7 +1672,7 @@
|
||||||
$('.fighter-two').setAttribute('aria-label','Status lawan '+opponentCharacter.toUpperCase());
|
$('.fighter-two').setAttribute('aria-label','Status lawan '+opponentCharacter.toUpperCase());
|
||||||
document.querySelectorAll('.skill-card').forEach((card,i)=>{card.querySelector('.skill-name').textContent=me.names[i];card.querySelector('img').src=me.icons[i];card.setAttribute('aria-label',me.names[i]+', '+['Spasi','I','O','P'][i]);});
|
document.querySelectorAll('.skill-card').forEach((card,i)=>{card.querySelector('.skill-name').textContent=me.names[i];card.querySelector('img').src=me.icons[i];card.setAttribute('aria-label',me.names[i]+', '+['Spasi','I','O','P'][i]);});
|
||||||
}
|
}
|
||||||
$('#player-status').textContent=selectedCharacter==='fenr'?(hero.form==='wolf'?'FERAL ACTIVE':'RANGER READY'):selectedCharacter==='mira'?'PILOT READY':selectedCharacter==='cora'?'WINGS READY':selectedCharacter==='naja'?'SANDS READY':selectedCharacter==='haldor'?'FURNACE HOT':selectedCharacter==='zanni'?'SHOWTIME':selectedCharacter==='isolde'?'LANCE READY':selectedCharacter==='rhea'?'ORBITS SET':selectedCharacter==='solan'?'PRIDE READY':selectedCharacter==='nib'?'ON THE ROUTE':selectedCharacter==='edda'?'STEADY AS STONE':'CORE ACTIVE';
|
$('#player-status').textContent=selectedCharacter==='fenr'?(hero.form==='wolf'?'FERAL ACTIVE':'RANGER READY'):selectedCharacter==='mira'?'PILOT READY':selectedCharacter==='cora'?'WINGS READY':selectedCharacter==='naja'?'SANDS READY':selectedCharacter==='haldor'?'FURNACE HOT':selectedCharacter==='zanni'?'SHOWTIME':selectedCharacter==='isolde'?'LANCE READY':selectedCharacter==='rhea'?'ORBITS SET':selectedCharacter==='solan'?'PRIDE READY':selectedCharacter==='nib'?'ON THE ROUTE':selectedCharacter==='edda'?'STEADY AS STONE':selectedCharacter==='browo'?'SAFARI READY':'CORE ACTIVE';
|
||||||
for(const [actor,id] of [[hero,'player-form-timer'],[dummy,'enemy-form-timer']]){const el=$('#'+id),active=actor.form==='wolf';el.hidden=!active;el.textContent=active?'FERAL '+Math.max(0,actor.formTime).toFixed(1)+' s':'';el.style.setProperty?.('--remaining',String(actor.formTime/F.balance.duration));}
|
for(const [actor,id] of [[hero,'player-form-timer'],[dummy,'enemy-form-timer']]){const el=$('#'+id),active=actor.form==='wolf';el.hidden=!active;el.textContent=active?'FERAL '+Math.max(0,actor.formTime).toFixed(1)+' s':'';el.style.setProperty?.('--remaining',String(actor.formTime/F.balance.duration));}
|
||||||
}
|
}
|
||||||
function updateHud() {
|
function updateHud() {
|
||||||
|
|
@ -1664,11 +1722,11 @@
|
||||||
// One banner at a time: FENR transformation, then ARCO, then a MIRA/CORA/NAJA/HALDOR summon still inside its cut-in window.
|
// One banner at a time: FENR transformation, then ARCO, then a MIRA/CORA/NAJA/HALDOR summon still inside its cut-in window.
|
||||||
const cutin=$('#ultimate-cutin'),live=g=>g&&g.t<SQUAD.cutinDuration?g:null;
|
const cutin=$('#ultimate-cutin'),live=g=>g&&g.t<SQUAD.cutinDuration?g:null;
|
||||||
const arcoGroup=live(enemySquad)||live(squad),summon=live(enemyParade)||live(parade)||live(enemyFlock)||live(flock)||live(enemySerpent)||live(serpent)||live(enemyQuake)||live(quake)||live(enemyFinale)||live(finale)||live(enemySkyfall)||live(skyfall)||live(enemyOrrery)||live(orrery)||live(enemySunroar)||live(sunroar)||live(enemyDelivery)||live(delivery)||live(enemyTortoise)||live(tortoise);
|
const arcoGroup=live(enemySquad)||live(squad),summon=live(enemyParade)||live(parade)||live(enemyFlock)||live(flock)||live(enemySerpent)||live(serpent)||live(enemyQuake)||live(quake)||live(enemyFinale)||live(finale)||live(enemySkyfall)||live(skyfall)||live(enemyOrrery)||live(orrery)||live(enemySunroar)||live(sunroar)||live(enemyDelivery)||live(delivery)||live(enemyTortoise)||live(tortoise);
|
||||||
const cutinKey=fenrCutin?'fenr':arcoGroup?'arco':summon?(summon===parade||summon===enemyParade?'mira':summon===serpent||summon===enemySerpent?'naja':summon===quake||summon===enemyQuake?'haldor':summon===finale||summon===enemyFinale?'zanni':summon===skyfall||summon===enemySkyfall?'isolde':summon===orrery||summon===enemyOrrery?'rhea':summon===sunroar||summon===enemySunroar?'solan':summon===delivery||summon===enemyDelivery?'nib':summon===tortoise||summon===enemyTortoise?'edda':'cora'):'arco';
|
const cutinKey=fenrCutin?'fenr':arcoGroup?'arco':summon?(summon===parade||summon===enemyParade?'mira':summon===serpent||summon===enemySerpent?'naja':summon===quake||summon===enemyQuake?'haldor':summon===finale||summon===enemyFinale?'zanni':summon===skyfall||summon===enemySkyfall?'isolde':summon===orrery||summon===enemyOrrery?'rhea':summon===sunroar||summon===enemySunroar?((summon===enemySunroar?opponentCharacter:selectedCharacter)==='browo'?'browo':'solan'):summon===delivery||summon===enemyDelivery?'nib':summon===tortoise||summon===enemyTortoise?'edda':'cora'):'arco';
|
||||||
const ct=fenrCutin?.t ?? (arcoGroup||summon)?.t ?? 100;
|
const ct=fenrCutin?.t ?? (arcoGroup||summon)?.t ?? 100;
|
||||||
cutin.classList.toggle('fenr-cutin',cutinKey==='fenr');cutin.classList.toggle('mira-cutin',cutinKey==='mira');cutin.classList.toggle('cora-cutin',cutinKey==='cora');cutin.classList.toggle('naja-cutin',cutinKey==='naja');cutin.classList.toggle('haldor-cutin',cutinKey==='haldor');cutin.classList.toggle('zanni-cutin',cutinKey==='zanni');cutin.classList.toggle('isolde-cutin',cutinKey==='isolde');cutin.classList.toggle('rhea-cutin',cutinKey==='rhea');cutin.classList.toggle('solan-cutin',cutinKey==='solan');cutin.classList.toggle('nib-cutin',cutinKey==='nib');cutin.classList.toggle('edda-cutin',cutinKey==='edda');
|
cutin.classList.toggle('fenr-cutin',cutinKey==='fenr');cutin.classList.toggle('mira-cutin',cutinKey==='mira');cutin.classList.toggle('cora-cutin',cutinKey==='cora');cutin.classList.toggle('naja-cutin',cutinKey==='naja');cutin.classList.toggle('haldor-cutin',cutinKey==='haldor');cutin.classList.toggle('zanni-cutin',cutinKey==='zanni');cutin.classList.toggle('isolde-cutin',cutinKey==='isolde');cutin.classList.toggle('rhea-cutin',cutinKey==='rhea');cutin.classList.toggle('solan-cutin',cutinKey==='solan');cutin.classList.toggle('nib-cutin',cutinKey==='nib');cutin.classList.toggle('edda-cutin',cutinKey==='edda');cutin.classList.toggle('browo-cutin',cutinKey==='browo');
|
||||||
const cutinArt=cutin.querySelector('.cutin-art'),cutinOwner=cutinKey==='fenr'?fenrCutin.owner:cutinKey==='mira'||cutinKey==='cora'||cutinKey==='naja'||cutinKey==='haldor'||cutinKey==='zanni'||cutinKey==='isolde'||cutinKey==='rhea'||cutinKey==='solan'||cutinKey==='nib'||cutinKey==='edda'?(summon.owner==='enemy'?'RIVAL':'PLAYER'):'';
|
const cutinArt=cutin.querySelector('.cutin-art'),cutinOwner=cutinKey==='fenr'?fenrCutin.owner:cutinKey==='mira'||cutinKey==='cora'||cutinKey==='naja'||cutinKey==='haldor'||cutinKey==='zanni'||cutinKey==='isolde'||cutinKey==='rhea'||cutinKey==='solan'||cutinKey==='browo'||cutinKey==='nib'||cutinKey==='edda'?(summon.owner==='enemy'?'RIVAL':'PLAYER'):'';
|
||||||
if(cutin.dataset.identity!==cutinKey+cutinOwner){cutin.dataset.identity=cutinKey+cutinOwner;cutinArt.src=CUTIN_ART[cutinKey];if(cutinArt.complete)cutinArt.style.visibility='';else{cutinArt.style.visibility='hidden';cutinArt.onload=()=>{cutinArt.style.visibility='';};}cutin.querySelector('.cutin-kicker').textContent={fenr:'FENR / '+cutinOwner,mira:'MIRA / '+cutinOwner,cora:'CORA / '+cutinOwner,naja:'NAJA / '+cutinOwner,haldor:'HALDOR / '+cutinOwner,zanni:'ZANNI / '+cutinOwner,isolde:'ISOLDE / '+cutinOwner,rhea:'RHEA / '+cutinOwner,solan:'SOLAN / '+cutinOwner,nib:'NIB / '+cutinOwner,edda:'EDDA / '+cutinOwner,arco:'ARCO / AETHER COMMAND'}[cutinKey];cutin.querySelector('strong').innerHTML={fenr:'FERAL<br><em>AWAKENING</em>',mira:'ROCKET<br><em>PARADE</em>',cora:'NIGHT<br><em>MURMURATION</em>',naja:'DUNE<br><em>SERPENT</em>',haldor:'FORGE<br><em>QUAKE</em>',zanni:'GRAND<br><em>FINALE</em>',isolde:'SKYFALL<br><em>LANCES</em>',rhea:'GRAND<br><em>ORRERY</em>',solan:'SUNMANE<br><em>ROAR</em>',nib:'SPECIAL<br><em>DELIVERY</em>',edda:'ELDER<br><em>TORTOISE</em>',arco:'HELIOS<br><em>SQUADRON</em>'}[cutinKey];cutin.querySelector('.cutin-detail').textContent={fenr:'THE BEAST WITHIN',mira:'TWELVE-ROCKET SALVO',cora:'THREE-PASS RAVEN STORM',naja:'THREE-STRIKE SAND COBRA',haldor:'THREE-SLAM MOLTEN SHOCKWAVE',zanni:'THREE-RING BLADE BOOMERANG',isolde:'THREE-LANCE ICE DIVE',rhea:'THREE-PLANET ORBIT',solan:'THREE-ROAR SHOCKWAVE',nib:'THREE-PARCEL HOMING RUN',edda:'THREE-STOMP SPIRIT WALK',arco:'ORBITAL LASER STRIKE'}[cutinKey];cutin.setAttribute('aria-label',{fenr:'FENR ultimate: Feral Awakening',mira:'MIRA ultimate: Rocket Parade',cora:'CORA ultimate: Night Murmuration',naja:'NAJA ultimate: Dune Serpent',haldor:'HALDOR ultimate: Forge Quake',zanni:'ZANNI ultimate: Grand Finale',isolde:'ISOLDE ultimate: Skyfall Lances',rhea:'RHEA ultimate: Grand Orrery',solan:'SOLAN ultimate: Sunmane Roar',nib:'NIB ultimate: Special Delivery',edda:'EDDA ultimate: Elder Tortoise',arco:'ARCO ultimate: Helios Squadron'}[cutinKey]);}
|
if(cutin.dataset.identity!==cutinKey+cutinOwner){cutin.dataset.identity=cutinKey+cutinOwner;cutinArt.src=CUTIN_ART[cutinKey];if(cutinArt.complete)cutinArt.style.visibility='';else{cutinArt.style.visibility='hidden';cutinArt.onload=()=>{cutinArt.style.visibility='';};}cutin.querySelector('.cutin-kicker').textContent={fenr:'FENR / '+cutinOwner,mira:'MIRA / '+cutinOwner,cora:'CORA / '+cutinOwner,naja:'NAJA / '+cutinOwner,haldor:'HALDOR / '+cutinOwner,zanni:'ZANNI / '+cutinOwner,isolde:'ISOLDE / '+cutinOwner,rhea:'RHEA / '+cutinOwner,solan:'SOLAN / '+cutinOwner,browo:'BRO WO / '+cutinOwner,nib:'NIB / '+cutinOwner,edda:'EDDA / '+cutinOwner,arco:'ARCO / AETHER COMMAND'}[cutinKey];cutin.querySelector('strong').innerHTML={fenr:'FERAL<br><em>AWAKENING</em>',mira:'ROCKET<br><em>PARADE</em>',cora:'NIGHT<br><em>MURMURATION</em>',naja:'DUNE<br><em>SERPENT</em>',haldor:'FORGE<br><em>QUAKE</em>',zanni:'GRAND<br><em>FINALE</em>',isolde:'SKYFALL<br><em>LANCES</em>',rhea:'GRAND<br><em>ORRERY</em>',solan:'SUNMANE<br><em>ROAR</em>',browo:'HUTAN<br><em>SAWIT</em>',nib:'SPECIAL<br><em>DELIVERY</em>',edda:'ELDER<br><em>TORTOISE</em>',arco:'HELIOS<br><em>SQUADRON</em>'}[cutinKey];cutin.querySelector('.cutin-detail').textContent={fenr:'THE BEAST WITHIN',mira:'TWELVE-ROCKET SALVO',cora:'THREE-PASS RAVEN STORM',naja:'THREE-STRIKE SAND COBRA',haldor:'THREE-SLAM MOLTEN SHOCKWAVE',zanni:'THREE-RING BLADE BOOMERANG',isolde:'THREE-LANCE ICE DIVE',rhea:'THREE-PLANET ORBIT',solan:'THREE-ROAR SHOCKWAVE',browo:'FOUR-PALM FOREST',nib:'THREE-PARCEL HOMING RUN',edda:'THREE-STOMP SPIRIT WALK',arco:'ORBITAL LASER STRIKE'}[cutinKey];cutin.setAttribute('aria-label',{fenr:'FENR ultimate: Feral Awakening',mira:'MIRA ultimate: Rocket Parade',cora:'CORA ultimate: Night Murmuration',naja:'NAJA ultimate: Dune Serpent',haldor:'HALDOR ultimate: Forge Quake',zanni:'ZANNI ultimate: Grand Finale',isolde:'ISOLDE ultimate: Skyfall Lances',rhea:'RHEA ultimate: Grand Orrery',solan:'SOLAN ultimate: Sunmane Roar',browo:'BRO WO ultimate: Hutan Sawit',nib:'NIB ultimate: Special Delivery',edda:'EDDA ultimate: Elder Tortoise',arco:'ARCO ultimate: Helios Squadron'}[cutinKey]);}
|
||||||
const visible = ct < SQUAD.cutinDuration;
|
const visible = ct < SQUAD.cutinDuration;
|
||||||
cutin.classList.toggle('visible', visible); cutin.setAttribute('aria-hidden', String(!visible));
|
cutin.classList.toggle('visible', visible); cutin.setAttribute('aria-hidden', String(!visible));
|
||||||
const slide = !visible ? -110 : ct < .16 ? -110 * Math.pow(1 - ct / .16,3) : ct > .57 ? 110 * Math.pow((ct-.57)/.21,2) : 0;
|
const slide = !visible ? -110 : ct < .16 ? -110 * Math.pow(1 - ct / .16,3) : ct > .57 ? 110 * Math.pow((ct-.57)/.21,2) : 0;
|
||||||
|
|
@ -1678,7 +1736,7 @@
|
||||||
}
|
}
|
||||||
// Cut-in art per fighter. Only the two fighters of the current fight are warmed (at start/select), so a banner never waits
|
// Cut-in art per fighter. Only the two fighters of the current fight are warmed (at start/select), so a banner never waits
|
||||||
// for its image; until the right image is decoded the art stays hidden (see updateHud) instead of showing the last one.
|
// for its image; until the right image is decoded the art stays hidden (see updateHud) instead of showing the last one.
|
||||||
const CUTIN_ART={fenr:'assets/fenr/ui/cutin.webp',mira:'assets/mira/ui/cutin.webp',cora:'assets/cora/ui/cutin.webp',naja:'assets/naja/ui/cutin.webp',haldor:'assets/haldor/ui/cutin.webp',zanni:'assets/zanni/ui/cutin.webp',isolde:'assets/isolde/ui/cutin.webp',rhea:'assets/rhea/ui/cutin.webp',solan:'assets/solan/ui/cutin.webp',nib:'assets/nib/ui/cutin.webp',edda:'assets/edda/ui/cutin.webp',arco:'assets/ui/ultimate-cutin.webp'};
|
const CUTIN_ART={fenr:'assets/fenr/ui/cutin.webp',mira:'assets/mira/ui/cutin.webp',cora:'assets/cora/ui/cutin.webp',naja:'assets/naja/ui/cutin.webp',haldor:'assets/haldor/ui/cutin.webp',zanni:'assets/zanni/ui/cutin.webp',isolde:'assets/isolde/ui/cutin.webp',rhea:'assets/rhea/ui/cutin.webp',solan:'assets/solan/ui/cutin.webp',browo:'assets/browo/ui/cutin.webp',nib:'assets/nib/ui/cutin.webp',edda:'assets/edda/ui/cutin.webp',arco:'assets/ui/ultimate-cutin.webp'};
|
||||||
let cutinWarm=[];
|
let cutinWarm=[];
|
||||||
function warmCutins(){cutinWarm=[...new Set([selectedCharacter,opponentCharacter])].map(id=>CUTIN_ART[id]).filter(Boolean).map(src=>{const im=new Image();im.decoding='async';im.src=src;return im;});}
|
function warmCutins(){cutinWarm=[...new Set([selectedCharacter,opponentCharacter])].map(id=>CUTIN_ART[id]).filter(Boolean).map(src=>{const im=new Image();im.decoding='async';im.src=src;return im;});}
|
||||||
function setPaused(value) { paused = value; clearInput(); syncUltimateVoice(); $('#pause-btn').textContent = value ? '▶' : 'Ⅱ'; const panel = $('#pause-panel'); if (value && !panel.open) panel.showModal(); if (!value && panel.open) panel.close(); if (!value) canvas.focus({ preventScroll: true }); }
|
function setPaused(value) { paused = value; clearInput(); syncUltimateVoice(); $('#pause-btn').textContent = value ? '▶' : 'Ⅱ'; const panel = $('#pause-panel'); if (value && !panel.open) panel.showModal(); if (!value && panel.open) panel.close(); if (!value) canvas.focus({ preventScroll: true }); }
|
||||||
|
|
@ -1721,7 +1779,7 @@
|
||||||
if(window.FRONTEND_ENABLED)setMenuOpen(true);
|
if(window.FRONTEND_ENABLED)setMenuOpen(true);
|
||||||
resize(); requestAnimationFrame(tick);
|
resize(); requestAnimationFrame(tick);
|
||||||
// Wait for the first-visit download (preload.js) so these requests are served from the cache, not fetched twice.
|
// Wait for the first-visit download (preload.js) so these requests are served from the cache, not fetched twice.
|
||||||
Promise.resolve(window.AETHER_PRELOAD).then(() => Promise.all([loadImage('hero', 'assets/mecha/run/sprite-sheet-alpha.webp', true), loadImage('stage', 'assets/stage.webp', true), ...(Rules?Object.entries(Rules.stages).filter(([id])=>id!=='bellora').map(([id,s])=>loadImage('stage-'+id,s.image,true)):[]), ...(F?[loadImage('fenrHuman','assets/fenr/human/run/sprite-sheet-alpha.webp',true),loadImage('fenrWolf','assets/fenr/wolf/run/sprite-sheet-alpha.webp',true),...['claw','gale','rush','bite','howl','transform'].map(name=>loadImage('fx-'+name,'assets/fenr/ui/fx-'+name+'.webp',true))]:[]), ...(M?[loadImage('mira','assets/mira/run/sprite-sheet-alpha.webp',true),...['star','rocket','burst','crash'].map(name=>loadImage('fx-mira-'+name,'assets/mira/ui/fx-'+name+'.webp',true))]:[]), ...(C?[loadImage('cora','assets/cora/run/sprite-sheet-alpha.webp',true),...['feather','gust','raven'].map(name=>loadImage('fx-cora-'+name,'assets/cora/ui/fx-'+name+'.webp',true))]:[]), ...(N?[loadImage('naja','assets/naja/run/sprite-sheet-alpha.webp',true),...['sandwave','cyclone','serpent','ripple'].map(name=>loadImage('fx-naja-'+name,'assets/naja/ui/fx-'+name+'.webp',true))]:[]), ...(HD?[loadImage('haldor','assets/haldor/run/sprite-sheet-alpha.webp',true),...['slag','splash','steam','quake'].map(name=>loadImage('fx-haldor-'+name,'assets/haldor/ui/fx-'+name+'.webp',true))]:[]), ...(Z?[loadImage('zanni','assets/zanni/run/sprite-sheet-alpha.webp',true),...['ring','bigring','snatch','confetti'].map(name=>loadImage('fx-zanni-'+name,'assets/zanni/ui/fx-'+name+'.webp',true))]:[]), ...(IS?[loadImage('isolde','assets/isolde/run/sprite-sheet-alpha.webp',true),...['piercer','skyfall','shatter','frost'].map(name=>loadImage('fx-isolde-'+name,'assets/isolde/ui/fx-'+name+'.webp',true))]:[]), ...(RH?[loadImage('rhea','assets/rhea/run/sprite-sheet-alpha.webp',true),...['drift','planet','well','burst'].map(name=>loadImage('fx-rhea-'+name,'assets/rhea/ui/fx-'+name+'.webp',true))]:[]), ...(SO?[loadImage('solan','assets/solan/run/sprite-sheet-alpha.webp',true),...['crescent','roar','impact','sunburst'].map(name=>loadImage('fx-solan-'+name,'assets/solan/ui/fx-'+name+'.webp',true))]:[]), ...(NB?[loadImage('nib','assets/nib/run/sprite-sheet-alpha.webp',true),...['letter','plane','slip','stamp'].map(name=>loadImage('fx-nib-'+name,'assets/nib/ui/fx-'+name+'.webp',true))]:[]), ...(ED?[loadImage('edda','assets/edda/run/sprite-sheet-alpha.webp',true),...['stone','ripple','shell','tortoise','stomp'].map(name=>loadImage('fx-edda-'+name,'assets/edda/ui/fx-'+name+'.webp',true))]:[]), loadImage('drone', 'assets/ui/drone.png', true), loadImage('cutin', 'assets/ui/ultimate-cutin.webp', true)])).then(results => {
|
Promise.resolve(window.AETHER_PRELOAD).then(() => Promise.all([loadImage('hero', 'assets/mecha/run/sprite-sheet-alpha.webp', true), loadImage('stage', 'assets/stage.webp', true), ...(Rules?Object.entries(Rules.stages).filter(([id])=>id!=='bellora').map(([id,s])=>loadImage('stage-'+id,s.image,true)):[]), ...(F?[loadImage('fenrHuman','assets/fenr/human/run/sprite-sheet-alpha.webp',true),loadImage('fenrWolf','assets/fenr/wolf/run/sprite-sheet-alpha.webp',true),...['claw','gale','rush','bite','howl','transform'].map(name=>loadImage('fx-'+name,'assets/fenr/ui/fx-'+name+'.webp',true))]:[]), ...(M?[loadImage('mira','assets/mira/run/sprite-sheet-alpha.webp',true),...['star','rocket','burst','crash'].map(name=>loadImage('fx-mira-'+name,'assets/mira/ui/fx-'+name+'.webp',true))]:[]), ...(C?[loadImage('cora','assets/cora/run/sprite-sheet-alpha.webp',true),...['feather','gust','raven'].map(name=>loadImage('fx-cora-'+name,'assets/cora/ui/fx-'+name+'.webp',true))]:[]), ...(N?[loadImage('naja','assets/naja/run/sprite-sheet-alpha.webp',true),...['sandwave','cyclone','serpent','ripple'].map(name=>loadImage('fx-naja-'+name,'assets/naja/ui/fx-'+name+'.webp',true))]:[]), ...(HD?[loadImage('haldor','assets/haldor/run/sprite-sheet-alpha.webp',true),...['slag','splash','steam','quake'].map(name=>loadImage('fx-haldor-'+name,'assets/haldor/ui/fx-'+name+'.webp',true))]:[]), ...(Z?[loadImage('zanni','assets/zanni/run/sprite-sheet-alpha.webp',true),...['ring','bigring','snatch','confetti'].map(name=>loadImage('fx-zanni-'+name,'assets/zanni/ui/fx-'+name+'.webp',true))]:[]), ...(IS?[loadImage('isolde','assets/isolde/run/sprite-sheet-alpha.webp',true),...['piercer','skyfall','shatter','frost'].map(name=>loadImage('fx-isolde-'+name,'assets/isolde/ui/fx-'+name+'.webp',true))]:[]), ...(RH?[loadImage('rhea','assets/rhea/run/sprite-sheet-alpha.webp',true),...['drift','planet','well','burst'].map(name=>loadImage('fx-rhea-'+name,'assets/rhea/ui/fx-'+name+'.webp',true))]:[]), ...(SO?[loadImage('solan','assets/solan/run/sprite-sheet-alpha.webp',true),...['crescent','roar','impact','sunburst'].map(name=>loadImage('fx-solan-'+name,'assets/solan/ui/fx-'+name+'.webp',true))]:[]), ...(NB?[loadImage('nib','assets/nib/run/sprite-sheet-alpha.webp',true),...['letter','plane','slip','stamp'].map(name=>loadImage('fx-nib-'+name,'assets/nib/ui/fx-'+name+'.webp',true))]:[]), ...(BW?[loadImage('browo','assets/browo/run/sprite-sheet-alpha.webp',true),...['sawit','impact','sunburst'].map(name=>loadImage('fx-browo-'+name,'assets/browo/ui/fx-'+name+'.webp',true))]:[]), ...(ED?[loadImage('edda','assets/edda/run/sprite-sheet-alpha.webp',true),...['stone','ripple','shell','tortoise','stomp'].map(name=>loadImage('fx-edda-'+name,'assets/edda/ui/fx-'+name+'.webp',true))]:[]), loadImage('drone', 'assets/ui/drone.png', true), loadImage('cutin', 'assets/ui/ultimate-cutin.webp', true)])).then(results => {
|
||||||
images['stage-bellora']=images.stage;images.arco=images.hero;if(F)syncPlayerForm();
|
images['stage-bellora']=images.stage;images.arco=images.hero;if(F)syncPlayerForm();
|
||||||
ready = results.every(Boolean) && (!F || (!!window.FENR_HUMAN_MANIFEST && !!window.FENR_WOLF_MANIFEST)) && !!manifest && frames('idle').length > 0;
|
ready = results.every(Boolean) && (!F || (!!window.FENR_HUMAN_MANIFEST && !!window.FENR_WOLF_MANIFEST)) && !!manifest && frames('idle').length > 0;
|
||||||
if (ready) { $('#load-state').classList.add('hidden'); announce('TRAINING READY', 1.65); }
|
if (ready) { $('#load-state').classList.add('hidden'); announce('TRAINING READY', 1.65); }
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,8 @@
|
||||||
</div></section><div class="stage-sign"><span id="stage-name">BELLORA</span><small id="stage-subtitle">COURTYARD</small><i></i></div><section class="training-data" aria-label="Hasil latihan"><div><span>TOTAL DAMAGE</span><strong id="total-damage">0 <small>DMG</small></strong></div><div><span>BEST CHAIN</span><strong id="best-combo">0 <small>HITS</small></strong></div><small class="reset-hint">R · RESET<span>ESC · PAUSE</span></small></section></footer>
|
</div></section><div class="stage-sign"><span id="stage-name">BELLORA</span><small id="stage-subtitle">COURTYARD</small><i></i></div><section class="training-data" aria-label="Hasil latihan"><div><span>TOTAL DAMAGE</span><strong id="total-damage">0 <small>DMG</small></strong></div><div><span>BEST CHAIN</span><strong id="best-combo">0 <small>HITS</small></strong></div><small class="reset-hint">R · RESET<span>ESC · PAUSE</span></small></section></footer>
|
||||||
<section id="touch-controls" aria-hidden="true"><div class="dpad"><button class="dbtn dbtn-up" data-key="w" tabindex="-1" aria-label="Atas / lompat"><i></i></button><button class="dbtn dbtn-left" data-key="a" tabindex="-1" aria-label="Kiri"><i></i></button><button class="dbtn dbtn-down" data-key="s" tabindex="-1" aria-label="Bawah / jongkok"><i></i></button><button class="dbtn dbtn-right" data-key="d" tabindex="-1" aria-label="Kanan"><i></i></button></div><div class="action-pad"><button class="tbtn tbtn-attack" data-key=" " data-slot="attack" tabindex="-1"><img src="assets/ui/attack.webp" alt=""></button><button class="tbtn tbtn-skill tbtn-s1" data-key="i" data-slot="skill1" tabindex="-1"><img src="assets/ui/skill1.webp" alt=""><span class="cooldown-wipe"></span><em class="cooldown-num"></em></button><button class="tbtn tbtn-skill tbtn-s2" data-key="o" data-slot="skill2" tabindex="-1"><img src="assets/ui/skill2.webp" alt=""><span class="cooldown-wipe"></span><em class="cooldown-num"></em></button><button class="tbtn tbtn-skill tbtn-ult" data-key="p" data-slot="ultimate" tabindex="-1"><img src="assets/ui/squadron-icon.webp" alt=""><span class="cooldown-wipe"></span><em class="cooldown-num"></em></button></div></section>
|
<section id="touch-controls" aria-hidden="true"><div class="dpad"><button class="dbtn dbtn-up" data-key="w" tabindex="-1" aria-label="Atas / lompat"><i></i></button><button class="dbtn dbtn-left" data-key="a" tabindex="-1" aria-label="Kiri"><i></i></button><button class="dbtn dbtn-down" data-key="s" tabindex="-1" aria-label="Bawah / jongkok"><i></i></button><button class="dbtn dbtn-right" data-key="d" tabindex="-1" aria-label="Kanan"><i></i></button></div><div class="action-pad"><button class="tbtn tbtn-attack" data-key=" " data-slot="attack" tabindex="-1"><img src="assets/ui/attack.webp" alt=""></button><button class="tbtn tbtn-skill tbtn-s1" data-key="i" data-slot="skill1" tabindex="-1"><img src="assets/ui/skill1.webp" alt=""><span class="cooldown-wipe"></span><em class="cooldown-num"></em></button><button class="tbtn tbtn-skill tbtn-s2" data-key="o" data-slot="skill2" tabindex="-1"><img src="assets/ui/skill2.webp" alt=""><span class="cooldown-wipe"></span><em class="cooldown-num"></em></button><button class="tbtn tbtn-skill tbtn-ult" data-key="p" data-slot="ultimate" tabindex="-1"><img src="assets/ui/squadron-icon.webp" alt=""><span class="cooldown-wipe"></span><em class="cooldown-num"></em></button></div></section>
|
||||||
<div id="load-state" class="load-state"><span class="loading-glyph">✦</span><strong>AETHER CLASH</strong><span id="load-message">Menyiapkan arena…</span></div>
|
<div id="load-state" class="load-state"><span class="loading-glyph">✦</span><strong>AETHER CLASH</strong><span id="load-message">Menyiapkan arena…</span></div>
|
||||||
<dialog id="settings-panel"><div class="dialog-kicker">AETHER CLASH / SETTINGS</div><h2>Pengaturan arena</h2><p>Atur audio, tampilan, dan kontrol permainan.</p><label class="setting-row training-only"><span>Karakter pemain<small>Mengganti karakter memulai ulang latihan</small></span><select id="character-select"><option value="arco">ARCO · Mecha</option><option value="fenr">FENR · Demi-Human</option><option value="mira">MIRA · Mecha</option><option value="cora">CORA · Demi-Human</option><option value="naja">NAJA · Demi-Human</option><option value="haldor">HALDOR · Mecha</option><option value="zanni">ZANNI · Mecha</option><option value="isolde">ISOLDE · Mecha</option><option value="rhea">RHEA · Mecha</option><option value="solan">SOLAN · Demi-Human</option><option value="nib">NIB · Demi-Human</option><option value="edda">EDDA · Demi-Human</option></select></label><label class="setting-row training-only"><span>Lawan aktif<small>Aktifkan serangan CPU saat latihan</small></span><input type="checkbox" id="ai-toggle" checked></label><label class="setting-row"><span>Visualisasi hitbox<small>Area tubuh dan jangkauan serangan</small></span><input type="checkbox" id="hitbox-toggle"></label><label class="setting-row"><span>Audio aktif<small>Suara karakter, benturan, dan skill</small></span><input type="checkbox" id="sound-toggle" checked></label><label class="setting-row"><span>Musik latar<small>Midday Showdown, diputar berulang di menu dan arena</small></span><input type="checkbox" id="music-toggle" checked></label><label class="volume-row"><span>Musik</span><input type="range" id="music-slider" min="0" max="100" value="5" aria-label="Volume musik"><output id="music-value">5%</output></label><label class="setting-row"><span>Animasi latar menu<small>Video loop pada main menu</small></span><input type="checkbox" id="menu-video-toggle" checked></label><label class="volume-row"><span>Suara</span><input type="range" id="volume-slider" min="0" max="100" value="45" aria-label="Volume audio"><output id="volume-value">45%</output></label><div class="dialog-buttons"><button id="sound-test">Tes audio</button><button id="fullscreen-btn">Layar penuh</button></div><details class="controls-help"><summary>Kontrol keyboard</summary><p>A / D · Gerak 2× A / D · Lari<br>W · Lompat S · Menunduk / turun cepat<br>2× S · Salto SPACE · Kombo 3 pukulan<br>I / O · Skill P · Ultimate</p></details><button class="primary-button" id="close-settings">Kembali ke arena <span>↗</span></button></dialog>
|
<dialog id="settings-panel"><div class="dialog-kicker">AETHER CLASH / SETTINGS</div><h2>Pengaturan arena</h2><p>Atur audio, tampilan, dan kontrol permainan.</p><label class="setting-row training-only"><span>Karakter pemain<small>Mengganti karakter memulai ulang latihan</small></span><select id="character-select"><option value="arco">ARCO · Mecha</option><option value="fenr">FENR · Demi-Human</option><option value="mira">MIRA · Mecha</option><option value="cora">CORA · Demi-Human</option><option value="naja">NAJA · Demi-Human</option><option value="haldor">HALDOR · Mecha</option><option value="zanni">ZANNI · Mecha</option><option value="isolde">ISOLDE · Mecha</option><option value="rhea">RHEA · Mecha</option><option value="solan">SOLAN · Demi-Human</option><option value="browo">BRO WO · Human</option><option value="nib">NIB · Demi-Human</option><option value="edda">EDDA · Demi-Human</option></select></label><label class="setting-row training-only"><span>Lawan aktif<small>Aktifkan serangan CPU saat latihan</small></span><input type="checkbox" id="ai-toggle" checked></label><label class="setting-row"><span>Visualisasi hitbox<small>Area tubuh dan jangkauan serangan</small></span><input type="checkbox" id="hitbox-toggle"></label><label class="setting-row"><span>Audio aktif<small>Suara karakter, benturan, dan skill</small></span><input type="checkbox" id="sound-toggle" checked></label><label class="setting-row"><span>Musik latar<small>Midday Showdown, diputar berulang di menu dan arena</small></span><input type="checkbox" id="music-toggle" checked></label><label class="volume-row"><span>Musik</span><input type="range" id="music-slider" min="0" max="100" value="5" aria-label="Volume musik"><output id="music-value">5%</output></label><label class="setting-row"><span>Animasi latar menu<small>Video loop pada main menu</small></span><input type="checkbox" id="menu-video-toggle" checked></label><label class="volume-row"><span>Suara</span><input type="range" id="volume-slider" min="0" max="100" value="45" aria-label="Volume audio"><output id="volume-value">45%</output></label><div class="dialog-buttons"><button id="sound-test">Tes audio</button><button id="fullscreen-btn">Layar penuh</button></div><details class="controls-help"><summary>Kontrol keyboard</summary><p>A / D · Gerak 2× A / D · Lari<br>W · Lompat S · Menunduk / turun cepat<br>2× S · Salto SPACE · Kombo 3 pukulan<br>I / O · Skill P · Ultimate</p></details><button class="primary-button" id="close-settings">Kembali ke arena <span>↗</span></button></dialog>
|
||||||
<dialog id="pause-panel"><div class="dialog-kicker">AETHER CLASH / PAUSE</div><h2>PAUSED</h2><p>Pertarungan dijeda. Siap melanjutkan?</p><button class="primary-button" id="resume-btn">Lanjut bertarung <span>↗</span></button><button class="text-button" id="restart-btn">Mulai ulang</button><button class="text-button" id="back-menu">Kembali ke main menu</button></dialog>
|
<dialog id="pause-panel"><div class="dialog-kicker">AETHER CLASH / PAUSE</div><h2>PAUSED</h2><p>Pertarungan dijeda. Siap melanjutkan?</p><button class="primary-button" id="resume-btn">Lanjut bertarung <span>↗</span></button><button class="text-button" id="restart-btn">Mulai ulang</button><button class="text-button" id="back-menu">Kembali ke main menu</button></dialog>
|
||||||
</main><section id="front-menu" aria-label="Main menu Aether Clash"></section><script src="assets/mecha/manifest.js"></script><script src="assets/stage-config.js"></script><script src="assets/ui/drone-config.js"></script><script src="assets/fenr/human/manifest.js"></script><script src="assets/fenr/wolf/manifest.js"></script><script src="fenr.js"></script><script src="assets/mira/manifest.js"></script><script src="mira.js"></script><script src="assets/cora/manifest.js"></script><script src="cora.js"></script><script src="assets/naja/manifest.js"></script><script src="naja.js"></script><script src="assets/haldor/manifest.js"></script><script src="haldor.js"></script><script src="assets/zanni/manifest.js"></script><script src="zanni.js"></script><script src="assets/isolde/manifest.js"></script><script src="isolde.js"></script><script src="assets/rhea/manifest.js"></script><script src="rhea.js"></script><script src="assets/solan/manifest.js"></script><script src="solan.js"></script><script src="assets/nib/manifest.js"></script><script src="nib.js"></script><script src="assets/edda/manifest.js"></script><script src="edda.js"></script><script src="assets/audio/announcer/manifest.js"></script><script src="announcer.js"></script><script src="match.js"></script><script>window.FRONTEND_ENABLED=true;</script><script src="game.js"></script><script src="touch.js"></script><script src="assets/showcase/showcase.js"></script><script src="menu.js"></script></body></html>
|
</main><section id="front-menu" aria-label="Main menu Aether Clash"></section><script src="assets/mecha/manifest.js"></script><script src="assets/stage-config.js"></script><script src="assets/ui/drone-config.js"></script><script src="assets/fenr/human/manifest.js"></script><script src="assets/fenr/wolf/manifest.js"></script><script src="fenr.js"></script><script src="assets/mira/manifest.js"></script><script src="mira.js"></script><script src="assets/cora/manifest.js"></script><script src="cora.js"></script><script src="assets/naja/manifest.js"></script><script src="naja.js"></script><script src="assets/haldor/manifest.js"></script><script src="haldor.js"></script><script src="assets/zanni/manifest.js"></script><script src="zanni.js"></script><script src="assets/isolde/manifest.js"></script><script src="isolde.js"></script><script src="assets/rhea/manifest.js"></script><script src="rhea.js"></script><script src="assets/solan/manifest.js"></script><script src="solan.js"></script><script src="assets/browo/manifest.js"></script><script src="browo.js"></script><script src="assets/nib/manifest.js"></script><script src="nib.js"></script><script src="assets/edda/manifest.js"></script><script src="edda.js"></script><script src="assets/audio/announcer/manifest.js"></script><script src="announcer.js"></script><script src="match.js"></script><script>window.FRONTEND_ENABLED=true;</script><script src="game.js"></script><script src="touch.js"></script><script src="assets/showcase/showcase.js"></script><script src="menu.js"></script></body></html>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
1
menu.js
|
|
@ -12,6 +12,7 @@
|
||||||
...(window.Zanni&&window.ZANNI_MANIFEST?{zanni:{name:'ZANNI',tag:'THE CLOCKWORK JESTER',race:'MECHA',portrait:'assets/zanni/ui/portrait.webp',art:'assets/menu/zanni-select.webp',detail:'Arms that stretch. Jokes that sting.',basic:'SCISSOR JAB',ultimate:'GRAND FINALE',style:'Trickster / extending scissor-arm strikes and bladed rings',color:'#c9d64a'}}:{}),
|
...(window.Zanni&&window.ZANNI_MANIFEST?{zanni:{name:'ZANNI',tag:'THE CLOCKWORK JESTER',race:'MECHA',portrait:'assets/zanni/ui/portrait.webp',art:'assets/menu/zanni-select.webp',detail:'Arms that stretch. Jokes that sting.',basic:'SCISSOR JAB',ultimate:'GRAND FINALE',style:'Trickster / extending scissor-arm strikes and bladed rings',color:'#c9d64a'}}:{}),
|
||||||
...(window.Isolde&&window.ISOLDE_MANIFEST?{isolde:{name:'ISOLDE',tag:'THE WHITE STRIDER',race:'MECHA',portrait:'assets/isolde/ui/portrait.webp',art:'assets/menu/isolde-select.webp',detail:'Long legs, longer lance, zero mercy.',basic:'LANCE LINE',ultimate:'SKYFALL LANCES',style:'Long-range lancer / stilt-leg charges',color:'#9fd4ff'}}:{}),
|
...(window.Isolde&&window.ISOLDE_MANIFEST?{isolde:{name:'ISOLDE',tag:'THE WHITE STRIDER',race:'MECHA',portrait:'assets/isolde/ui/portrait.webp',art:'assets/menu/isolde-select.webp',detail:'Long legs, longer lance, zero mercy.',basic:'LANCE LINE',ultimate:'SKYFALL LANCES',style:'Long-range lancer / stilt-leg charges',color:'#9fd4ff'}}:{}),
|
||||||
...(window.Rhea&&window.RHEA_MANIFEST?{rhea:{name:'RHEA',tag:'THE LITTLE ORRERY',race:'MECHA',portrait:'assets/rhea/ui/portrait.webp',art:'assets/menu/rhea-select.webp',detail:'Homework done. Planets armed. Class dismissed.',basic:'ORBIT STRIKE',ultimate:'GRAND ORRERY',style:'Zoner / orbiting orrery spheres',color:'#c7485e'}}:{}),
|
...(window.Rhea&&window.RHEA_MANIFEST?{rhea:{name:'RHEA',tag:'THE LITTLE ORRERY',race:'MECHA',portrait:'assets/rhea/ui/portrait.webp',art:'assets/menu/rhea-select.webp',detail:'Homework done. Planets armed. Class dismissed.',basic:'ORBIT STRIKE',ultimate:'GRAND ORRERY',style:'Zoner / orbiting orrery spheres',color:'#c7485e'}}:{}),
|
||||||
|
...(window.Browo&&window.BROWO_MANIFEST?{browo:{name:'BRO WO',tag:'THE PALM RANGER',race:'HUMAN',portrait:'assets/browo/ui/portrait.webp',art:'assets/menu/browo-select.webp',detail:'Steady boots. Wide hat. Whole forests.',basic:'TINJU SAFARI',ultimate:'HUTAN SAWIT',style:'Bruiser / palm trees and area slam',color:'#c9b87a'}}:{}),
|
||||||
...(window.Solan&&window.SOLAN_MANIFEST?{solan:{name:'SOLAN',tag:'THE SUNMANE',race:'DEMI-HUMAN',portrait:'assets/solan/ui/portrait.webp',art:'assets/menu/solan-select.webp',detail:'Golden mane, heavy blade, louder roar.',basic:'SUNBLADE',ultimate:'SUNMANE ROAR',style:'Powerhouse / greatsword and roar',color:'#f2b632'}}:{}),
|
...(window.Solan&&window.SOLAN_MANIFEST?{solan:{name:'SOLAN',tag:'THE SUNMANE',race:'DEMI-HUMAN',portrait:'assets/solan/ui/portrait.webp',art:'assets/menu/solan-select.webp',detail:'Golden mane, heavy blade, louder roar.',basic:'SUNBLADE',ultimate:'SUNMANE ROAR',style:'Powerhouse / greatsword and roar',color:'#f2b632'}}:{}),
|
||||||
...(window.Nib&&window.NIB_MANIFEST?{nib:{name:'NIB',tag:'THE ROOFTOP POST',race:'DEMI-HUMAN',portrait:'assets/nib/ui/portrait.webp',art:'assets/menu/nib-select.webp',detail:'Every letter delivered. Every punch, too.',basic:'BATON FLURRY',ultimate:'SPECIAL DELIVERY',style:'Rushdown / twin courier batons',color:'#8fd4ff'}}:{}),
|
...(window.Nib&&window.NIB_MANIFEST?{nib:{name:'NIB',tag:'THE ROOFTOP POST',race:'DEMI-HUMAN',portrait:'assets/nib/ui/portrait.webp',art:'assets/menu/nib-select.webp',detail:'Every letter delivered. Every punch, too.',basic:'BATON FLURRY',ultimate:'SPECIAL DELIVERY',style:'Rushdown / twin courier batons',color:'#8fd4ff'}}:{}),
|
||||||
...(window.Edda&&window.EDDA_MANIFEST?{edda:{name:'EDDA',tag:'THE SHELL SAGE',race:'DEMI-HUMAN',portrait:'assets/edda/ui/portrait.webp',art:'assets/menu/edda-select.webp',detail:'Slow to anger, impossible to knock down.',basic:'STAFF FORMS',ultimate:'ELDER TORTOISE',style:'Counter defender / staff and shell guard',color:'#8fe3b4'}}:{})
|
...(window.Edda&&window.EDDA_MANIFEST?{edda:{name:'EDDA',tag:'THE SHELL SAGE',race:'DEMI-HUMAN',portrait:'assets/edda/ui/portrait.webp',art:'assets/menu/edda-select.webp',detail:'Slow to anger, impossible to knock down.',basic:'STAFF FORMS',ultimate:'ELDER TORTOISE',style:'Counter defender / staff and shell guard',color:'#8fe3b4'}}:{})
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ dialog{margin:auto;background:linear-gradient(140deg,#1c303d,#101e2b);color:#f9f
|
||||||
.form-timers{position:absolute;top:140px;left:4%;right:4%;display:flex;justify-content:space-between;pointer-events:none;z-index:3}
|
.form-timers{position:absolute;top:140px;left:4%;right:4%;display:flex;justify-content:space-between;pointer-events:none;z-index:3}
|
||||||
.form-timer{position:relative;min-width:120px;padding:7px 13px 10px;background:#17291de8;color:#ffe0a5;border:1px solid #a67e43;font:700 16px Rajdhani;letter-spacing:1.4px;box-shadow:0 3px 14px #0004}
|
.form-timer{position:relative;min-width:120px;padding:7px 13px 10px;background:#17291de8;color:#ffe0a5;border:1px solid #a67e43;font:700 16px Rajdhani;letter-spacing:1.4px;box-shadow:0 3px 14px #0004}
|
||||||
.form-timer:after{content:'';position:absolute;left:0;bottom:0;width:calc(var(--remaining,1)*100%);height:3px;background:#e7bd76}.form-timer[hidden]{visibility:hidden;display:block}
|
.form-timer:after{content:'';position:absolute;left:0;bottom:0;width:calc(var(--remaining,1)*100%);height:3px;background:#e7bd76}.form-timer[hidden]{visibility:hidden;display:block}
|
||||||
#enemy-form-timer{margin-left:auto}.fenr-cutin{background:linear-gradient(100deg,#202e1b,#584326 60%,#202b1d);border-color:#e6c186}.fenr-cutin .cutin-kicker{color:#d5e7a5}.fenr-cutin .cutin-caption em{color:#e9aa71}.mira-cutin{background:linear-gradient(100deg,#2a1640,#5a2f6d 58%,#24153a);border-color:#ffd978}.mira-cutin .cutin-kicker{color:#ffc4ec}.mira-cutin .cutin-caption em{color:#ffd978}.cora-cutin{background:linear-gradient(100deg,#150f26,#3b2758 58%,#120d20);border-color:#f0b35a}.cora-cutin .cutin-kicker{color:#cdb6ff}.cora-cutin .cutin-caption em{color:#f0b35a}.naja-cutin{background:linear-gradient(100deg,#0d2a33,#1f4652 55%,#2b2350);border-color:#e3bf78}.naja-cutin .cutin-kicker{color:#f2d9a0}.naja-cutin .cutin-caption em{color:#e3bf78}.nib-cutin{background:linear-gradient(100deg,#0e1e2a,#2a5674 58%,#0b1720);border-color:#8fd4ff}.nib-cutin .cutin-kicker{color:#e8f6ff}.nib-cutin .cutin-caption em{color:#e8c48a}.edda-cutin{background:linear-gradient(100deg,#15231a,#3f6a4c 58%,#1a2016);border-color:#8fe3b4}.edda-cutin .cutin-kicker{color:#e9f7df}.edda-cutin .cutin-caption em{color:#e0c07a}.solan-cutin{background:linear-gradient(100deg,#261707,#684210 58%,#1a1005);border-color:#f2b632}.solan-cutin .cutin-kicker{color:#ffe3a0}.solan-cutin .cutin-caption em{color:#f2b632}.rhea-cutin{background:linear-gradient(100deg,#231015,#562231 58%,#1a0b0f);border-color:#e8c07a}.rhea-cutin .cutin-kicker{color:#f5e6c8}.rhea-cutin .cutin-caption em{color:#e8c07a}.isolde-cutin{background:linear-gradient(100deg,#171d25,#34465a 58%,#12171e);border-color:#bfe3ff}.isolde-cutin .cutin-kicker{color:#e6f4ff}.isolde-cutin .cutin-caption em{color:#8fd0ff}.zanni-cutin{background:linear-gradient(100deg,#141611,#2e3318 58%,#11120d);border-color:#d8e24a}.zanni-cutin .cutin-kicker{color:#eef39a}.zanni-cutin .cutin-caption em{color:#d8e24a}.haldor-cutin{background:linear-gradient(100deg,#1c1411,#4a2616 58%,#16100d);border-color:#ff9a3c}.haldor-cutin .cutin-kicker{color:#ffc58a}.haldor-cutin .cutin-caption em{color:#ff9a3c}
|
#enemy-form-timer{margin-left:auto}.fenr-cutin{background:linear-gradient(100deg,#202e1b,#584326 60%,#202b1d);border-color:#e6c186}.fenr-cutin .cutin-kicker{color:#d5e7a5}.fenr-cutin .cutin-caption em{color:#e9aa71}.mira-cutin{background:linear-gradient(100deg,#2a1640,#5a2f6d 58%,#24153a);border-color:#ffd978}.mira-cutin .cutin-kicker{color:#ffc4ec}.mira-cutin .cutin-caption em{color:#ffd978}.cora-cutin{background:linear-gradient(100deg,#150f26,#3b2758 58%,#120d20);border-color:#f0b35a}.cora-cutin .cutin-kicker{color:#cdb6ff}.cora-cutin .cutin-caption em{color:#f0b35a}.naja-cutin{background:linear-gradient(100deg,#0d2a33,#1f4652 55%,#2b2350);border-color:#e3bf78}.naja-cutin .cutin-kicker{color:#f2d9a0}.naja-cutin .cutin-caption em{color:#e3bf78}.nib-cutin{background:linear-gradient(100deg,#0e1e2a,#2a5674 58%,#0b1720);border-color:#8fd4ff}.nib-cutin .cutin-kicker{color:#e8f6ff}.nib-cutin .cutin-caption em{color:#e8c48a}.edda-cutin{background:linear-gradient(100deg,#15231a,#3f6a4c 58%,#1a2016);border-color:#8fe3b4}.edda-cutin .cutin-kicker{color:#e9f7df}.edda-cutin .cutin-caption em{color:#e0c07a}.solan-cutin{background:linear-gradient(100deg,#261707,#684210 58%,#1a1005);border-color:#f2b632}.solan-cutin .cutin-kicker{color:#ffe3a0}.solan-cutin .cutin-caption em{color:#f2b632}.browo-cutin{background:linear-gradient(100deg,#1c2410,#5b5a2b 58%,#141a0b);border-color:#c9b87a}.browo-cutin .cutin-kicker{color:#e6e0b2}.browo-cutin .cutin-caption em{color:#c9b87a}.rhea-cutin{background:linear-gradient(100deg,#231015,#562231 58%,#1a0b0f);border-color:#e8c07a}.rhea-cutin .cutin-kicker{color:#f5e6c8}.rhea-cutin .cutin-caption em{color:#e8c07a}.isolde-cutin{background:linear-gradient(100deg,#171d25,#34465a 58%,#12171e);border-color:#bfe3ff}.isolde-cutin .cutin-kicker{color:#e6f4ff}.isolde-cutin .cutin-caption em{color:#8fd0ff}.zanni-cutin{background:linear-gradient(100deg,#141611,#2e3318 58%,#11120d);border-color:#d8e24a}.zanni-cutin .cutin-kicker{color:#eef39a}.zanni-cutin .cutin-caption em{color:#d8e24a}.haldor-cutin{background:linear-gradient(100deg,#1c1411,#4a2616 58%,#16100d);border-color:#ff9a3c}.haldor-cutin .cutin-kicker{color:#ffc58a}.haldor-cutin .cutin-caption em{color:#ff9a3c}
|
||||||
.setting-row select{max-width:180px;background:#172b30;color:#f5edd9;border:1px solid #778a7c;padding:8px;font:700 15px Rajdhani}
|
.setting-row select{max-width:180px;background:#172b30;color:#f5edd9;border:1px solid #778a7c;padding:8px;font:700 15px Rajdhani}
|
||||||
@media(max-width:620px){.form-timers{top:137px}.form-timer{font-size:12px;min-width:86px;padding:4px 7px 7px}.setting-row select{max-width:145px}}
|
@media(max-width:620px){.form-timers{top:137px}.form-timer{font-size:12px;min-width:86px;padding:4px 7px 7px}.setting-row select{max-width:145px}}
|
||||||
@media(max-height:500px) and (min-width:620px){.form-timers{top:97px}.form-timer{font-size:12px;padding:4px 8px 7px}}
|
@media(max-height:500px) and (min-width:620px){.form-timers{top:97px}.form-timer{font-size:12px;padding:4px 8px 7px}}
|
||||||
|
|
|
||||||