diff --git a/languages/zh-CN.js b/languages/zh-CN.js index d5bbb564..08f81955 100644 --- a/languages/zh-CN.js +++ b/languages/zh-CN.js @@ -33,7 +33,7 @@ delay: tp`${'icon'}延迟敌人的攻击`, //icon mass_attack: tp`所有攻击变为${'icon'}全体攻击`, leader_change: tp`${'icon'}将${'target'}换为队长,再次使用则换回来`, - no_skyfall: tp`【${'icon'}天降的宝珠不会消除】`, + no_skyfall: tp`${'icon'}天降的宝珠不会消除`, self_harm: tp`${'icon'}${'stats'}减少${'value'}`, heal: tp`${'icon'}回复 ${'value'} 的 ${'stats'}`, unbind_normal: tp`${'icon'}封锁状态减少${'turns'}`, @@ -43,6 +43,7 @@ poison: tp`${'icon'}使${'target'}全体中毒,每回合损失${'belong_to'} ${'value'} 的 ${'stats'}`, time_extend: tp`${'icon'}宝珠移动时间 ${'value'}`, follow_attack: tp`${'icon'}消除宝珠的回合,以${'belong_to'}${'value'}的伤害追打${'target'}(计算防御力)`, + follow_attack_fixed: tp`追加${'target'}的${'icon'}固定伤害`, auto_heal_buff: tp`行动结束后${'icon'}回复${'value'}的${'stats'}`, auto_heal: tp`${'icon'}消除宝珠的回合,回复${'belong_to'}${'value'}的${'stats'}`, ctw: tp`${'icon'}${'value'}内时间停止,可以任意移动宝珠`, @@ -50,7 +51,7 @@ resolve: tp`${'icon'}如${'stats'}≧${'value'},受到单一次致命攻击时,${'prob'}将会以1点 HP 生还`, board_change: tp`全画面的宝珠变为${'orbs'}`, skill_boost: tp`自身以外成员的技能冷却储备${'icon'}${'turns'}`, - add_combo: tp`结算时连击数增加${'value'}c${'icon'}`, + add_combo: tp`结算时连击数增加${'value'}${'icon'}`, fixed_time: tp`【${'icon'}操作时间固定${'value'}】`, min_match_length: tp`【限定≥${'value'}珠才能消除】`, drop_refresh: tp`全板刷新`, @@ -76,7 +77,18 @@ rate_multiply_coin: tp`${'icon'}金币掉落率`, rate_multiply_exp: tp`${'icon'}等级经验倍率`, reduce_damage: tp`${'condition'}受到的${'attrs'}伤害${'icon'}减少${'value'}`, - power_up: tp`${'condition'}${'targets'}${'value'}${'reduceDamage'}`, + power_up: tp`${'condition'}${'targets'}${'value'}${'reduceDamage'}${'addCombo'}${'followAttack'}`, + }, + power: { + unknown: tp`[ 未知能力提升: ${'type'} ]`, + scale_attributes: tp`${'attrs'}中${'min'}种属性同时攻击时${'stats'}${'bonus'}`, + scale_attributes_bonus: tp`,每多1种${'bonus'},最大${'max'}种时${'stats_max'}`, + scale_combos: tp`${'min'}连击时,${'stats'}${'bonus'}`, + scale_combos_bonus: tp`,每多1连击${'bonus'},最大${'max'}连击时${'stats_max'}`, + scale_match_attrs: tp`${'matches'}中${'min'}串匹配时,${'stats'}${'bonus'}`, + scale_match_attrs_bonus: tp`,每多1串${'bonus'},最大${'max'}串时${'stats_max'}`, + scale_match_length: tp`相连消除${'min'}个${'attrs'}时${'stats'}${'bonus'}`, + scale_match_length_bonus: tp`,每多1个${'bonus'},最大${'max'}个时${'stats_max'}`, }, cond: { unknown: tp`[ 未知条件 ]`, @@ -95,9 +107,6 @@ compo_type_series: tp`队员组成全为 ${'ids'} 系列时`, compo_type_evolution: tp`队员组成全为 ${'ids'} 进化时`, }, - power: { - unknown: tp`[ 未知能力提升: ${'type'} ]`, - }, position: { top: tp`上方第${'pos'}横行`, bottom: tp`下方第${'pos'}横行`, @@ -190,6 +199,8 @@ [7]: tp`${'icon'}毒`, [8]: tp`${'icon'}剧毒`, [9]: tp`${'icon'}炸弹`, + _5color: tp`${'icon'}5色`, + _6color: tp`${'_5color'}+${'orb_rcv'}`, all: tp`所有`, any: tp`任何`, }, @@ -1662,7 +1673,7 @@ function parseSkillDescription(skill) { case 219: //192同时消除多色中所有色,219任意消除多色中1色 str = `相连消除${sk[1]}个或以上的${getOrbsAttrString(sk[0], true)}宝珠时,结算时连击数+${sk[2]}`; break; - case 220: //192同时消除多色中所有色,219任意消除多色中1色 + case 220: str = `以L字形消除5个${getOrbsAttrString(sk[0], true)}宝珠时,结算时连击数+${sk[1]}`; break; case 223: diff --git a/script-skill-parser.js b/script-skill-parser.js index 5ecd4c46..77d08684 100644 --- a/script-skill-parser.js +++ b/script-skill-parser.js @@ -65,6 +65,16 @@ Attributes.all = function () { this.Dark ]; } +Attributes._6color = function () { + return [ + this.Fire, + this.Water, + this.Wood, + this.Light, + this.Dark, + this.Heart + ]; +} Attributes.orbs = function () { return [ this.Fire, @@ -530,8 +540,8 @@ const p = { scaleCombos: function (min, max, baseMul, bonusMul) { return { kind: SkillPowerUpKind.ScaleCombos ,...this.scale(min, max, baseMul, bonusMul) }; }, - scaleMatchLength: function (attrs, min, max, baseMul, bonusMul) { - return { kind: SkillPowerUpKind.ScaleMatchLength, attrs: attrs ,...this.scale(min, max, baseMul, bonusMul) }; + scaleMatchLength: function (attrs, min, max, baseMul, bonusMul, matchAll = false) { + return { kind: SkillPowerUpKind.ScaleMatchLength, attrs: attrs, matchAll ,...this.scale(min, max, baseMul, bonusMul) }; }, scaleMatchAttrs: function (matches, min, max, baseMul, bonusMul) { return { kind: SkillPowerUpKind.ScaleMatchAttrs, matches: matches ,...this.scale(min, max, baseMul, bonusMul) }; @@ -577,13 +587,13 @@ function generateOrbs(orbs, exclude, count) { function fixedOrbs() { return { kind: SkillKinds.FixedOrbs, generates: Array.from(arguments) }; } -function powerUp(attrs, types, value, condition, reduceDamageValue) { +function powerUp(attrs, types, value, condition, reduceDamageValue, addCombo, followAttack) { if (value.kind === SkillPowerUpKind.Multiplier) { let hp = value.hp, atk = value.atk, rcv = value.rcv; if (hp === 1 && atk === 1 && rcv === 1 && !reduceDamage) return null; } - return { kind: SkillKinds.PowerUp, attrs: attrs, types: types, condition: condition, value: value, reduceDamage: reduceDamageValue }; + return { kind: SkillKinds.PowerUp, attrs: attrs, types: types, condition: condition, value: value, reduceDamage: reduceDamageValue, addCombo: addCombo, followAttack: followAttack }; } function counterAttack(attr, prob, value) { return { kind: SkillKinds.CounterAttack, attr: attr, prob: prob, value: value }; @@ -981,6 +991,9 @@ const parsers = { [191](turns) { return activeTurns(turns, voidEnemyBuff(['damage-void'])); }, + [192](attrs, len, mul, combo) { + return powerUp(null, null, p.scaleMatchLength(flags(attrs), len, len, [mul, 100], [0, 0], true), null, null, combo); + }, [195](percent) { return selfHarm(percent ? v.xHP(percent) : v.constantTo(1)); }, @@ -1510,7 +1523,7 @@ function renderSkill(skill, option = {}) break; } case SkillKinds.PowerUp: { - let attrs = skill.attrs, types = skill.types, condition = skill.condition, value = skill.value, reduceDamage = skill.reduceDamage; + let attrs = skill.attrs, types = skill.types, condition = skill.condition, value = skill.value, reduceDamage = skill.reduceDamage, addCombo = skill.addCombo, followAttack = skill.followAttack; let targets = []; if (attrs?.length && !isEqual(attrs, Attributes.all())) targets.push(renderAttrs(attrs || [], {affix: true})); if (types?.length) targets.push(renderTypes(types || [], {affix: true})); @@ -1527,6 +1540,15 @@ function renderSkill(skill, option = {}) icon: createIcon("reduce-damage"), })); } + if (addCombo) { + dict.addCombo = tsp.word.comma().ap(renderSkill({kind: SkillKinds.AddCombo, value: addCombo})); + } + if (followAttack) { + dict.followAttack = tsp.word.comma().ap(tsp.skill.follow_attack_fixed({ + value: renderValue(v.constant(followAttack)), + icon: createIcon("follow-attack"), + })); + } frg.ap(tsp.skill.power_up(dict)); break; } @@ -1591,6 +1613,17 @@ function renderOrbs(attrs, option = {}) { { contentFrg = option.any ? tsp.orbs.any() : tsp.orbs.all(); } + else if (isEqual(attrs, Attributes.all())) + { + contentFrg = renderOrbs('_5color'); + } + else if (isEqual(attrs, Attributes._6color())) + { + contentFrg = tsp.orbs._6color({ + _5color: renderOrbs('_5color'), + orb_rcv: renderOrbs(5), + }); + } else { contentFrg = attrs.map(attr => { @@ -1724,29 +1757,89 @@ function renderPowerUp(powerUp) { frg.ap(renderStats(hp, atk, rcv)); break; } - /*case SkillPowerUpKind.ScaleAttributes: { + case SkillPowerUpKind.ScaleAttributes: { let attrs = powerUp.attrs, min = powerUp.min, max = powerUp.max, baseAtk = powerUp.baseAtk, baseRcv = powerUp.baseRcv, bonusAtk = powerUp.bonusAtk, bonusRcv = powerUp.bonusRcv; - return <> - ≥ {min} of [{renderAttrs(attrs)}] ⇒ {renderStats(1, baseAtk, baseRcv)} - {max !== min && <> for each ≤ {max} attributes: {renderStats(0, bonusAtk, bonusRcv, false)}} - ; + + let dict = { + attrs: renderOrbs(attrs, {affix: true}), + min: min, + stats: renderStats(1, baseAtk, baseRcv), + } + if (max !== min) + { + let _dict = { + max: max, + bonus: renderStats(0, bonusAtk, bonusRcv, false), + stats_max: renderStats(1, baseAtk + bonusAtk * (max-min), baseRcv + bonusRcv * (max-min)), + } + dict.bonus = frg.ap(tsp.power.scale_attributes_bonus(_dict)); + } + frg.ap(tsp.power.scale_attributes(dict)); + + break; } case SkillPowerUpKind.ScaleCombos: { - const { min, max, baseAtk, baseRcv, bonusAtk, bonusRcv } = powerUp as SkillPowerUp.Scale; - return <> - ≥ {min} combos ⇒ {renderStats(1, baseAtk, baseRcv)} - {max !== min && <> for each ≤ {max} combos: {renderStats(0, bonusAtk, bonusRcv, false)}} - ; + let min = powerUp.min, max = powerUp.max, baseAtk = powerUp.baseAtk, baseRcv = powerUp.baseRcv, bonusAtk = powerUp.bonusAtk, bonusRcv = powerUp.bonusRcv; + let dict = { + min: min, + stats: renderStats(1, baseAtk, baseRcv), + } + if (max !== min) + { + let _dict = { + max: max, + bonus: renderStats(0, bonusAtk, bonusRcv, false), + stats_max: renderStats(1, baseAtk + bonusAtk * (max-min), baseRcv + bonusRcv * (max-min)), + } + dict.bonus = frg.ap(tsp.power.scale_combos_bonus(_dict)); + } + frg.ap(tsp.power.scale_combos(dict)); + + break; } case SkillPowerUpKind.ScaleMatchAttrs: { - const { matches, min, max, baseAtk, baseRcv, bonusAtk, bonusRcv } = powerUp as SkillPowerUp.ScaleMultiAttrs; - return <> - ≥ {min} matches of [{matches.map((attrs, i) => - {i !== 0 && ', '}{renderAttrs(attrs)} - )}] ⇒ {renderStats(1, baseAtk, baseRcv)} - {max !== min && <> for each ≤ {max} matches: {renderStats(0, bonusAtk, bonusRcv, false)}} - ; + let matches = powerUp.matches, min = powerUp.min, max = powerUp.max, baseAtk = powerUp.baseAtk, baseRcv = powerUp.baseRcv, bonusAtk = powerUp.bonusAtk, bonusRcv = powerUp.bonusRcv; + let dict = { + matches: matches.map(orbs=>renderOrbs(orbs)).nodeJoin(tsp.word.slight_pause()), + min: min, + stats: renderStats(1, baseAtk, baseRcv), + } + if (max !== min) + { + let _dict = { + max: max, + bonus: renderStats(0, bonusAtk, bonusRcv, false), + stats_max: renderStats(1, baseAtk + bonusAtk * (max-min), baseRcv + bonusRcv * (max-min)), + } + dict.bonus = frg.ap(tsp.power.scale_match_attrs_bonus(_dict)); + } + frg.ap(tsp.power.scale_match_attrs(dict)); + + break; } + case SkillPowerUpKind.ScaleMatchLength: { + let attrs = powerUp.attrs, min = powerUp.min, max = powerUp.max, baseAtk = powerUp.baseAtk, baseRcv = powerUp.baseRcv, bonusAtk = powerUp.bonusAtk, bonusRcv = powerUp.bonusRcv; + + let dict = { + attrs: renderOrbs(attrs, {affix: true}), + min: min, + stats: renderStats(1, baseAtk, baseRcv), + } + if (max !== min) + { + let _dict = { + max: max, + bonus: renderStats(0, bonusAtk, bonusRcv, false), + stats_max: renderStats(1, baseAtk + bonusAtk * (max-min), baseRcv + bonusRcv * (max-min)), + } + dict.bonus = frg.ap(tsp.power.scale_match_length_bonus(_dict)); + } + frg.ap(tsp.power.scale_match_length(dict)); + + break; + } + /* + case SkillPowerUpKind.ScaleMatchLength: { const { attrs, min, max, baseAtk, baseRcv, bonusAtk, bonusRcv } = powerUp as SkillPowerUp.ScaleAttrs; return <> diff --git a/style-monsterimages.css b/style-monsterimages.css index fdf657c9..b8956ec2 100644 --- a/style-monsterimages.css +++ b/style-monsterimages.css @@ -1079,6 +1079,11 @@ icon.type animation: hidden-visible-animate 0.8s infinite ease-out alternate; } +.orb[data-orb-icon='_5color'] +{ + background-image: url(images/icon-skills.fw.png); + background-position-y:calc(-36px * 24); +} .orb[data-orb-icon='-1'] { width: auto; diff --git a/style.css b/style.css index 331edbc0..0d3ac326 100644 --- a/style.css +++ b/style.css @@ -3171,6 +3171,7 @@ table .orb-icon .icon-skill::after, .icon-skill::before { + font-weight: normal; display: inline-block; width: 36px; height: 36px;