Mediawiki:scmcchemistry.js
| Строка 30: | Строка 30: | ||
Narcotic: 'Наркотик', | Narcotic: 'Наркотик', | ||
Poison: 'Яд' | Poison: 'Яд' | ||
}; | }; | ||
var DAMAGE_LABELS = { | var DAMAGE_LABELS = { | ||
Airloss: 'кислородного голодания', | Airloss: 'урона от кислородного голодания', | ||
Asphyxiation: 'кислородного голодания', | Asphyxiation: 'урона от кислородного голодания', | ||
Bloodloss: 'кровопотери', | Bloodloss: 'урона от кровопотери', | ||
Blunt: 'тупого', Brute: 'механического', Burn: 'термического', | Blunt: 'тупого урона', | ||
Caustic: 'кислотного', Cellular: 'клеточного', Cold: 'холодового', | Brute: 'механического урона', | ||
Genetic: 'генетического', Heat: 'ожогового', Piercing: 'колотого', | Burn: 'термического урона', | ||
Poison: 'токсического', Radiation: 'радиационного', Slash: 'режущего', | Caustic: 'кислотного урона', | ||
Toxin: 'токсического' | Cellular: 'клеточного урона', | ||
Cold: 'холодового урона', | |||
Genetic: 'генетического урона', | |||
Heat: 'ожогового урона', | |||
Piercing: 'колотого урона', | |||
Poison: 'токсического урона', | |||
Radiation: 'радиационного урона', | |||
Slash: 'режущего урона', | |||
Toxin: 'токсического урона' | |||
}; | }; | ||
var | var EFFECT_TOKEN_RE = /(урона от кислородного голодания|урона от кровопотери|полностью лечит|дополнительно наносит|восстанавливает жизнеспособность|создаёт иммунитет|восстанавливает|возвращает|омолаживает|сокращает|удаляет|лечит|наносит|вызывает|заражает|поджигает|уничтожает|расходует|замедляет|снижает|повышает|механического(?: урона)?|тупого(?: урона)?|колотого(?: урона)?|режущего(?: урона)?|термического(?: урона)?|ожогового(?: урона)?|холодового(?: урона)?|токсического(?: урона)?|кислотного(?: урона)?|генетического(?: урона)?|клеточного(?: урона)?|радиационного(?: урона)?)/gi; | ||
var EFFECT_ACTION_CLASSES = { | |||
'полностью лечит': 'beneficial', 'лечит': 'beneficial', | |||
'восстанавливает': 'beneficial', 'восстанавливает жизнеспособность': 'beneficial', | |||
'возвращает': 'beneficial', 'омолаживает': 'beneficial', 'сокращает': 'beneficial', | |||
'удаляет': 'beneficial', 'создаёт иммунитет': 'beneficial', | |||
'наносит': 'harmful', 'дополнительно наносит': 'harmful', 'вызывает': 'harmful', | |||
'заражает': 'harmful', 'поджигает': 'harmful', 'уничтожает': 'harmful', | |||
'расходует': 'warning', 'замедляет': 'warning', | |||
'снижает': 'utility', 'повышает': 'utility' | |||
}; | }; | ||
var DAMAGE_TOKEN_CLASSES = [ | |||
{ pattern: /кислородного голодания|кровопотери/, className: 'oxygen' }, | |||
{ pattern: /механического|тупого|колотого|режущего/, className: 'physical' }, | |||
{ pattern: /термического|ожогового/, className: 'burn' }, | |||
{ pattern: /холодового/, className: 'cold' }, | |||
{ pattern: /токсического/, className: 'toxin' }, | |||
{ pattern: /кислотного/, className: 'acid' }, | |||
{ pattern: /генетического/, className: 'genetic' }, | |||
{ pattern: /клеточного/, className: 'cellular' }, | |||
{ pattern: /радиационного/, className: 'radiation' } | |||
]; | |||
var STATUS_LABELS = { | var STATUS_LABELS = { | ||
Jitter: 'дрожь', RMCUnconscious: 'потерю сознания', | |||
StatusEffectSeeingRainbow: 'галлюцинации', Unconscious: 'потерю сознания' | StatusEffectSeeingRainbow: 'галлюцинации', Unconscious: 'потерю сознания' | ||
}; | }; | ||
var EMOTE_LABELS = { | var EMOTE_LABELS = { | ||
Gasp: 'судорожный вдох', Laugh: 'смех', Scream: 'крик', Yawn: 'зевоту' | |||
}; | }; | ||
var | var PLANT_ATTRIBUTE_LABELS = { | ||
PlantAdjustGrowth: 'возраст растения', PlantAdjustHealth: 'здоровье растения', | PlantAdjustGrowth: 'возраст растения', PlantAdjustHealth: 'здоровье растения', | ||
PlantAdjustMutationLevel: 'уровень мутации', PlantAdjustMutationMod: ' | PlantAdjustMutationLevel: 'уровень мутации', PlantAdjustMutationMod: 'модификатор мутации', | ||
PlantAdjustNutrition: ' | PlantAdjustNutrition: 'уровень питания', PlantAdjustPests: 'уровень вредителей', | ||
PlantAdjustPotency: 'потенцию растения', PlantAdjustToxins: 'уровень токсинов', | PlantAdjustPotency: 'потенцию растения', PlantAdjustToxins: 'уровень токсинов', | ||
PlantAdjustWater: 'уровень воды', PlantAdjustWeeds: ' | PlantAdjustWater: 'уровень воды', PlantAdjustWeeds: 'уровень сорняков', | ||
PlantAffectGrowth: 'возраст растения' | |||
}; | }; | ||
var REAGENT_LABELS = { | var REAGENT_LABELS = { | ||
| Строка 154: | Строка 131: | ||
var text = String(value || '').trim(); | var text = String(value || '').trim(); | ||
return text ? text.charAt(0).toLocaleUpperCase('ru-RU') + text.slice(1) : text; | return text ? text.charAt(0).toLocaleUpperCase('ru-RU') + text.slice(1) : text; | ||
} | |||
function lowerFirst(value) { | |||
var text = String(value || ''); | |||
return text ? text.charAt(0).toLocaleLowerCase('ru-RU') + text.slice(1) : text; | |||
} | |||
function finishSentence(value) { | |||
var text = capitalizeFirst(String(value || '').trim()); | |||
return !text || /[.!?]$/.test(text) ? text : text + '.'; | |||
} | |||
function tagName(tag) { | |||
return String(tag || '').replace(/^!type:/, ''); | |||
} | } | ||
| Строка 172: | Строка 163: | ||
function getReagent(id) { | function getReagent(id) { | ||
return state.data.reagents[id] || state.data.dependencies[id] || null; | return state.data.reagents[id] || state.data.dependencies[id] || null; | ||
} | |||
function reagentName(id) { | |||
var reagent = getReagent(id); | |||
return reagent && reagent.name ? reagent.name : REAGENT_LABELS[id] || id; | |||
} | } | ||
| Строка 655: | Строка 651: | ||
add(wrapper, block); | add(wrapper, block); | ||
return wrapper; | return wrapper; | ||
} | |||
/* Исходная реализация описаний из js.txt. */ | |||
function originalEffectValue(effect) { | |||
var value = effect && effect.value; | |||
return value && typeof value === 'object' ? value : {}; | |||
} | |||
function originalWithChance(text, probability) { | |||
if (typeof probability !== 'number' || probability >= 1) { | |||
return finishSentence(text); | |||
} | |||
return finishSentence('С шансом ' + formatNumber(probability * 100) + '% ' + lowerFirst(text)); | |||
} | |||
function originalConditionText(condition) { | |||
var type = tagName(condition && condition.yamlTag); | |||
var value = originalEffectValue(condition); | |||
if (type === 'ReagentThreshold') { | |||
if (value.min !== undefined && value.max !== undefined) { | |||
return 'при количестве от ' + formatAmount(value.min) + ' до ' + formatAmount(value.max); | |||
} | |||
if (value.min !== undefined) { | |||
return 'при количестве от ' + formatAmount(value.min) + ' в организме'; | |||
} | |||
if (value.max !== undefined) { | |||
return 'при количестве до ' + formatAmount(value.max) + ' в организме'; | |||
} | |||
} | |||
if (type === 'Temperature') { | |||
if (value.min !== undefined && value.max !== undefined) { | |||
return 'при температуре от ' + formatNumber(value.min) + ' до ' + formatNumber(value.max) + ' K'; | |||
} | |||
if (value.min !== undefined) { | |||
return 'при температуре не ниже ' + formatNumber(value.min) + ' K'; | |||
} | |||
if (value.max !== undefined) { | |||
return 'при температуре не выше ' + formatNumber(value.max) + ' K'; | |||
} | |||
} | |||
if (type === 'MobStateCondition') { | |||
return value.mobstate === 'Critical' ? 'в критическом состоянии' : 'в состоянии «' + (value.mobstate || 'неизвестно') + '»'; | |||
} | |||
if (type === 'OrganType') { | |||
return (value.shouldHave === false ? 'кроме организмов типа ' : 'для организмов типа ') + (value.type || 'неизвестно'); | |||
} | |||
return type ? 'при выполнении условия «' + type + '»' : ''; | |||
} | |||
function originalThresholdMinimum(effect) { | |||
var conditions = originalEffectValue(effect).conditions; | |||
var minimum = null; | |||
if (!Array.isArray(conditions)) { | |||
return minimum; | |||
} | |||
conditions.forEach(function (condition) { | |||
if (tagName(condition && condition.yamlTag) !== 'ReagentThreshold') { | |||
return; | |||
} | |||
var value = originalEffectValue(condition); | |||
if (typeof value.min === 'number' && (minimum === null || value.min > minimum)) { | |||
minimum = value.min; | |||
} | |||
}); | |||
return minimum; | |||
} | |||
function originalEffectTier(effect, reagent) { | |||
var minimum = originalThresholdMinimum(effect); | |||
var properties = reagent.properties || {}; | |||
if (minimum === null) { | |||
return 'normal'; | |||
} | |||
if (typeof properties.criticalOverdose === 'number' && minimum >= properties.criticalOverdose) { | |||
return 'critical'; | |||
} | |||
if (typeof properties.overdose === 'number' && minimum >= properties.overdose) { | |||
return 'overdose'; | |||
} | |||
return 'normal'; | |||
} | |||
function originalRemainingConditions(effect, reagent) { | |||
var conditions = originalEffectValue(effect).conditions; | |||
if (!Array.isArray(conditions)) { | |||
return []; | |||
} | |||
return conditions.map(function (condition) { | |||
if (tagName(condition && condition.yamlTag) === 'ReagentThreshold' && originalEffectTier(effect, reagent) !== 'normal') { | |||
return ''; | |||
} | |||
return originalConditionText(condition); | |||
}).filter(Boolean); | |||
} | |||
function originalDamageChanges(damage, equalGroups) { | |||
var entries = []; | |||
if (equalGroups && Array.isArray(damage)) { | |||
damage.forEach(function (entry) { | |||
var key = Object.keys(entry || {})[0]; | |||
if (key) { | |||
entries.push({ id: key, amount: entry[key] }); | |||
} | |||
}); | |||
} else if (damage && typeof damage === 'object') { | |||
['groups', 'types'].forEach(function (key) { | |||
var values = damage[key]; | |||
if (!values || typeof values !== 'object') { | |||
return; | |||
} | |||
Object.keys(values).forEach(function (damageId) { | |||
entries.push({ id: damageId, amount: values[damageId] }); | |||
}); | |||
}); | |||
} | |||
return entries.map(function (entry) { | |||
var actionText = entry.amount < 0 ? 'Лечит' : 'Наносит'; | |||
return actionText + ' ' + formatNumber(Math.abs(entry.amount)) + ' ед. ' + | |||
(DAMAGE_LABELS[entry.id] || ('урона типа «' + entry.id + '»')) + ' в секунду'; | |||
}); | |||
} | |||
function originalDoseDescription(tier, text) { | |||
return { tier: tier, text: finishSentence(text) }; | |||
} | |||
function originalAddDoseEffects(result, reagent, overdoseText, criticalText) { | |||
var properties = reagent.properties || {}; | |||
if (properties.overdose !== undefined && overdoseText) { | |||
result.push(originalDoseDescription('overdose', overdoseText)); | |||
} | |||
if (properties.criticalOverdose !== undefined && criticalText) { | |||
result.push(originalDoseDescription('critical', criticalText)); | |||
} | |||
} | |||
function originalRmcEffectDescriptions(type, value, reagent) { | |||
var result = []; | |||
var potency = Number(value.potency || 0); | |||
var actual = potency || 0.5; | |||
var perSecond = potency * 0.25; | |||
var healing; | |||
if (type === 'Neogenetic') { | |||
healing = perSecond * (actual >= 2 ? 1.5 : 1); | |||
result.push(originalDoseDescription('normal', 'Лечит ' + formatNumber(healing) + ' ед. механического урона в секунду')); | |||
originalAddDoseEffects(result, reagent, | |||
'Наносит ' + formatNumber(perSecond) + ' ед. ожогового урона в секунду', | |||
'Дополнительно наносит ' + formatNumber(perSecond * 5) + ' ед. ожогового и ' + formatNumber(perSecond * 2) + ' ед. токсического урона в секунду'); | |||
return result; | |||
} | |||
if (type === 'Anticorrosive') { | |||
healing = perSecond * (actual >= 2 ? 1.5 : 1); | |||
result.push(originalDoseDescription('normal', 'Лечит ' + formatNumber(healing) + ' ед. термического урона в секунду')); | |||
originalAddDoseEffects(result, reagent, | |||
'Наносит по ' + formatNumber(perSecond) + ' ед. тупого и токсического урона в секунду', | |||
'Дополнительно наносит по ' + formatNumber(perSecond * 5) + ' ед. тупого и токсического урона в секунду'); | |||
return result; | |||
} | |||
if (type === 'Biocidic') { | |||
result.push(originalDoseDescription('normal', 'Наносит ' + formatNumber(perSecond) + ' ед. механического урона в секунду')); | |||
originalAddDoseEffects(result, reagent, | |||
'Наносит ' + formatNumber(perSecond * 2) + ' ед. механического урона в секунду', | |||
'Дополнительно наносит ' + formatNumber(perSecond * 5) + ' ед. механического урона в секунду'); | |||
return result; | |||
} | |||
if (type === 'Antitoxic') { | |||
result.push(originalDoseDescription('normal', 'Лечит по ' + formatNumber(perSecond * 2) + ' ед. токсического и генетического урона в секунду; удаляет 0,125 ед. токсичных веществ из крови в секунду')); | |||
originalAddDoseEffects(result, reagent, '', 'Дополнительно даёт 5% шанс потерять сознание на 10 секунд'); | |||
return result; | |||
} | |||
if (type === 'Oxygenating') { | |||
result.push(originalDoseDescription('normal', actual >= 3 ? | |||
'Полностью лечит урон от кислородного голодания и удаляет ' + formatAmount(perSecond) + ' Лексорина из крови в секунду' : | |||
'Лечит ' + formatNumber(perSecond) + ' ед. урона от кислородного голодания и удаляет ' + formatAmount(perSecond) + ' Лексорина из крови в секунду')); | |||
originalAddDoseEffects(result, reagent, | |||
'Наносит ' + formatNumber(perSecond * 0.5) + ' ед. токсического урона в секунду', | |||
'Дополнительно наносит ' + formatNumber(perSecond) + ' ед. тупого и ' + formatNumber(perSecond * 2) + ' ед. токсического урона в секунду'); | |||
return result; | |||
} | |||
if (type === 'Electrogenetic') { | |||
result.push(originalDoseDescription('normal', 'При дефибрилляции лечит по ' + formatNumber(potency * 10) + ' ед. механического, термического и токсического урона; расходует 1 ед. препарата')); | |||
return result; | |||
} | |||
if (type === 'Antihallucinogenic') { | |||
result.push(originalDoseDescription('normal', 'Удаляет по 2,5 ед. Токсина «Разрушитель разума» и космических наркотиков из крови; сокращает галлюцинации на ' + formatNumber(perSecond * 10) + ' сек. каждую секунду')); | |||
originalAddDoseEffects(result, reagent, | |||
'Наносит ' + formatNumber(perSecond) + ' ед. токсического урона в секунду', | |||
'Дополнительно наносит по ' + formatNumber(perSecond) + ' ед. тупого и ожогового урона, а также ' + formatNumber(perSecond * 3) + ' ед. токсического урона в секунду'); | |||
return result; | |||
} | |||
if (type === 'Focusing') { | |||
result.push(originalDoseDescription('normal', 'Удаляет ' + formatAmount(perSecond) + ' алкоголя из крови и сокращает опьянение, заикание и дрожь на ' + formatNumber(perSecond * 2) + ' сек. каждую секунду' + (actual >= 3 ? '; также снимает немоту и слепоту' : ''))); | |||
originalAddDoseEffects(result, reagent, | |||
'Наносит ' + formatNumber(perSecond) + ' ед. токсического урона в секунду', | |||
'Дополнительно наносит ' + formatNumber(perSecond * 3) + ' ед. токсического урона в секунду'); | |||
return result; | |||
} | |||
if (type === 'Thermostabilizing') { | |||
result.push(originalDoseDescription('normal', 'Возвращает температуру тела к норме, изменяя её примерно на ' + formatNumber(perSecond * 60) + ' K в секунду')); | |||
originalAddDoseEffects(result, reagent, 'Вызывает потерю сознания на 40 секунд', 'Дополнительно даёт 5% шанс потерять сознание на 10 секунд'); | |||
return result; | |||
} | |||
if (type === 'Hemogenic') { | |||
result.push(originalDoseDescription('normal', 'Если персонаж не голоден, восстанавливает ' + formatNumber(perSecond) + ' сл крови и расходует ' + formatNumber(perSecond) + ' ед. питания в секунду')); | |||
if (actual >= 3) { | |||
result.push(originalDoseDescription('normal', 'При избытке крови наносит ' + formatNumber(perSecond) + ' ед. тупого и ' + formatNumber(perSecond * 2) + ' ед. урона от кислородного голодания в секунду, а также замедляет')); | |||
} | |||
originalAddDoseEffects(result, reagent, | |||
'Наносит ' + formatNumber(perSecond) + ' ед. токсического урона в секунду', | |||
'Дополнительно расходует ' + formatNumber(perSecond * 5) + ' ед. питания в секунду'); | |||
return result; | |||
} | |||
if (type === 'Ketogenic') { | |||
result.push(originalDoseDescription('normal', 'Расходует ' + formatNumber(perSecond * 5) + ' ед. питания в секунду и ускоряет выведение алкоголя')); | |||
originalAddDoseEffects(result, reagent, | |||
'Дополнительно расходует ' + formatNumber(perSecond * 5) + ' ед. питания, наносит ' + formatNumber(perSecond) + ' ед. токсического урона в секунду и даёт ' + formatNumber(actual * 2.5) + '% шанс рвоты', | |||
'Вызывает потерю сознания на 40 секунд'); | |||
return result; | |||
} | |||
if (type === 'Nutritious') { | |||
var nutrition = ((Number(value.nutFactor || 0) * Number(value.nutMetabolism || 0)) + potency) * actual; | |||
result.push(originalDoseDescription('normal', 'Восстанавливает ' + formatNumber(nutrition) + ' ед. питания за цикл метаболизма')); | |||
return result; | |||
} | |||
if (type === 'Toxic') { | |||
result.push(originalDoseDescription('normal', 'Наносит ' + formatNumber(perSecond) + ' ед. токсического урона в секунду')); | |||
originalAddDoseEffects(result, reagent, | |||
'Наносит ' + formatNumber(perSecond * 2) + ' ед. токсического урона в секунду', | |||
'Дополнительно наносит ' + formatNumber(perSecond * 5) + ' ед. токсического урона в секунду'); | |||
return result; | |||
} | |||
if (type === 'Corrosive') { | |||
result.push(originalDoseDescription('normal', 'Наносит ' + formatNumber(perSecond) + ' ед. кислотного урона в секунду')); | |||
originalAddDoseEffects(result, reagent, | |||
'Наносит ' + formatNumber(perSecond * 2) + ' ед. кислотного урона в секунду', | |||
'Дополнительно наносит ' + formatNumber(perSecond * 5) + ' ед. кислотного урона в секунду'); | |||
return result; | |||
} | |||
if (type === 'Hypoxemic') { | |||
result.push(originalDoseDescription('normal', 'Наносит ' + formatNumber(perSecond * 2) + ' ед. урона от кислородного голодания в секунду и даёт 10% шанс судорожного вдоха')); | |||
originalAddDoseEffects(result, reagent, | |||
'Наносит по ' + formatNumber(perSecond) + ' ед. тупого и токсического урона, а также ' + formatNumber(perSecond * 5) + ' ед. урона от кислородного голодания в секунду', | |||
'Дополнительно наносит ' + formatNumber(perSecond * 5) + ' ед. тупого и ' + formatNumber(perSecond * 2) + ' ед. токсического урона в секунду'); | |||
return result; | |||
} | |||
if (type === 'Carcinogenic') { | |||
result.push(originalDoseDescription('normal', 'Наносит ' + formatNumber(perSecond * 0.5) + ' ед. клеточного урона в секунду')); | |||
originalAddDoseEffects(result, reagent, | |||
'Наносит ' + formatNumber(perSecond * 2) + ' ед. клеточного урона в секунду', | |||
'Дополнительно наносит ' + formatNumber(perSecond * 2) + ' ед. тупого урона в секунду'); | |||
return result; | |||
} | |||
if (type === 'Oxidizing') { | |||
result.push(originalDoseDescription('normal', 'Наносит ' + formatNumber(perSecond) + ' ед. ожогового урона в секунду; в огненной смеси повышает интенсивность, но уменьшает длительность и радиус')); | |||
originalAddDoseEffects(result, reagent, | |||
'Наносит ' + formatNumber(perSecond * 2) + ' ед. ожогового урона в секунду', | |||
'Дополнительно наносит ' + formatNumber(perSecond * 5) + ' ед. ожогового урона в секунду'); | |||
return result; | |||
} | |||
if (type === 'Fueling') { | |||
result.push(originalDoseDescription('normal', 'Повышает воспламеняемость тела на ' + formatNumber(perSecond) + ' ед. в секунду; в огненной смеси увеличивает длительность и радиус, но снижает интенсивность')); | |||
originalAddDoseEffects(result, reagent, | |||
'Повышает воспламеняемость тела на ' + formatNumber(perSecond * 2) + ' ед. в секунду', | |||
'Поджигает тело с высокой интенсивностью'); | |||
return result; | |||
} | |||
if (type === 'Flowing') { | |||
result.push(originalDoseDescription('normal', 'Делает огненную смесь более текучей: увеличивает радиус, но снижает интенсивность и длительность горения')); | |||
return result; | |||
} | |||
if (type === 'Viscous') { | |||
result.push(originalDoseDescription('normal', 'Замедляет движение на ' + formatNumber(perSecond) + ' сек. за каждый цикл и уменьшает радиус огненной смеси')); | |||
originalAddDoseEffects(result, reagent, | |||
'Сильно замедляет движение на ' + formatNumber(perSecond * 2) + ' сек. за каждый цикл', | |||
'Практически останавливает движение на ' + formatNumber(perSecond * 3) + ' сек. за каждый цикл'); | |||
return result; | |||
} | |||
return null; | |||
} | |||
function originalGenericEffectDescription(effect, reagent) { | |||
var type = tagName(effect && effect.yamlTag); | |||
var value = originalEffectValue(effect); | |||
var probability = value.probability; | |||
var tier = originalEffectTier(effect, reagent); | |||
var conditions = originalRemainingConditions(effect, reagent); | |||
var text = ''; | |||
if (probability === 0) { | |||
return []; | |||
} | |||
var rmc = originalRmcEffectDescriptions(type, value, reagent); | |||
if (rmc) { | |||
return rmc; | |||
} | |||
if (type === 'HealthChange' || type === 'EqualHealthChange') { | |||
text = originalDamageChanges(value.damage, type === 'EqualHealthChange').join('; '); | |||
} else if (type === 'AdjustReagent' && value.reagent) { | |||
text = (value.amount >= 0 ? 'Добавляет ' : 'Удаляет ') + formatAmount(Math.abs(value.amount || 0)) + ' реагента «' + capitalizeFirst(reagentName(value.reagent)) + '» за цикл метаболизма'; | |||
} else if (type === 'MovespeedModifier') { | |||
var walk = Math.round((Number(value.walkSpeedModifier || 1) - 1) * 100); | |||
var sprint = Math.round((Number(value.sprintSpeedModifier || 1) - 1) * 100); | |||
text = 'Изменяет скорость ходьбы на ' + (walk >= 0 ? '+' : '') + walk + '% и бега на ' + (sprint >= 0 ? '+' : '') + sprint + '%'; | |||
} else if (type === 'GenericStatusEffect') { | |||
var status = STATUS_LABELS[value.key] || value.key || 'неизвестный статус'; | |||
text = value.type === 'Remove' ? 'Сокращает ' + status + ' на ' + formatNumber(value.time || 2) + ' сек.' : 'Вызывает ' + status + ' на ' + formatNumber(value.time || 2) + ' сек.'; | |||
} else if (type === 'ModifyStatusEffect') { | |||
var modifiedStatus = STATUS_LABELS[value.effectProto] || value.effectProto || 'неизвестный статус'; | |||
text = value.type === 'Remove' ? 'Сокращает ' + modifiedStatus + ' на ' + formatNumber(value.time || 2) + ' сек.' : 'Вызывает ' + modifiedStatus + ' на ' + formatNumber(value.time || 2) + ' сек.'; | |||
} else if (type === 'Jitter') { | |||
text = 'Вызывает дрожь на ' + formatNumber(value.time || 2) + ' сек.'; | |||
} else if (type === 'Emote') { | |||
text = 'Вызывает ' + (EMOTE_LABELS[value.emote] || ('эмоцию «' + (value.emote || 'неизвестно') + '»')); | |||
} else if (type === 'ChemVomit') { | |||
text = 'Вызывает рвоту'; | |||
} else if (type === 'Drunk') { | |||
text = 'Добавляет ' + formatNumber(value.boozePower || 3) + ' сек. опьянения за цикл метаболизма'; | |||
} else if (type === 'SatiateHunger') { | |||
text = 'Восстанавливает ' + formatNumber(value.factor !== undefined ? value.factor : 3) + ' ед. насыщения за цикл метаболизма'; | |||
} else if (type === 'SatiateThirst') { | |||
text = 'Восстанавливает ' + formatNumber(value.factor !== undefined ? value.factor : 3) + ' ед. жажды за цикл метаболизма'; | |||
} else if (type === 'ChemHealEyeDamage') { | |||
text = 'Лечит повреждения глаз'; | |||
} else if (type === 'CauseZombieInfection') { | |||
text = 'Заражает зомби-инфекцией'; | |||
} else if (type === 'CureZombieInfection') { | |||
text = value.innoculate ? 'Лечит зомби-инфекцию и создаёт иммунитет' : 'Лечит зомби-инфекцию'; | |||
} else if (type === 'FlammableReaction') { | |||
text = 'Покрывает цель горючим; интенсивность составляет ' + formatNumber(Number(value.multiplier || 1) * 100) + '% от стандартной'; | |||
} else if (type === 'PopupMessage') { | |||
text = value.messages && value.messages.indexOf('rmc-body-stings') !== -1 ? 'Вызывает болезненное жжение' : 'Вызывает заметное субъективное ощущение действия препарата'; | |||
} else { | |||
text = 'Дополнительный игровой эффект «' + (type || 'неизвестно') + '»'; | |||
} | |||
if (conditions.length) { | |||
text += ' (' + conditions.join(', ') + ')'; | |||
} | |||
return [originalDoseDescription(tier, originalWithChance(text, probability))]; | |||
} | |||
function originalSemanticTokenClass(token) { | |||
var normalized = String(token || '').toLocaleLowerCase('ru-RU'); | |||
var actionClass = EFFECT_ACTION_CLASSES[normalized]; | |||
if (actionClass) { | |||
return 'scmc-chem__effect-action scmc-chem__effect-action--' + actionClass; | |||
} | |||
for (var index = 0; index < DAMAGE_TOKEN_CLASSES.length; index += 1) { | |||
DAMAGE_TOKEN_CLASSES[index].pattern.lastIndex = 0; | |||
if (DAMAGE_TOKEN_CLASSES[index].pattern.test(normalized)) { | |||
return 'scmc-chem__damage-type scmc-chem__damage-type--' + DAMAGE_TOKEN_CLASSES[index].className; | |||
} | |||
} | |||
return ''; | |||
} | |||
function originalEffectTone(text) { | |||
var value = String(text || '').toLocaleLowerCase('ru-RU'); | |||
var beneficial = value.search(/полностью лечит|лечит|восстанавливает|возвращает|омолаживает|сокращает|удаляет|создаёт иммунитет/); | |||
var harmful = value.search(/наносит|вызывает|заражает|поджигает|уничтожает/); | |||
var warning = value.search(/расходует|замедляет/); | |||
var candidates = []; | |||
if (beneficial !== -1) { candidates.push({ index: beneficial, tone: 'beneficial' }); } | |||
if (harmful !== -1) { candidates.push({ index: harmful, tone: 'harmful' }); } | |||
if (warning !== -1) { candidates.push({ index: warning, tone: 'warning' }); } | |||
candidates.sort(function (left, right) { return left.index - right.index; }); | |||
return candidates.length ? candidates[0].tone : 'utility'; | |||
} | |||
function originalAppendSemanticEffectText(parent, text) { | |||
var value = finishSentence(text); | |||
var lastIndex = 0; | |||
var match; | |||
EFFECT_TOKEN_RE.lastIndex = 0; | |||
while ((match = EFFECT_TOKEN_RE.exec(value)) !== null) { | |||
if (match.index > lastIndex) { | |||
parent.appendChild(document.createTextNode(value.slice(lastIndex, match.index))); | |||
} | |||
var className = originalSemanticTokenClass(match[0]); | |||
parent.appendChild(className ? el('span', className, match[0]) : document.createTextNode(match[0])); | |||
lastIndex = EFFECT_TOKEN_RE.lastIndex; | |||
} | |||
if (lastIndex < value.length) { | |||
parent.appendChild(document.createTextNode(value.slice(lastIndex))); | |||
} | |||
} | |||
function originalRenderEffectText(text) { | |||
var tone = originalEffectTone(text); | |||
var item = el('li', 'scmc-chem__effect scmc-chem__effect--' + tone); | |||
var content = el('span', 'scmc-chem__effect-name'); | |||
originalAppendSemanticEffectText(content, text); | |||
item.appendChild(content); | |||
return item; | |||
} | |||
function originalTierTitle(tier, reagent) { | |||
var properties = reagent.properties || {}; | |||
if (tier === 'overdose') { | |||
return 'Передозировка' + (properties.overdose !== undefined ? ' · от ' + formatAmount(properties.overdose) : ''); | |||
} | |||
if (tier === 'critical') { | |||
return 'Критическая передозировка' + (properties.criticalOverdose !== undefined ? ' · от ' + formatAmount(properties.criticalOverdose) : ''); | |||
} | |||
return 'Обычная доза'; | |||
} | |||
function originalAppendEffectTier(group, tier, effects, reagent) { | |||
if (!effects.length) { | |||
return; | |||
} | |||
var tierBlock = el('div', 'scmc-chem__effect-tier scmc-chem__effect-tier--' + tier); | |||
tierBlock.appendChild(el('div', 'scmc-chem__effect-tier-title', originalTierTitle(tier, reagent))); | |||
var list = el('ul', 'scmc-chem__effect-list'); | |||
effects.forEach(function (description) { list.appendChild(originalRenderEffectText(description.text)); }); | |||
tierBlock.appendChild(list); | |||
group.appendChild(tierBlock); | |||
} | |||
function renderOriginalMetabolisms(reagent) { | |||
var metabolisms = reagent.properties && reagent.properties.metabolisms; | |||
if (!metabolisms || !Object.keys(metabolisms).length) { | |||
return null; | |||
} | |||
var block = el('div', 'scmc-chem__card-section'); | |||
var hasContent = false; | |||
block.appendChild(el('h4', 'scmc-chem__card-subtitle', 'Воздействие')); | |||
Object.keys(metabolisms).forEach(function (metabolismId) { | |||
var metabolism = metabolisms[metabolismId] || {}; | |||
var tiers = { normal: [], overdose: [], critical: [] }; | |||
(metabolism.effects || []).forEach(function (effect) { | |||
originalGenericEffectDescription(effect, reagent).forEach(function (description) { | |||
tiers[description.tier].push(description); | |||
}); | |||
}); | |||
if (!tiers.normal.length && !tiers.overdose.length && !tiers.critical.length) { | |||
return; | |||
} | |||
var group = el('div', 'scmc-chem__metabolism'); | |||
var title = METABOLISM_LABELS[metabolismId] || metabolismId; | |||
if (metabolism.metabolismRate !== undefined) { | |||
title += ' · расход ' + formatAmount(metabolism.metabolismRate) + '/сек.'; | |||
} | |||
group.appendChild(el('div', 'scmc-chem__metabolism-title', title)); | |||
originalAppendEffectTier(group, 'normal', tiers.normal, reagent); | |||
originalAppendEffectTier(group, 'overdose', tiers.overdose, reagent); | |||
originalAppendEffectTier(group, 'critical', tiers.critical, reagent); | |||
block.appendChild(group); | |||
hasContent = true; | |||
}); | |||
return hasContent ? block : null; | |||
} | |||
function originalPlantEffectText(effect) { | |||
var type = tagName(effect && effect.yamlTag); | |||
var value = originalEffectValue(effect); | |||
var probability = value.probability; | |||
var amount = Number(value.amount !== undefined ? value.amount : 1); | |||
var attribute = PLANT_ATTRIBUTE_LABELS[type]; | |||
var text; | |||
if (probability === 0) { | |||
return ''; | |||
} | |||
if (attribute) { | |||
if (type === 'PlantAdjustHealth') { | |||
text = amount >= 0 ? 'Восстанавливает здоровье растения на ' + formatNumber(amount) : 'Снижает здоровье растения на ' + formatNumber(Math.abs(amount)); | |||
} else { | |||
text = (amount >= 0 ? 'Повышает ' : 'Снижает ') + attribute + ' на ' + formatNumber(Math.abs(amount)); | |||
} | |||
} else if (type === 'PlantCryoxadone') { | |||
text = 'Омолаживает растение с учётом его возраста и времени роста'; | |||
} else if (type === 'PlantPhalanximine') { | |||
text = 'Возвращает жизнеспособность растению, погибшему из-за мутации'; | |||
} else if (type === 'PlantDiethylamine') { | |||
text = 'Повышает продолжительность жизни или базовое здоровье растения; шанс 10% на единицу реагента'; | |||
} else if (type === 'PlantRestoreSeeds') { | |||
text = 'Восстанавливает семена растения'; | |||
} else if (type === 'PlantDestroySeeds') { | |||
text = 'Уничтожает семена растения'; | |||
} else { | |||
text = 'Дополнительный растительный эффект «' + (type || 'неизвестно') + '»'; | |||
} | |||
return originalWithChance(text, probability); | |||
} | |||
function renderOriginalPlantMetabolism(reagent) { | |||
var effects = reagent.properties && reagent.properties.plantMetabolism; | |||
if (!Array.isArray(effects) || !effects.length) { | |||
return null; | |||
} | |||
var descriptions = effects.map(originalPlantEffectText).filter(Boolean); | |||
if (!descriptions.length) { | |||
return null; | |||
} | |||
var block = el('div', 'scmc-chem__card-section'); | |||
block.appendChild(el('h4', 'scmc-chem__card-subtitle', 'Метаболизм растений')); | |||
var group = el('div', 'scmc-chem__metabolism'); | |||
group.appendChild(el('div', 'scmc-chem__metabolism-title', '1 ед. реагента каждые 3 секунды (базово)')); | |||
var list = el('ul', 'scmc-chem__effect-list'); | |||
descriptions.forEach(function (description) { list.appendChild(originalRenderEffectText(description)); }); | |||
group.appendChild(list); | |||
block.appendChild(group); | |||
return block; | |||
} | } | ||
| Строка 700: | Строка 1198: | ||
add(body, recipeSection); | add(body, recipeSection); | ||
} | } | ||
add(body, | add(body, renderOriginalMetabolisms(reagent)); | ||
add(body, | add(body, renderOriginalPlantMetabolism(reagent)); | ||
add(details, summary, body); | add(details, summary, body); | ||
return details; | return details; | ||