fighting-konoha/browo.js

65 lines
5.4 KiB
JavaScript

/* 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:9,ultimate:24}, castTime:.5, 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:135,duration:.34,hitAt:.5},
{damage:8,knockback:110,reach:135,duration:.38,hitAt:.5},
{damage:12,knockback:220,reach:155,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 long cheerful dance. `pulses` leaf bursts, `gap` s apart from `first`; every burst that reaches a rival
// inside `radius` stuns them (for gap + stunExtra s), deals `pulseDamage`, and refreshes a poison that drains `poisonDps`
// HP per second for `poisonTime` s without interrupting them.
const dance = { radius:150, pulses:5, first:.12, gap:.3, pulseDamage:3, stunExtra:.5, poisonDps:2.5, poisonTime:6, duration:1.7, loops:3 };
// Hutan Sawit (ultimate), seconds from the cast. The camera dives onto BRO WO under a dark screen (zoom to `zoomIn`),
// holds, then `treeCount` palms erupt in a rapid run toward the rival (`treeDamage` each) while the rival is held in place.
// At `giantAt` one giant palm rises (`giantRise`), leans back (`giantHold`) and is brought down on the rival (`slam`),
// dealing `giantDamage` and a knockdown. Afterwards BRO WO rampages (see `rage`).
const forest = { cutinDuration:.78, zoomIn:.45, lockAt:.3, treesAt:1.45, treeCount:10, treeGap:.11, treeDamage:3,
giantAt:2.85, giantRise:.55, giantHold:.3, slam:.16, giantDamage:40, tail:.55 };
forest.release = forest.giantAt + forest.giantRise + forest.giantHold + forest.slam;
forest.duration = forest.release + forest.tail;
// Mengamuk: for `duration` s after the ultimate BRO WO is stronger, longer-reaching and faster, and his three specials are
// replaced (skills 1 and 2 are refreshed with their own cooldowns, the ultimate is usable once and ends the rampage):
// skill1 TRUK KATERING - a delivery truck crosses the whole stage at `speed` px/s, hits once (`damage`, knockdown).
// skill2 HUTAN TERBAKAR - `palms` palms catch fire in a row ahead; each burns an area for `life` s at `dps` HP/s.
// ultimate TORNADO API SAWIT - a fire tornado hunts the rival, holds and burns them, then explodes.
const rage = { duration:10, damageMul:1.4, speedMul:1.25, reachAdd:25 };
const rageNames = ['TINJU API','TRUK KATERING','HUTAN TERBAKAR','TORNADO API SAWIT'];
const rageBalance = { cooldowns:{skill1:5,skill2:8,ultimate:999} };
const truck = { speed:1250, damage:24, tall:130, size:400 };
const fire = { palms:5, first:130, gap:105, radius:70, ignite:8, dps:6, life:3.6, delay:.09 };
// Tornado, seconds from the cast: the camera dives on BRO WO (`spawnAt`), the tornado is born and then chases the rival at
// `chase` px/s for `life` s; inside `radius` the rival is held, pulled to its core and burned for `tickDamage` every `tick` s.
// It ends in an explosion (`blast`, knockdown) and the rampage ends with it.
const tornado = { cutinDuration:.78, spawnAt:.85, life:3.6, chase:330, radius:150, tick:.22, tickDamage:4, blast:30, tail:.6 };
tornado.duration = tornado.spawnAt + tornado.life + tornado.tail;
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:0,duration:dance.duration,knockback:0,dance:true,loops:dance.loops,reach:dance.radius,hitAt:.04};
return {name:'ultimate',type:'ultimate',duration:balance.castTime,damage:0,hitAt:1};
}
// While `a.bwRage` is set (the game keeps it in step with the rampage) the three specials are the rage versions.
function rmove(name) {
if(name==='skill1')return {name,type:name,damage:truck.damage,duration:.6,knockback:320,truck:true,rage:true,reach:900,hitAt:.5};
if(name==='skill2')return {name,type:name,damage:fire.ignite,duration:.62,knockback:120,fire:true,rage:true,reach:fire.first+fire.gap*fire.palms,hitAt:.55};
return {name:'ultimate',type:'ultimate',duration:balance.castTime,damage:0,hitAt:1,rage:true};
}
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;
const rg=!!a.bwRage&&name!=='attack';
if(name!=='attack')a.cooldowns[name]=rg?rageBalance.cooldowns[name]:balance.cooldowns[name];
a.action={...(rg?rmove(name):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,rage,rageNames,rageBalance,truck,fire,tornado,move,rmove,start,refund};
})();