Compare commits

...

25 commits

Author SHA1 Message Date
bbbccd2903 Release 1.1.0 2025-04-19 10:28:10 +00:00
c128a3ba92 Update Interface Classic ERA number 2025-04-19 12:26:23 +02:00
a06edeb492 Refactor encounter rendering and description formatting 2025-04-19 12:15:35 +02:00
f37808207e Refactor and improve encounter data handling and formatting 2025-04-19 00:42:06 +02:00
a32b698ebf Refactor encounter handling and placeholder logic 2025-04-18 14:03:11 +02:00
c2eda51d7d Update dependency typescript to v5.8.3 2025-04-17 19:56:39 +02:00
b289fe613d Update dependency prettier to v3.5.3 2025-04-17 19:56:26 +02:00
269feb0e6d Update dependency dotenv to v16.5.0 2025-04-17 19:56:12 +02:00
f2d35d65d5 Fix key for entities 2025-04-17 19:52:26 +02:00
908f45eb9b Refactor Encounters, use new translations format for save space 2025-04-17 19:05:58 +02:00
7d9f58650a Update dependency typescript to v5.8.2 2025-04-01 17:13:26 +02:00
352271d34d Update quests and restrict tactics to non-classic versions 2025-03-31 12:46:14 +02:00
666bbc4659 Refactor config initialization and enhance font safety checks 2025-03-30 22:57:07 +02:00
30e04df022 Set empty text for 'inform' frame when tactic is not found. 2025-03-30 22:32:25 +02:00
b727b537ef Optimize and standardize tactical data formatting. 2025-03-30 22:00:13 +02:00
3cb2ed503f Improve tactic data handling and update UI logic. 2025-03-30 17:56:56 +02:00
9fe284c18e New feature: Boss tactics 2025-03-29 07:44:17 +01:00
6c2381d65c POC: Boss tactics 2025-03-28 10:45:45 +01:00
45b919a41e Update naming consistency and improve JSON module resolution 2025-03-27 09:07:00 +01:00
d1fa5a6bc7 Remove responsive speech frame width, fix generator 2025-03-20 20:18:54 +01:00
ab820ccf7e Replacements for "Champions" and "champions" are removed 2025-03-12 09:54:16 +01:00
269ab6486b Fix numbers in bubble text 2025-03-10 13:32:50 +01:00
ca7603458c Add renovate.json 2025-03-09 09:18:33 +01:00
63563bc2e9 Move support files into own folder 2025-03-09 09:02:31 +01:00
c8fc9f08ef Remove screenshots from repository 2025-03-09 08:53:24 +01:00
75 changed files with 106979 additions and 51928 deletions

1
.gitattributes vendored
View file

@ -1 +0,0 @@
* whitespace=space-before-tab,-space-after-tab,blank-at-eol,-blank-at-eof

4
.gitignore vendored
View file

@ -1,7 +1,7 @@
.idea/
.DS_Store
downloader/.env
downloader/node_modules
.support/.env
.support/node_modules
lib

91
.support/index.ts Normal file
View file

@ -0,0 +1,91 @@
import * as fs from 'node:fs';
import * as path from 'node:path';
import dotenv from 'dotenv';
import { callTolgee } from './utils/callTolgee';
import {
buildTree,
getEncounterGroupKey,
getEncounterKey,
writeEncounter,
writeEncounterStructure,
} from './utils/entities/encounter';
import { TolgeeKey, TolgeeTranslationsResponse } from './types';
import { writeQuest } from './utils/entities/quest';
import { writeBook } from './utils/entities/book';
import { writeSpeech } from './utils/entities/speech';
dotenv.config({ path: '.env' }).parsed;
(async () => {
const args = process.argv.slice(2);
const addonDir = path.join(process.cwd(), `../Addon/Data/${args[0]}`);
const addonData: TolgeeKey[][] = [];
let pageNumber = 0;
try {
// load all data from tolgee
while (true) {
const response = await callTolgee<TolgeeTranslationsResponse>('GET', `/translations`, {
filterTranslatedInLang: 'cs',
languages: 'cs,csf,en',
size: 1000,
page: pageNumber,
});
const translations = response.data?._embedded?.keys ?? [];
if (response.data?.page.totalPages > response.data?.page.number) {
addonData[pageNumber] = [];
for (const tolgeeKey of translations) {
addonData[pageNumber].push(tolgeeKey);
}
pageNumber++;
} else {
break;
}
}
const encounterKeys: Record<string, string[]> = {};
let fileIndex = 0;
addonData.forEach((chunk, index) => {
fileIndex = index;
const fileName = path.join(addonDir, `${fileIndex++}.lua`);
try {
fs.unlinkSync(fileName);
} catch (e) {}
fs.appendFileSync(fileName, 'local _, addon = ...\n', 'utf8');
for (const [, key] of Object.entries(chunk)) {
switch (key.keyNamespace) {
case 'quest':
fs.appendFileSync(fileName, writeQuest(key), 'utf8');
break;
case 'book':
fs.appendFileSync(fileName, writeBook(key), 'utf8');
break;
case 'speech':
fs.appendFileSync(fileName, writeSpeech(key), 'utf8');
break;
case 'encounter':
const groupId = getEncounterGroupKey(key);
encounterKeys[groupId] = encounterKeys[groupId] ?? [];
encounterKeys[groupId].push(getEncounterKey(key));
fs.appendFileSync(fileName, writeEncounter(key), 'utf8');
break;
}
}
});
const fileName = path.join(addonDir, `${fileIndex++}.lua`);
try {
fs.unlinkSync(fileName);
} catch (e) {}
fs.appendFileSync(fileName, 'local _, addon = ...\n', 'utf8');
Object.entries(encounterKeys).forEach(([key, encounterKeys]) => {
const structure = buildTree(encounterKeys);
fs.appendFileSync(fileName, writeEncounterStructure(key, structure), 'utf8');
});
} catch (e) {
throw e;
}
})();

View file

@ -9,10 +9,10 @@
"dependencies": {
"axios": "^1.7.2",
"dotenv": "^16.4.5",
"typescript": "5.4.2"
"typescript": "5.8.3"
},
"devDependencies": {
"prettier": "3.2.5",
"prettier": "3.5.3",
"ts-node": "10.9.2"
},
"private": true

View file

@ -11,25 +11,19 @@ importers:
axios:
specifier: ^1.7.2
version: 1.7.9
diff:
specifier: ^7.0.0
version: 7.0.0
dotenv:
specifier: ^16.4.5
version: 16.4.7
pg:
specifier: ^8.13.3
version: 8.13.3
version: 16.5.0
typescript:
specifier: 5.4.2
version: 5.4.2
specifier: 5.8.3
version: 5.8.3
devDependencies:
prettier:
specifier: 3.2.5
version: 3.2.5
specifier: 3.5.3
version: 3.5.3
ts-node:
specifier: 10.9.2
version: 10.9.2(@types/node@22.10.2)(typescript@5.4.2)
version: 10.9.2(@types/node@22.10.2)(typescript@5.8.3)
packages:
@ -95,12 +89,8 @@ packages:
resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==}
engines: {node: '>=0.3.1'}
diff@7.0.0:
resolution: {integrity: sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==}
engines: {node: '>=0.3.1'}
dotenv@16.4.7:
resolution: {integrity: sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==}
dotenv@16.5.0:
resolution: {integrity: sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg==}
engines: {node: '>=12'}
follow-redirects@1.15.9:
@ -127,68 +117,14 @@ packages:
resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
engines: {node: '>= 0.6'}
pg-cloudflare@1.1.1:
resolution: {integrity: sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==}
pg-connection-string@2.7.0:
resolution: {integrity: sha512-PI2W9mv53rXJQEOb8xNR8lH7Hr+EKa6oJa38zsK0S/ky2er16ios1wLKhZyxzD7jUReiWokc9WK5nxSnC7W1TA==}
pg-int8@1.0.1:
resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==}
engines: {node: '>=4.0.0'}
pg-pool@3.7.1:
resolution: {integrity: sha512-xIOsFoh7Vdhojas6q3596mXFsR8nwBQBXX5JiV7p9buEVAGqYL4yFzclON5P9vFrpu1u7Zwl2oriyDa89n0wbw==}
peerDependencies:
pg: '>=8.0'
pg-protocol@1.7.1:
resolution: {integrity: sha512-gjTHWGYWsEgy9MsY0Gp6ZJxV24IjDqdpTW7Eh0x+WfJLFsm/TJx1MzL6T0D88mBvkpxotCQ6TwW6N+Kko7lhgQ==}
pg-types@2.2.0:
resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==}
engines: {node: '>=4'}
pg@8.13.3:
resolution: {integrity: sha512-P6tPt9jXbL9HVu/SSRERNYaYG++MjnscnegFh9pPHihfoBSujsrka0hyuymMzeJKFWrcG8wvCKy8rCe8e5nDUQ==}
engines: {node: '>= 8.0.0'}
peerDependencies:
pg-native: '>=3.0.1'
peerDependenciesMeta:
pg-native:
optional: true
pgpass@1.0.5:
resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==}
postgres-array@2.0.0:
resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==}
engines: {node: '>=4'}
postgres-bytea@1.0.0:
resolution: {integrity: sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==}
engines: {node: '>=0.10.0'}
postgres-date@1.0.7:
resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==}
engines: {node: '>=0.10.0'}
postgres-interval@1.2.0:
resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==}
engines: {node: '>=0.10.0'}
prettier@3.2.5:
resolution: {integrity: sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==}
prettier@3.5.3:
resolution: {integrity: sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==}
engines: {node: '>=14'}
hasBin: true
proxy-from-env@1.1.0:
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
split2@4.2.0:
resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==}
engines: {node: '>= 10.x'}
ts-node@10.9.2:
resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==}
hasBin: true
@ -203,8 +139,8 @@ packages:
'@swc/wasm':
optional: true
typescript@5.4.2:
resolution: {integrity: sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==}
typescript@5.8.3:
resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==}
engines: {node: '>=14.17'}
hasBin: true
@ -214,10 +150,6 @@ packages:
v8-compile-cache-lib@3.0.1:
resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==}
xtend@4.0.2:
resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==}
engines: {node: '>=0.4'}
yn@3.1.1:
resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==}
engines: {node: '>=6'}
@ -277,9 +209,7 @@ snapshots:
diff@4.0.2: {}
diff@7.0.0: {}
dotenv@16.4.7: {}
dotenv@16.5.0: {}
follow-redirects@1.15.9: {}
@ -297,58 +227,11 @@ snapshots:
dependencies:
mime-db: 1.52.0
pg-cloudflare@1.1.1:
optional: true
pg-connection-string@2.7.0: {}
pg-int8@1.0.1: {}
pg-pool@3.7.1(pg@8.13.3):
dependencies:
pg: 8.13.3
pg-protocol@1.7.1: {}
pg-types@2.2.0:
dependencies:
pg-int8: 1.0.1
postgres-array: 2.0.0
postgres-bytea: 1.0.0
postgres-date: 1.0.7
postgres-interval: 1.2.0
pg@8.13.3:
dependencies:
pg-connection-string: 2.7.0
pg-pool: 3.7.1(pg@8.13.3)
pg-protocol: 1.7.1
pg-types: 2.2.0
pgpass: 1.0.5
optionalDependencies:
pg-cloudflare: 1.1.1
pgpass@1.0.5:
dependencies:
split2: 4.2.0
postgres-array@2.0.0: {}
postgres-bytea@1.0.0: {}
postgres-date@1.0.7: {}
postgres-interval@1.2.0:
dependencies:
xtend: 4.0.2
prettier@3.2.5: {}
prettier@3.5.3: {}
proxy-from-env@1.1.0: {}
split2@4.2.0: {}
ts-node@10.9.2(@types/node@22.10.2)(typescript@5.4.2):
ts-node@10.9.2(@types/node@22.10.2)(typescript@5.8.3):
dependencies:
'@cspotcode/source-map-support': 0.8.1
'@tsconfig/node10': 1.0.11
@ -362,16 +245,14 @@ snapshots:
create-require: 1.1.1
diff: 4.0.2
make-error: 1.3.6
typescript: 5.4.2
typescript: 5.8.3
v8-compile-cache-lib: 3.0.1
yn: 3.1.1
typescript@5.4.2: {}
typescript@5.8.3: {}
undici-types@6.20.0: {}
v8-compile-cache-lib@3.0.1: {}
xtend@4.0.2: {}
yn@3.1.1: {}

30
.support/sync.sh Normal file
View file

@ -0,0 +1,30 @@
#!/bin/bash
wow_source_folder="retail"
wow_destiny_folder="retail"
# wow_source_folder="beta"
# wow_destiny_folder="retail"
# wow_source_folder="classic_era"
# wow_destiny_folder="classic_era"
src_folder="$(pwd)/./"
dest_folder="/Applications/World of Warcraft/_${wow_destiny_folder}_/Interface/AddOns/CzechQuests"
mkdir -p "$dest_folder/Addon/Data/"
fswatch -o "$src_folder" | while read -r change; do
rsync -auv --delete \
"$src_folder/Addon/Data/$wow_source_folder/" \
"$dest_folder/Addon/Data/"
cp "$src_folder/Addon/Data/other.lua" "$dest_folder/Addon/Data/"
rsync -auv --delete \
--exclude '.*' \
--exclude 'Addon/Data/**' \
--exclude 'lib/**' \
--exclude 'Jenkinsfile' \
"$src_folder" "$dest_folder"
done

View file

@ -7,6 +7,7 @@
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true
},
"exclude": ["node_modules"]
}

45
.support/types.ts Normal file
View file

@ -0,0 +1,45 @@
export type TolgeeKey = {
keyId: number;
keyName: string;
keyNamespace: string;
keyDescription: string;
keyTags: TolgeeTag[];
translations: {
en: {
id: number;
text: string;
state: 'REVIEWED' | 'TRANSLATED';
};
cs: {
id: number;
text: string | null;
state: 'REVIEWED' | 'TRANSLATED';
};
csf: {
id: number;
text: string | null;
state: 'REVIEWED' | 'TRANSLATED';
};
};
};
export type TolgeeTag = {
name: string;
};
export type TolgeeTranslationsResponse = {
_embedded: {
keys: TolgeeKey[];
};
page: {
size: number;
totalElements: number;
totalPages: number;
number: number;
};
};
export type TreeNode = {
key: string;
children: TreeNode[];
};

4
.support/utils/array.ts Normal file
View file

@ -0,0 +1,4 @@
export function splitByIndexes(input: string, indexes: number[]): string[] {
const parts = input.split('_');
return indexes.map((index) => parts[index]).filter((item) => item !== undefined);
}

View file

@ -0,0 +1,23 @@
import axios from 'axios';
export const callTolgee = async <R>(
method: 'GET' | 'POST' | 'PUT' | 'DELETE' = 'GET',
path: string,
params?: any,
data?: any,
) => {
const args = process.argv.slice(2);
const projectId = args[1];
try {
return await axios<R>(`https://translate.romanjaros.local/v2/projects/${projectId}${path}`, {
method,
data,
params,
headers: {
'X-API-KEY': process.env.TOLGEE_PAT as string,
},
});
} catch (e) {
throw e;
}
};

View file

@ -0,0 +1,12 @@
import { TolgeeKey } from '../../types';
import { writeAlsoFemaleTranslation } from '../translation';
export const writeBook = (tolgeeKey: TolgeeKey): string => {
let luaRecord = '';
const isName = tolgeeKey.keyName.endsWith('_name');
const key = isName ? '_name' : '_page_' + tolgeeKey.keyName.split('_')[2];
luaRecord += `addon.data.book["${tolgeeKey.keyDescription}${key}"] = {\n`;
luaRecord += writeAlsoFemaleTranslation(tolgeeKey.translations);
luaRecord += `}\n`;
return luaRecord;
};

View file

@ -0,0 +1,61 @@
import { TolgeeKey, TreeNode } from '../../types';
import { writeAlsoFemaleTranslation } from '../translation';
export function buildTree(inputs: string[], layer = ''): TreeNode[] {
const root: TreeNode[] = [];
inputs
.filter((input) => new RegExp(`_(${layer})([0-9]{2})$`).test(input))
.forEach((input) => {
const layerIndex = input.split('_').at(-1);
root.push({
key: input,
children: buildTree(inputs, layerIndex),
});
});
return root;
}
export const getEncounterKey = (tolgeeKey: TolgeeKey): string => {
const [, difficulty, instance, type, key] = tolgeeKey.keyName.split('_');
return [tolgeeKey.keyDescription, difficulty, instance, type, key].join('_');
};
export const getEncounterGroupKey = (tolgeeKey: TolgeeKey): string => {
const [, difficulty, instance] = tolgeeKey.keyName.split('_');
return [tolgeeKey.keyDescription, difficulty, instance].join('_');
};
export const writeEncounter = (tolgeeKey: TolgeeKey): string => {
let luaRecord = '';
const keyName = getEncounterKey(tolgeeKey);
luaRecord += `addon.data.encounter["${keyName}"] = {\n`;
luaRecord += writeAlsoFemaleTranslation(tolgeeKey.translations);
luaRecord += `}\n`;
return luaRecord;
};
const writeStructure = (structure: TreeNode[], layer = 0): string => {
let luaRecord = '';
const tab = '\t'.repeat(layer);
const layerIndex = layer + 1;
structure.forEach((node) => {
const hasEmptyChildren = node.children.length === 0;
luaRecord += `${tab}{\n`;
luaRecord += `\t${tab}key = "${node.key}",\n`;
luaRecord += `\t${tab}children = {${hasEmptyChildren ? '' : '\n'}`;
luaRecord += `${writeStructure(node.children, layerIndex)}`;
luaRecord += `${hasEmptyChildren ? '' : `\t${tab}`}},\n`;
luaRecord += `${tab}},\n`;
});
return luaRecord;
};
export const writeEncounterStructure = (key: string, structure: TreeNode[]): string => {
let luaRecord = '';
luaRecord += `addon.data.encounter["${key}"] = {\n`;
luaRecord += writeStructure(structure);
luaRecord += `}\n`;
return luaRecord;
};

View file

@ -0,0 +1,10 @@
import { TolgeeKey } from '../../types';
import { writeAlsoFemaleTranslation } from '../translation';
export const writeQuest = (tolgeeKey: TolgeeKey): string => {
let luaRecord = '';
luaRecord += `addon.data.quest["${tolgeeKey.keyName}"] = {\n`;
luaRecord += writeAlsoFemaleTranslation(tolgeeKey.translations);
luaRecord += `}\n`;
return luaRecord;
};

View file

@ -0,0 +1,11 @@
import { TolgeeKey } from '../../types';
import { normalize, writeMaleTranslation } from '../translation';
export const writeSpeech = (tolgeeKey: TolgeeKey): string => {
let luaRecord = '';
const en = tolgeeKey.translations.en.text.split(': ')[1].trim();
luaRecord += `addon.data.speech["${normalize(tolgeeKey.keyDescription)}_${normalize(en)}"] = {\n`;
luaRecord += writeMaleTranslation(tolgeeKey.translations);
luaRecord += `}\n`;
return luaRecord;
};

View file

@ -0,0 +1,30 @@
import { TolgeeKey } from '../types';
export const normalize = (translation: string | null | undefined) => {
if (translation == null) {
return '';
}
return translation.replace(/\n/g, '\\n').replace(/"/g, "'");
};
export const writeMaleTranslation = (value: TolgeeKey['translations']) => {
let text = '';
const normalizedValue = normalize(value?.['cs']?.text);
if (normalizedValue != '') {
text += '\tm = "' + normalizedValue + '", \n';
}
return text;
};
export const writeAlsoFemaleTranslation = (value: TolgeeKey['translations']) => {
let text = '';
const normalizedMaleValue = normalize(value?.['cs']?.text);
const normalizedFemaleValue = normalize(value?.['csf']?.text);
if (normalizedMaleValue != '') {
text += '\tm = "' + normalizedMaleValue + '", \n';
}
if (normalizedFemaleValue != '' && normalizedMaleValue != normalizedFemaleValue) {
text += '\tf = "' + normalizedFemaleValue + '", \n';
}
return text;
};

View file

@ -1,11 +1,11 @@
local _, addon = ...
local function ResolveGender(maleVersion, femaleVersion)
local function ResolveGender(obj)
local gender = UnitSex("player")
if gender == 2 then
return maleVersion
return obj.m
else
return femaleVersion == nil and maleVersion or femaleVersion
return obj.f == nil and obj.m or obj.f
end
end
addon.API.ResolveGender = ResolveGender
@ -16,6 +16,8 @@ function CzechQuestsAddon:GetData(key, id)
return addon.API.GetQuest(id)
elseif key == "speech" then
return addon.API.GetSpeech(id)
elseif key == "encounter" then
return addon.API.GetEncounter(id)
elseif addon.data[key][id] then
return addon.data[key][id]
end

336
Addon/Code/Encounter.lua Executable file
View file

@ -0,0 +1,336 @@
local _, addon = ...
local ENCOUNTER_TAB_ID = 9
local CURRENT_TAB_ID = 0
local PREVIOUS_TAB_ID = 0
local ENCOUNTER_ID = 0
local DIFFICULTY = 0
local TAG_TO_ICON = {
tank = 0,
dps = 1,
healer = 2,
important = 5,
mythic = 12,
interruptible = 6,
magic = 7,
curse = 8,
poison = 9,
heroic = 3,
disease = 10,
deadly = 4,
enrage = 11
}
local ORIGINALS = {}
local function HideOtherContent()
local frames = { "overviewScroll", "LootContainer", 'detailsScroll', 'model' }
for _, frame in ipairs(frames) do
EncounterJournal.encounter.info[frame]:Hide();
end
local tabs = { "overviewTab", "lootTab", "bossTab", "modelTab" }
for _, tab in ipairs(tabs) do
EncounterJournal.encounter.info[tab].selected:Hide();
EncounterJournal.encounter.info[tab].unselected:Show();
EncounterJournal.encounter.info[tab]:UnlockHighlight();
end
if EncounterJournal.encounter.info.creatureButtons then
for _, button in pairs(EncounterJournal.encounter.info.creatureButtons) do
button:Hide()
end
end
addon.EncounterFrame:ClearHeaders()
end
local function SetAbilityTagIcon(header, tags)
local result = {}
for part in string.gmatch(tags, "([^,]+)") do
table.insert(result, part)
end
for i, tag in pairs(result) do
local tex = header.button:CreateTexture()
if i == 1 then
tex:SetAllPoints(header.button.icon1.icon)
elseif i == 2 then
tex:SetAllPoints(header.button.icon2.icon)
elseif i == 3 then
tex:SetAllPoints(header.button.icon3.icon)
end
tex:SetTexture("Interface/EncounterJournal/UI-EJ-Icons")
local index = TAG_TO_ICON[string.lower(tag)] or nil
if index ~= nil then
EncounterJournal_SetFlagIcon(tex, index)
end
end
end
local function SetAbilityIcon(header, name)
if ORIGINALS[name] == nil then
return
end
local abilityIcon = ORIGINALS[name].abilityIcon or nil
if abilityIcon then
header.button.abilityIcon:SetTexture(abilityIcon)
header.button.abilityIcon:Show()
header.button.title:SetPoint("TOPLEFT", header, "TOPLEFT", 45, -7);
end
end
local function SetEncounterPortraitIcon(header, name)
if ORIGINALS[name] == nil then
return
end
local creatureDisplayID = ORIGINALS[name].creatureDisplayID or 0
local uiModelSceneID = ORIGINALS[name].uiModelSceneID or 0
if creatureDisplayID ~= 0 and uiModelSceneID ~= 0 then
header.button.portrait.displayInfo = creatureDisplayID;
header.button.portrait.uiModelSceneID = uiModelSceneID;
SetPortraitTextureFromCreatureDisplayID(header.button.portrait.icon, creatureDisplayID);
header.button.portrait:Show()
header.button.title:SetPoint("TOPLEFT", header, "TOPLEFT", 50, -7);
end
end
local function RenderBossAbilities(data, parent, layer)
local frame = addon.EncounterFrame
if not parent.children then
parent.children = {}
end
for _, node in ipairs(data) do
local abilityValue = addon.API.GetEncounterAbility(node.key)
if abilityValue then
local abilityParts = addon.API.ParseAbilities(abilityValue, "|")
local name = abilityParts[1]
local tag = abilityParts[3]
local description = abilityParts[5]
if name ~= "???" then
local header = frame:CreateHeader()
header:SetWidth(frame:GetWidth() - (layer * 20))
header.button.title:SetText(name)
SetAbilityIcon(header, name)
SetEncounterPortraitIcon(header, name)
if tag and tag ~= '???' then
SetAbilityTagIcon(header, tag)
end
header.description:SetWidth(header:GetWidth() - 20)
header.description:SetText(
addon.API.FormatEncounterDescription(description, ORIGINALS[name].description)
)
if description == "" then header.empty = true end
table.insert(parent.children, header)
if node.children and #node.children > 0 then
RenderBossAbilities(node.children, header, layer + 1)
end
else
RenderBossAbilities(node.children, parent, layer)
end
end
end
end
local function RenderBossEncounter(bossKey, encounterName)
local frame = addon.EncounterFrame
HideOtherContent()
local bossData = CzechQuestsAddon:GetData('encounter', bossKey)
frame.summary:SetText(
addon.API.FormatEncounterDescription(bossData.overview, ORIGINALS['Overview'].description)
)
local tankHeader = frame:CreateHeader()
tankHeader.button.title:SetText("Tank")
local originalTank = ORIGINALS['Tanks'] or ORIGINALS['Tank']
local tankDescription = addon.API.FormatEncounterDescription(bossData.tank, originalTank.description)
tankHeader.description:SetText(tankDescription)
table.insert(frame.headers, tankHeader)
SetAbilityTagIcon(tankHeader, 'tank')
local healHeader = frame:CreateHeader()
healHeader.button.title:SetText("Healer")
local originalHealer = ORIGINALS['Healers'] or ORIGINALS['Healer']
local healerDescription = addon.API.FormatEncounterDescription(bossData.healer, originalHealer.description)
healHeader.description:SetText(healerDescription)
table.insert(frame.headers, healHeader)
SetAbilityTagIcon(healHeader, 'healer')
local dpsHeader = frame:CreateHeader()
dpsHeader.button.title:SetText("Damage Dealer")
local originalDps = ORIGINALS['Damage Dealers']
local dpsDescription = addon.API.FormatEncounterDescription(bossData.dps, originalDps.description)
dpsHeader.description:SetText(dpsDescription)
table.insert(frame.headers, dpsHeader)
SetAbilityTagIcon(dpsHeader, 'dps')
local bossHeader = frame:CreateHeader()
bossHeader.button.title:SetText(encounterName)
bossHeader.empty = true
table.insert(frame.headers, bossHeader)
RenderBossAbilities(bossData.abilities, bossHeader, 1)
frame:GetParent():Show()
frame:UpdateHeaderPositions()
end
local function StoreBossAbilities()
ORIGINALS = {}
local stack, _, _, _, curSectionID = {}, EJ_GetEncounterInfo(ENCOUNTER_ID)
repeat
local info = C_EncounterJournal.GetSectionInfo(curSectionID)
if not info.filteredByDifficulty then
ORIGINALS[info.title] = {}
ORIGINALS[info.title].description = info.description
ORIGINALS[info.title].creatureDisplayID = info.creatureDisplayID
ORIGINALS[info.title].uiModelSceneID = info.uiModelSceneID
ORIGINALS[info.title].abilityIcon = info.abilityIcon
end
table.insert(stack, info.siblingSectionID)
if not info.filteredByDifficulty then
table.insert(stack, info.firstChildSectionID)
end
curSectionID = table.remove(stack)
until not curSectionID
end
local function DetectBossToRender()
local frame = addon.EncounterFrame
local encounterName = EJ_GetEncounterInfo(ENCOUNTER_ID)
local difficulty = 'lfg_raid' -- 17
if DIFFICULTY == 14 then
difficulty = 'normal_raid'
elseif DIFFICULTY == 15 then
difficulty = 'heroic_raid'
elseif DIFFICULTY == 16 then
difficulty = 'mythic_raid'
elseif DIFFICULTY == 1 then
difficulty = 'normal_dungeon'
elseif DIFFICULTY == 2 then
difficulty = 'heroic_dungeon'
elseif DIFFICULTY == 23 then
difficulty = 'mythic_dungeon'
end
local bossKey = nil
for i = 1, 10 do
local id, name = EJ_GetCreatureInfo(i);
if id then
local key = name .. "_" .. difficulty
if addon.data.encounter[key] then
bossKey = key
break
end
end
end
if bossKey then
StoreBossAbilities()
RenderBossEncounter(bossKey, encounterName)
end
if bossKey == nil then
frame.summary:SetText("Pro souboj " .. encounterName .. " není vytvořen překlad.")
frame:GetParent():Show()
end
end
local function HideEncounterContent()
addon.EncounterFrame:GetParent():Hide()
end
local function ShowEncounterContent()
CURRENT_TAB_ID = ENCOUNTER_TAB_ID
HideOtherContent()
local frame = addon.EncounterFrame
frame.tab:SetHighlight(true);
EncounterJournal.encounter.info.rightShadow:Show()
EncounterJournal.encounter.info.difficulty:Show()
DetectBossToRender()
end
local function SetupCustomTab()
addon.EncounterFrame.tab:SetScript("OnClick", function()
ShowEncounterContent()
end)
hooksecurefunc("EncounterJournal_DisplayEncounter", function(encounterID)
ENCOUNTER_ID = encounterID
addon.EncounterFrame.tab:SetActive(true);
if CURRENT_TAB_ID == ENCOUNTER_TAB_ID then
ShowEncounterContent()
end
end)
hooksecurefunc("EncounterJournal_DisplayInstance", function()
addon.EncounterFrame.tab:SetActive(false);
end)
hooksecurefunc("EncounterJournal_SetTab", function(tabId)
if CURRENT_TAB_ID ~= tabId then
addon.EncounterFrame.tab:SetHighlight(false);
end
PREVIOUS_TAB_ID = CURRENT_TAB_ID
CURRENT_TAB_ID = tabId
HideEncounterContent()
end)
hooksecurefunc("EncounterJournalBossButton_OnClick", function(encounterID)
if PREVIOUS_TAB_ID == ENCOUNTER_TAB_ID then
ShowEncounterContent()
end
end)
hooksecurefunc("EncounterJournal_UpdateDifficulty", function(difficulty)
DIFFICULTY = difficulty
if PREVIOUS_TAB_ID == ENCOUNTER_TAB_ID and ENCOUNTER_ID then
ShowEncounterContent()
end
end)
end
local function InitEncounters()
local frame = addon.EncounterFrame
frame:RegisterEvent("ADDON_LOADED")
frame:SetScript("OnEvent", function(self, event, addonName)
if not CzechQuestsAddon_Store.config.ENCOUNTER_ENABLED then
return
end
if addonName == 'Blizzard_EncounterJournal' then
addon.EncounterFrame:Init()
SetupCustomTab()
end
end)
end
addon.API.InitEncounters = InitEncounters

84
Addon/Code/EncounterDataApi.lua Executable file
View file

@ -0,0 +1,84 @@
local _, addon = ...
-- Parse ability information from data
local function ParseAbilities(input, delimiter)
local result = {}
local pattern = "([^" .. delimiter .. "]*)"
local normalizedAbility = string.gsub(input, "||", "|???|")
local lastPos = 1
for part in string.gmatch(normalizedAbility, pattern) do
table.insert(result, part)
lastPos = lastPos + #part + 1
end
if input:sub(-1) == delimiter then
table.insert(result, "")
end
return result
end
addon.API.ParseAbilities = ParseAbilities
-- Replace special marks with actual numbers from original description
local function FillNumberPositionPlaceholder(text, sourceText)
local numbers = {}
local source = addon.API.ClearStringFormatMarks(sourceText)
for num in source:gmatch("(%d[%d,%.]*)") do
table.insert(numbers, num)
end
local replacedText = text:gsub("<#(%d+)%?>", function(position)
position = tonumber(position)
local n = numbers[position]
if n then
if source:match("%s+" .. n .. "%s+million") then
return n .. " <mil>"
elseif source:match("%s+" .. n .. "%s+millions") then
return n .. " <mil>"
else
return n
end
end
return "?"
end)
return replacedText
end
-- Prepare description for Encounter ability
local function FormatEncounterDescription(text, original)
local formated = FillNumberPositionPlaceholder(text, original)
formated = addon.API.ParseParagraphs(original, formated)
formated = addon.API.ColorSpellNames(formated)
-- fix [mil], 4 s, 5 %
formated = string.gsub(formated, "<mil>", "mil.")
formated = string.gsub(formated, "(%d+) s([%s%.%,%?%!])", "%1s%2")
formated = string.gsub(formated, "(%d+) %%([%s%.])", "%1%%%2")
return formated
end
addon.API.FormatEncounterDescription = FormatEncounterDescription
-- Return specific Encounter Ability data
local function GetEncounterAbility(abilityKey)
return addon.data.encounter[abilityKey].m or nil
end
addon.API.GetEncounterAbility = GetEncounterAbility
-- Get Encounter object
local function GetEncounter(bossKey)
return {
abilities = addon.data.encounter[bossKey] or nil,
overview = addon.data.encounter[bossKey .. "_summary_instance"].m or nil,
tank = addon.data.encounter[bossKey .. "_summary_tank"].m or nil,
healer = addon.data.encounter[bossKey .. "_summary_healer"].m or nil,
dps = addon.data.encounter[bossKey .. "_summary_dps"].m or nil,
}
end
addon.API.GetEncounter = GetEncounter

241
Addon/Code/EncounterFrame.lua Executable file
View file

@ -0,0 +1,241 @@
local _, addon = ...
local EncounterFrame = CreateFrame("Frame", nil)
EncounterFrame:Hide()
addon.EncounterFrame = EncounterFrame
EncounterFrame.headers = {}
local NEXT_HEADER_ID = 0
function EncounterFrame:Init()
local frame = self
if not EncounterJournal or not EncounterJournal.encounter or not EncounterJournal.encounter.info then
return
end
local scrollFrame = CreateFrame("ScrollFrame", "$parentOverviewScrollFrame", EncounterJournal.encounter.info, "ScrollFrameTemplate")
scrollFrame:SetSize(330, 370)
scrollFrame:SetPoint("TOPLEFT", EncounterJournal.encounter.info.overviewScroll, "TOPLEFT", 0, -7)
scrollFrame.scrollBarX = -25
scrollFrame.scrollBarTopY = -6
scrollFrame.scrollBarBottomY = 6
frame:SetParent(scrollFrame)
frame:SetSize(scrollFrame:GetWidth() - 10, 1)
frame:Show()
scrollFrame:SetScrollChild(frame)
frame.summary = addon.API.CreateCzechFont(
frame,
CzechQuestsAddon_Store.config.ENCOUNTER_TEXT_FONT_NAME,
CzechQuestsAddon_Store.config.ENCOUNTER_TEXT_FONT_SIZE
)
frame.summary:SetTextColor(0.251, 0.145, 0.012)
frame.summary:SetPoint("TOPLEFT", frame, "TOPLEFT", 2, 0)
frame.summary:SetWidth(scrollFrame:GetWidth() - 10)
frame:UpdateSettings()
frame:InitTab()
end
function EncounterFrame:UpdateSettings()
local frame = self
addon.API.UpdateCzechFont(
frame.summary,
CzechQuestsAddon_Store.config.ENCOUNTER_TEXT_FONT_NAME,
CzechQuestsAddon_Store.config.ENCOUNTER_TEXT_FONT_SIZE
)
for _, header in ipairs(self.headers) do
addon.API.UpdateCzechFont(
header.description,
CzechQuestsAddon_Store.config.ENCOUNTER_TEXT_FONT_NAME,
CzechQuestsAddon_Store.config.ENCOUNTER_TEXT_FONT_SIZE
)
end
end
function EncounterFrame:InitTab()
local frame = self
local tab = CreateFrame("Button", "EncounterJournalCustomTab", EncounterJournal.encounter.info, "EncounterTabTemplate")
tab:SetPoint("TOP", EncounterJournal.encounter.info.modelTab, "BOTTOM", -3, -12)
tab:SetSize(50, 40)
tab.tooltip = "Taktika"
local selected = tab:CreateTexture(nil, "BACKGROUND")
selected:SetTexture("Interface\\EncounterJournal\\UI-EncounterJournalTextures")
selected:SetAllPoints(tab)
selected:SetBlendMode("ADD")
selected:SetDrawLayer("OVERLAY")
selected:SetTexCoord(0, 0.126953125, 0.90234375, 0.9599609375)
selected:Hide()
tab.selected = selected
function tab:SetActive(enable)
self:SetEnabled(enable);
self:GetDisabledTexture():SetDesaturated(not enable);
end
function tab:SetHighlight(enable)
if not enable then
self.selected:Hide();
else
self.selected:Show();
end
end
frame.tab = tab
end
function EncounterFrame:CreateHeader()
local frame = self
local id = NEXT_HEADER_ID + 1
NEXT_HEADER_ID = id
local HeaderFrame = CreateFrame("FRAME", "CzechQuestsEncounterHeader" .. id, frame, "EncounterInfoTemplate")
HeaderFrame:SetSize(self:GetParent():GetWidth() - 10, 30)
addon.API.UpdateCzechFont(
HeaderFrame.description,
CzechQuestsAddon_Store.config.ENCOUNTER_TEXT_FONT_NAME,
CzechQuestsAddon_Store.config.ENCOUNTER_TEXT_FONT_SIZE
)
HeaderFrame.button.abilityIcon:Hide()
HeaderFrame.button.portrait:Hide()
HeaderFrame.button.icon2:Hide()
HeaderFrame.button.icon3:Hide()
HeaderFrame.button.icon4:Hide()
HeaderFrame.button.expandedIcon:SetText("+")
HeaderFrame.expanded = false
HeaderFrame.empty = false
HeaderFrame.button.title:SetPoint("TOPLEFT", HeaderFrame, "TOPLEFT", 30, -7);
HeaderFrame.button.title:SetWidth(self:GetParent():GetWidth() - 110)
for i = 1, #HeaderFrame.Bullets do
HeaderFrame.Bullets[i]:Hide()
end
wipe(HeaderFrame.Bullets)
for _, icon in ipairs(HeaderFrame.button.icons) do
icon:Hide()
end
HeaderFrame.description:SetWidth(HeaderFrame:GetWidth() - 20)
HeaderFrame.description:Hide()
HeaderFrame.overviewDescription:Hide()
HeaderFrame.descriptionBG:Hide()
HeaderFrame.descriptionBGBottom:Hide()
function HeaderFrame:Open()
local header = self
header.button.expandedIcon:SetText("-")
if (header.empty == false) then
header.description:Show()
header.descriptionBG:Show()
header.descriptionBGBottom:Show()
end
end
function HeaderFrame:Close()
local header = self
header.button.expandedIcon:SetText("+")
header.description:Hide()
header.descriptionBG:Hide()
header.descriptionBGBottom:Hide()
end
HeaderFrame.button:SetScript("OnClick", function(self)
local header = self:GetParent()
header.expanded = not header.expanded
EncounterJournal_UpdateButtonState(header.button)
if header.expanded then
header:Open()
else
header:Close()
end
frame:ToggleHeader(header)
end)
return HeaderFrame
end
function EncounterFrame:UpdateHeaderPositions()
local yOffset = -40
local function updatePosition(headers)
for _, header in ipairs(headers) do
header:SetPoint("BOTTOMRIGHT", self.summary, "BOTTOMRIGHT", 0, yOffset)
if header.expanded then
yOffset = yOffset - header.description:GetHeight()
if header.empty == false then
yOffset = yOffset - 50
else
yOffset = yOffset - 30
end
if header.children and #header.children > 0 then
yOffset = updatePosition(header.children)
end
else
yOffset = yOffset - 30
end
end
return yOffset
end
updatePosition(self.headers)
end
function EncounterFrame:ToggleHeader(header)
if header.expanded and header.children then
for _, child in ipairs(header.children) do
child:Show()
end
end
if not header.expanded and header.children then
local function hideChildren(children)
for _, child in ipairs(children) do
child.expanded = false
child:Close()
child:Hide()
if child.children then
hideChildren(child.children)
end
end
end
hideChildren(header.children)
end
self:UpdateHeaderPositions()
end
function EncounterFrame:ClearHeaders()
local function clear(headers)
for _, header in ipairs(headers) do
header:Hide()
header:SetParent(nil)
if header.children and #header.children > 0 then
clear(header.children)
end
header = nil
end
wipe(headers)
end
clear(self.headers)
end

View file

@ -5,19 +5,23 @@ local FontPath = "Interface\\AddOns\\CzechQuests\\Assets\\Fonts\\"
local TestFont = UIParent:CreateFontString(nil, "BACKGROUND", "GameFontNormal")
TestFont:SetPoint("TOP", UIParent, "BOTTOM", 0, -64);
local function CreateCzechFont(frame, name, size, flags)
local font = frame:CreateFontString(nil, "OVERLAY")
local function CreateCzechFont(frame, name, size, flags, style)
local font = frame:CreateFontString(nil, "OVERLAY", style)
font:SetTextColor(0, 0, 0, 1)
font:SetJustifyH("LEFT")
font:SetWidth(frame:GetWidth())
font:SetWordWrap(true)
font:SetFont(FontPath ..name, size, flags or "")
return font
end
addon.API.CreateCzechFont = CreateCzechFont
local function UpdateCzechFont(FontString, name, size)
local _, _, flags = FontString:GetFont()
FontString:SetFont(FontPath .. name, size, flags)
if not FontString then
return
end
local _, currentSize, flags = FontString:GetFont()
FontString:SetFont(FontPath .. name, size or currentSize, flags)
end
addon.API.UpdateCzechFont = UpdateCzechFont

View file

@ -116,6 +116,22 @@ local function InitSpeeches()
end
local function InitEncounters()
local function Update(name, value)
CzechQuestsAddon_Store.config[name] = value
addon.EncounterFrame:UpdateSettings()
end
local layout = Options.layout
layout:AddInitializer(CreateSettingsListSectionHeaderInitializer("Taktiky"))
CreateCheckbox("ENCOUNTER_ENABLED", "Zapnout *", Update)
CreateDropdown("ENCOUNTER_TEXT_FONT_NAME", "Pismo *", addon.API.GetFontContainer, Update)
CreateSlider("ENCOUNTER_TEXT_FONT_SIZE", "Velikost pisma *", 10, 30, 1, Update)
end
local function InitOthers()
local layout = Options.layout
layout:AddInitializer(CreateSettingsListSectionHeaderInitializer("Ostatni"))
@ -125,12 +141,15 @@ local function InitOthers()
end
local function InitOptions()
local category, layout = Settings.RegisterVerticalLayoutCategory("CzechQuests")
local category, layout = Settings.RegisterVerticalLayoutCategory("Czech Quests")
Options.category = category
Options.layout = layout
InitQuests()
InitSpeeches()
if (WOW_PROJECT_ID ~= WOW_PROJECT_CLASSIC) then
InitEncounters()
end
InitOthers()
Settings.RegisterAddOnCategory(category)

View file

@ -1,5 +1,6 @@
local _, addon = ...
-- Split original text by break-lines
local function SplitParagraphs(text)
local paragraphs = {}
for paragraph in string.gmatch(text, "([^\n]+)") do
@ -8,6 +9,7 @@ local function SplitParagraphs(text)
return paragraphs
end
-- Split text into sentences
local function SplitSentences(paragraph)
local sentences = {}
for sentence in string.gmatch(paragraph, "([^%.%?!]+[%.%?!]?)[%s]*") do
@ -19,10 +21,17 @@ local function SplitSentences(paragraph)
return sentences
end
-- Put break-lines
local function ReplaceMultipleBreakLines(text)
return text:gsub("\r?\n+", "\n\n")
end
-- Because decimal numbers contain dot, remove space between those numbers
local function FixDecimalNumbers(text)
return text:gsub("(%d+)%.%s+(%d+)", "%1.%2")
end
-- Fix translated text break-line based on original
local function ParseParagraphs(original_text, translation_text)
if original_text == "" or original_text == nil then
return translation_text
@ -58,8 +67,9 @@ local function ParseParagraphs(original_text, translation_text)
table.insert(translation_paragraphs, table.concat(collected, " "))
end
return ReplaceMultipleBreakLines(
table.concat(translation_paragraphs, "\n")
)
local multilines = ReplaceMultipleBreakLines(table.concat(translation_paragraphs, "\n"))
local fixedDecimalNumbers = FixDecimalNumbers(multilines)
return fixedDecimalNumbers
end
addon.API.ParseParagraphs = ParseParagraphs

View file

@ -66,26 +66,26 @@ local function ShowQuestTranslation(event)
end
end
local function ShowQuestItemTranslation()
local function ShowBookTranslation()
local frame = addon.QuestFrame
frame:Hide()
-- classic and retail has same frame
if ItemTextFrame:IsVisible() then
local itemName = ItemTextGetItem();
local itemNameTranslation = CzechQuestsAddon:GetData("item", itemName)
local itemNameTranslation = CzechQuestsAddon:GetData("book", itemName .. "_name")
if itemNameTranslation then
local pageNum = ItemTextGetPage()
local itemPageContentTranslation = CzechQuestsAddon:GetData("item", itemName .. '__' .. pageNum)
local itemPageContentTranslation = CzechQuestsAddon:GetData("book", itemName .. '_page_' .. pageNum)
if itemPageContentTranslation then
frame:SetData(
itemNameTranslation.title,
itemPageContentTranslation.text,
itemNameTranslation.m,
addon.API.ResolveGender(itemPageContentTranslation),
"",
"",
ItemTextFrame,
-20,
0
5
)
end
end
@ -137,7 +137,7 @@ local function InitQuests()
end
if (event == "ITEM_TEXT_READY") then
ShowQuestItemTranslation()
ShowBookTranslation()
end
if CzechQuestsAddon_Store.config.QUEST_TEXTURE_ALPHA_ONLY_MOVING then

View file

@ -77,15 +77,23 @@ local function FillPlaceholders(text)
return formatted
end
local function GetQuestText(maleText, femaleText, original)
local translation = addon.API.ResolveGender(maleText, femaleText)
local function GetQuestText(questTranslation, original)
if questTranslation == nil then
return nil
end
local translation = addon.API.ResolveGender(questTranslation)
local paragraphs = addon.API.ParseParagraphs(original, translation)
return FillPlaceholders(paragraphs)
end
local function GetQuest(id)
local quest = addon.data.quest[id];
if quest then
local questName = addon.data.quest['q' .. id .. '_name'];
local questObjective = addon.data.quest['q' .. id .. '_objective'];
local questDescription = addon.data.quest['q' .. id .. '_description'];
local questProgress = addon.data.quest['q' .. id .. '_progress'];
local questCompletion = addon.data.quest['q' .. id .. '_completion'];
if questName or questObjective or questDescription or questProgress or questCompletion then
local description = ""
local objective = ""
@ -98,11 +106,11 @@ local function GetQuest(id)
end
return {
title = GetQuestText(quest.titleMale, quest.titleFemale),
objective = GetQuestText(quest.objectiveMale, quest.objectiveFemale, objective),
description = GetQuestText(quest.descriptionMale, quest.descriptionFemale, description),
progress = GetQuestText(quest.progressMale, quest.progressFemale),
completion = GetQuestText(quest.completionMale, quest.completionFemale),
title = GetQuestText(questName),
objective = GetQuestText(questObjective, objective),
description = GetQuestText(questDescription, description),
progress = GetQuestText(questProgress),
completion = GetQuestText(questCompletion),
}
end
end

17
Addon/Code/Shared.lua Normal file
View file

@ -0,0 +1,17 @@
local _, addon = ...
local function ClearStringFormatMarks(text)
-- Remove colors (|cffffff...)
text = text:gsub("|c%x%x%x%x%x%x%x%x", "")
-- Remove H marks
text = text:gsub("|H.-|h", "")
return text
end
addon.API.ClearStringFormatMarks = ClearStringFormatMarks
local function ColorSpellNames(text, color)
return text:gsub("%[(.-)%]", function(match)
return string.format("|c%s[%s]|r", color or "FF0000FF", match)
end)
end
addon.API.ColorSpellNames = ColorSpellNames

View file

@ -76,7 +76,7 @@ end
addon.API.AddSpeechMessage = AddMessage
local function ShowSpeechTranslation(sender, message)
local text = CzechQuestsAddon:GetData("speech", message)
local text = CzechQuestsAddon:GetData("speech", sender .. "_" .. message)
if text == nil and CzechQuestsAddon_Store.config.SPEECH_ORIGINAL_WHEN_MISSING then
text = message
end

View file

@ -1,5 +1,28 @@
local _, addon = ...
local function BuildIndex(text)
local numberMarks = text:gsub("%d+%.?%d*", "#?")
local normalized = numberMarks:gsub('"', "'")
return normalized
end
local function FillNumbers(text, sourceText)
local numbers = {}
local currentIndex = 1
for num in sourceText:gmatch("%d+%.?%d*") do
table.insert(numbers, num)
end
local replacedText = text:gsub("#%?", function()
local n = numbers[currentIndex]
currentIndex = currentIndex + 1
return n or "?"
end)
return replacedText
end
local function FillPlaceholders(text)
if text == nil then
return text
@ -9,15 +32,18 @@ local function FillPlaceholders(text)
local formatted = text;
formatted = string.gsub(formatted, '<name>', playerName);
formatted = string.gsub(formatted, 'Champions', playerName);
formatted = string.gsub(formatted, 'champions', playerName);
return formatted
end
local function GetSpeech(message)
local speech = addon.data.speech[message];
local text = speech and speech.text or nil
return FillPlaceholders(text)
local index = BuildIndex(message)
local speech = addon.data.speech[index];
local text = speech and speech.m or nil
if text then
return FillPlaceholders(FillNumbers(text, message))
else
return nil
end
end
addon.API.GetSpeech = GetSpeech

View file

@ -45,8 +45,7 @@ function SpeechFrame:CreateMessage()
MessageFrame.Message = addon.API.CreateCzechFont(
MessageFrame,
CzechQuestsAddon_Store.config.SPEECH_TEXT_FONT_NAME,
CzechQuestsAddon_Store.config.SPEECH_TEXT_FONT_SIZE,
"THICK"
CzechQuestsAddon_Store.config.SPEECH_TEXT_FONT_SIZE
)
MessageFrame.Message:SetTextColor(1, 1, 1)
MessageFrame.Message:SetPoint("TOPLEFT", MessageFrame, "TOPLEFT", 5, -5)

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,482 @@
local _, addon = ...
addon.data.quest["q85251_description"] = {
m = "Konečně nastal čas. Stálo mě to všechno, než jsem našel Van Amburghův tábor, a navíc jsem byl zraněn jednou z jeho pastí. Jeho zvířata jsou s ním. Jsi připraven to dokončit?",
}
addon.data.quest["q85251_completion"] = {
m = "Je hotovo. Van Amburgh už nebude páchat žádná další zvěrstva.",
}
addon.data.quest["q85699_name"] = {
m = "Snakestone of the Shadow Huntress (Hadí kámen lovkyně stínů)",
}
addon.data.quest["q85699_objective"] = {
m = "Vydejte se do Blackrock Spire a zabijte lovce stínů Vosh'gajina. Získejte Vosh'gajinův hadí kámen a vraťte se do Kilramu.",
}
addon.data.quest["q85699_description"] = {
m = "Nenech se zmást její krásou, <cM3>. Stínová lovkyně Voš'gajin je smrtelně nebezpečná a vyšinutá.\n\n<Kilram ukazuje na jizvu na tváři.>\n\nJo, tu mi dala - milostný ťukanec, tak tomu říkala.\n\nKonečně nadešel čas pomsty.\n\nVosh'gajin najdete v Blackrock Spire. Zabij ji a vrať mi její hadí kámen. Udělej to a já tě naučím způsobům sekerníka.",
f = "Nenech se zmást její krásou, <cF4>. Stínová lovkyně Vosh'gajin je smrtelně nebezpečná a vyšinutá.\n\n<Kilram ukazuje na jizvu na tváři.>\n\nJo, tu mi dala - milostný ťukanec, tak tomu říkala.\n\nKonečně nadešel čas pomsty.\n\nVosh'gajin najdete v Blackrock Spire. Zabij ji a vrať mi její hadí kámen. Udělej to a já tě naučím způsobům sekerníka.",
}
addon.data.quest["q85699_progress"] = {
m = "Legenda praví, že jedno použití Voš'gajinova hadího kamene udrží sekeru ostrou po dobu 1000 let!",
}
addon.data.quest["q85699_completion"] = {
m = "Takže jste si jistí, že to je to, co chcete? Stát se sekerníkem? Nezapomeň, že dveře k tomu, aby ses stal mečířem a kladivářem, se navždy zavřou.",
}
addon.data.quest["q85066_name"] = {
m = "Připravenost",
}
addon.data.quest["q85066_objective"] = {
m = "Promluvte si v Andorhalu s Gregorem a požádejte ho, aby vás doprovodil na spálení Andorhalu.",
}
addon.data.quest["q85066_description"] = {
m = "Invaze démonů a rituály smrti! To vše zní velmi děsivě. Naštěstí se díky této malé časové bublině, ve které stojíme, můžeme snadno spojit s určitým časovým bodem na tomto místě. Bude to však nebezpečné. Až budete s přítelem připraveni, řekněte slovo.",
}
addon.data.quest["q85066_completion"] = {
m = "Pak se to opravdu děje...\n\nI když to nerad přiznávám, nemyslím si, že jsem ten nejlepší člověk, který by se s tebou mohl vrátit. Mé tělo utrpělo příliš mnoho škod mezi Aeonasovým svatým ohněm a útokem démonů. Ve svém současném stavu vás spíš zpomalím, než abych vám pomohl. Když je Ada mrtvá, myslím, že budeme potřebovat pomoc zvenčí.",
}
addon.data.quest["q85385_name"] = {
m = "Knihovníkův učeň",
}
addon.data.quest["q85385_objective"] = {
m = "Promluvte si s Valxxem Cracklequilem v Everlooku a zjistěte, co se o něm povídá.",
}
addon.data.quest["q85385_description"] = {
m = "Tvůj objev esence ohně výrazně rozšířil naše znalosti o arkánech. Slyšel jsem zvěsti o podobné síle ve Winterspringu, i když je mrazivé povahy. Můj společník v Everlooku bude mít více informací o podrobnostech.",
}
addon.data.quest["q85385_completion"] = {
m = "Takže tě poslali ti staří netopýři z knihovny, co? Nemají mě moc rádi, říkají, že 'střelný prach a magie se nemíchají'. Pche.\n\nJo, o tom, na co se ptáš, něco vím. Naštěstí pro tebe mám moc práce, než abych se tím zabýval sám.",
}
addon.data.quest["q85630_name"] = {
m = "Paragony moci: Iluzionistické závoje",
}
addon.data.quest["q85630_objective"] = {
m = "Přineste Al'tabimovi Vševidoucí primární vazbu Hakkari. Musíš mít také pověst stejnou nebo vyšší než Přátelská u kmene Zandalar.\n\nVševidoucí Al'tabim se nachází na ostrově Yojamba ve Stranglethorn Vale.",
}
addon.data.quest["q85630_description"] = {
m = "Mágové v našem kmeni jsou známí jako iluzionisté. Ve svých zaklínadlech používají mocné kouzlo, které často zmate a poplete nepřátele kmene!\n\n<Al'tabim se zlomyslně směje.>\n\nJe to docela pěkná podívaná vidět mocného iluzionistu při práci, jak sráží naše nepřátele na kolena z jejich vlastního šílenství!\n\nAbys poznal způsob práce našich iluzionistů, jdi do Zul'Gurubu a přiveď mi vybrané Paragony moci. Za to ti dám obaly na ruce, které naši iluzionisté používají ke splétání svých kouzel.",
}
addon.data.quest["q85630_progress"] = {
m = "<name> - už ses vrátil? Podařilo se ti získat Paragony moci, které potřebuji?",
}
addon.data.quest["q85630_completion"] = {
m = "Působivé... cítili jste, jak jimi proudí mojo? Paragony moci se používaly jako svého druhu platidlo v dobách, kdy těmto zemím vládla říše Gurubaši. Nyní my, Zandalar, využijeme latentní mojo, které se v nich skrývá, v boji proti druhému vzestupu krvavého boha Hakkara!\n\nDnes sis vedl dobře - považuj se za přítele v Zandalaru. Za to jsou tu iluzionistické zábaly, které jsem slíbil!",
}
addon.data.quest["q85067_name"] = {
m = "Paladin Stříbrné ruky",
}
addon.data.quest["q85067_objective"] = {
m = "Jdi do Utherovy hrobky a vysvětli Aeonasovi situaci.",
}
addon.data.quest["q85067_description"] = {
m = "Řekl jsem, že nevěřím na osud, ale nevím, jestli to byla úplně pravda. Můj pohled na věc se od konce mého smrtelného života hodně změnil, ale čím déle jsem na této misi, tím víc začínám ve věcech vidět zákonitosti a souvislosti. Myslím, že už to víš, ale to Aeonas musí jít s tebou. Věř mi, když říkám, že bych si nepřál nic jiného než nechat svého starého přítele na pokoji, ale tohle je něco většího, než co chci já. Jdi do Utherovy hrobky a vysvětli mu situaci.",
}
addon.data.quest["q85067_completion"] = {
m = "<Gregory kývne na tebe a pak na Aeonase>\n\nJe čas. <name> Jdi si promluvit s Chromiem, až budeš připraven.",
}
addon.data.quest["q85660_name"] = {
m = "Srdce Hakkaru",
}
addon.data.quest["q85660_objective"] = {
m = "Přineste Srdce Hakkaru Molthorovi na ostrov Yojamba.",
}
addon.data.quest["q85660_description"] = {
m = "Hakkarovo srdce hoří zevnitř. Přestože je Vrah duší poražen, jádro jeho moci v tomto prokletém orgánu stále zůstává.",
}
addon.data.quest["q85660_completion"] = {
m = "Ach, srdce Hakkaru. Tak byl Zabiják duší zabit! Náš svět je zachráněn!\n\n<name>, tvé služby pro nás nelze přeceňovat. Skutečně jsi hrdina této říše!",
}
addon.data.quest["q85615_name"] = {
m = "Paragony moci: Náprsní štít mstitele (Paragons of Power: The Vindicator's Breastplate)",
}
addon.data.quest["q85615_objective"] = {
m = "Přineste Jin'rokh the Breaker a Primal Hakkari Kossack. Zároveň musíš mít u kmene Zandalar reputaci stejnou nebo vyšší než Uctívaný.\n\nJin'rokh Breaker se nachází na ostrově Yojamba ve Stranglethorn Vale.",
}
addon.data.quest["q85615_description"] = {
m = "Symbolem moci mstitele je náprsní štít. Je vykovaný mocným mojo. Je svěřen pouze těm, které ctíme. Je to zandalarský symbol pomsty.\n\nStát se mstitelem znamená stát se pomstou. Vezměte si od Zul'Guruba Paragony moci, které potřebujeme. Přiveďte je k nám. My si vezmeme mojo, které nám bylo ukradeno. Donutíme Hakkarovy přisluhovače zaplatit. Odměníme tě náprsním štítem mstitele.\n\nJdi. Buď naší pomstou, <name>.",
}
addon.data.quest["q85611_name"] = {
m = "Paragoni moci: Haruspexova tunika",
}
addon.data.quest["q85611_objective"] = {
m = "Přineste Maywiki ze Zuldazaru primární hakkárský tabard. Maywiki of Zuldazar se nachází na ostrově Yojamba ve Stranglethorn Vale. Musíš být také uctíván Zandalarem.",
}
addon.data.quest["q85611_description"] = {
m = "Nejvyšším symbolem moci haruspexe je to, co nosí, <name>. Z nich tunika symbolizuje spojení mezi nimi a božskou moudrostí, kterou hledají. Často do tuniky vplétá části bestií, které obětují; to jim připomíná spojení, které mají se svými dary.\n\nPřineste mi oběť z Paragonů moci z nitra Zul'Gurubu a dokažte nám svou cenu. Udělej to a tunika prosycená skutečnou mocí haruspexu bude tvá.",
}
addon.data.quest["q85611_progress"] = {
m = "Máte potřebné Paragony moci ze Zul'Gurubu? Haruspexova tunika stojí za jakoukoli námahu, kterou budeš muset vynaložit.",
}
addon.data.quest["q85611_completion"] = {
m = "Působivé... úspěšně jsi shromáždil požadované Paragony moci, <name>. Tvé úspěchy v Zul'Gurubu pro Zandalar jsou legendární; od nynějška budeš mezi kmenem uctíván. Zde je tvá tunika, mocný <cM3>!",
f = "Působivé... úspěšně jsi shromáždil požadované Paragony moci, <name>. Tvé úspěchy v Zul'Gurubu pro Zandalar jsou legendární; od nynějška budeš mezi kmenem uctíván. Zde je tvá tunika, mocná <cF4>!",
}
addon.data.quest["q85609_name"] = {
m = "Paragony moci: Haruspexova nárameníky",
}
addon.data.quest["q85609_objective"] = {
m = "Přineste Maywiki ze Zuldazaru primární hakkárskou hůl. Musíš mít také stejnou nebo vyšší reputaci než Přátelský u kmene Zandalar.\n\nMaywiki ze Zuldazaru se nachází na ostrově Yojamba, Stranglethorn Vale.",
}
addon.data.quest["q85609_description"] = {
m = "Haruspex je klíčovým členem našeho kmene; bylo by moudré naslouchat jeho předpovědím. Tím, že komunikují se zvířaty a v případě potřeby je předávají duchům, nám poskytují božské vedení. V minulých dobách nám haruspexův vhled a moudrost poskytovaly výhodu ve válkách proti roztříštěným kmenům Gurubaši.\n\nPřines mi nabídku Paragonů moci z nitra Zul'Gurubu a dokaž nám svou cenu. Udělej to a já ti dám nárameníky, které by chtěl každý haruspex ze Zandalaru.",
}
addon.data.quest["q85609_progress"] = {
m = "Máš Paragony moci ze Zul'Gurubu? Tyhle nárameníky stojí za námahu, <name>. Věř mi, mon!",
}
addon.data.quest["q85609_completion"] = {
m = "Ach, cítím sílu, která vychází z těchto Vzorů moci, <name>. Ukázalo se, že jsi někdo, koho můžeme v kmeni nazývat 'přítelem'. Dohoda je dohoda, <name>... hle, síla haruspexových nárameníků!",
}
addon.data.quest["q85640_name"] = {
m = "Paragony moci: Plášť dravce",
}
addon.data.quest["q85640_objective"] = {
m = "Přiveď následující Paragony moci ze Zul'Gurubu k Falthirovi Bezzrakému: A Primal Hakkari Aegis. Dále musíš mít u kmene Zandalar pověst stejnou nebo vyšší než Uctívaný.\n\nFalthir the Sightless se nachází na ostrově Yojamba ve Stranglethorn Vale.",
}
addon.data.quest["q85640_description"] = {
m = "My Zandalar si ceníme toho, co nosíme jako symbol úspěchu. Nemusíte vidět, co má člověk na sobě, abyste dokázali vycítit, co z něj vyzařuje - moc přesahuje zrak. Oděv zandalarského dravce je takový a nejvíce si cení pláště, který nosí. Pomáhá jim zakrýt pohled... a dát najevo svou přítomnost, když si to přejí.\n\nParagoni moci čekají na vaše získání v Zul'Gurubu. Přines mi, co hledám, a plášť dravce bude tvůj.",
}
addon.data.quest["q85093_name"] = {
m = "NEPOUŽITÉ",
}
addon.data.quest["q85093_objective"] = {
m = "Promluvte si s Gregorym na Smutečním vrchu poblíž mostu do Andorhalu.",
}
addon.data.quest["q85093_description"] = {
m = "Rád bych s vámi naposledy promluvil, než odjedu. Prosím, sejdeme se ještě jednou u mostu do Andorhalu na Smutečním vrchu. Budeme přemýšlet o tom, co se stalo, a o Aeonasově oběti, která nám vynesla toto vítězství.",
}
addon.data.quest["q85623_name"] = {
m = "Paragony moci: Vazba Zpovědnice",
}
addon.data.quest["q85623_objective"] = {
m = "Přineste Al'tabimu Vševidoucímu prvotní hakkari šerpu. Zároveň musíš mít u kmene Zandalar pověst stejnou nebo vyšší než Čestný.\n\nVševidoucí Al'tabim se nachází na ostrově Yojamba ve Stranglethorn Vale.",
}
addon.data.quest["q85623_description"] = {
m = "Krátce po pádu Gurubaši jsme my, Zandalar, málem podlehli konečné porážce od zla uvnitř vlastního kmene. Tehdy mezi námi povstali vyznavači, kteří zachovali kmen tím, že vyhnali ty, kdo by chtěli zničit vlastní druh. Nejenže nás udržují v souladu s duchy, ale také chrání tělo.\n\nVydej se do Zul'Gurubu a na vlastní oči se přesvědč o zkaženosti Hakkaru a Gurubaši. Zápaste s Paragony moci, které od nich hledáme; úspěch bude odměněn!",
}
addon.data.quest["q85623_progress"] = {
m = "Paragony moci... máte je? Teprve až je budeme mít, budeme moci využít latentní sílu, která je v nich uložena. Bylo by dobré obrátit karty proti přisluhovačům Boha krve...",
}
addon.data.quest["q85623_completion"] = {
m = "Úspěch! Ty nám pomohou posílit naši sílu proti vzestupu Hakkaru. S vaší pomocí jsme učinili významný krok k tomu, aby nás Bůh krve všechny nezničil.\n\nDnes sis u kmene vysloužil čest, <name>. Vezmi si toto - zpovědnické pouto - jako symbol našeho poděkování.",
}
addon.data.quest["q85624_name"] = {
m = "Paragony moci: Plášť zpovědníka",
}
addon.data.quest["q85624_objective"] = {
m = "Přineste Al'tabimovi Vševidoucímu prvotní hakkárskou egidu. Zároveň musíš mít u kmene Zandalar pověst stejnou nebo vyšší než Uctívaný.\n\nVševidoucí Al'tabim se nachází na ostrově Yojamba ve Stranglethorn Vale.",
}
addon.data.quest["q85624_description"] = {
m = "Všichni zpovědníci Zandalaru nosí charakteristický plášť, který je označuje jako ochránce kmene. Tyto pláště jsou protkány mocným mojo, které jim pomáhá soudit ty, kdo by chtěli náš kmen ohrozit. Jako kněz musíš i ty trávit svůj čas posuzováním těch hodných a nehodných; takový plášť by pro tebe byl rozhodně požehnáním.\n\nVýměnou za boj s Hakkarovými přisluhovači v Zul'Gurubu a za to, že mi přineseš Paragony moci, které hledám, ti dám plášť hodný našich nejlepších zpovědníků.",
}
addon.data.quest["q85626_name"] = {
m = "Paragony moci: Démonické zábaly (Paragons of Power: The Demoniac's Wraps)",
}
addon.data.quest["q85626_objective"] = {
m = "Přineste Al'tabimu Vševidoucímu prvotní hakkárský staniol. Zároveň musíš mít u kmene Zandalar pověst stejnou nebo vyšší než Přátelská.\n\nVševidoucí Al'tabim se nachází na ostrově Yojamba v údolí Stranglethorn.",
}
addon.data.quest["q85626_description"] = {
m = "Čarodějové se při jednání s démony pohybují na nebezpečné půdě, ale naši démoni jdou ještě o krok dál. Prostřednictvím starobylého a tajemného rituálu nechají démona vstoupit do své bytosti. Místo aby se jím nechali ovládnout, zotročí démona zevnitř a pohltí jeho sílu pro své vlastní rozkazy. Je to výkon, který se podaří zvládnout jen málokomu.\n\nAbys poznal démonovu moc, musím mít od Zul'Guruba Paragony moci. Jdi tam a získej to, co hledáme.",
}
addon.data.quest["q85626_progress"] = {
m = "Vrátili jste se s Paragony moci? Porážkou ďábelských přisluhovačů Hakkaru nám prokážeš nejen sebe, ale i svou ochotu naučit se způsobům démona.",
}
addon.data.quest["q85626_completion"] = {
m = "Dobrá práce... nepochybně za to museli zaplatit nesnesitelnými způsoby, než se vzdali Paragonů moci. Vezměte si tohle - zábaly démona. Je vyroben z mocného mojo, které se používá při vyvolávání démonické kořisti, a je mocným nástrojem při získávání moci.",
}
addon.data.quest["q85435_name"] = {
m = "Nečistý zásah",
}
addon.data.quest["q85435_objective"] = {
m = "Zastavte korupci Mazthorilu.",
}
addon.data.quest["q85435_description"] = {
m = "Zatímco jsi byl pryč, slyšel jsem, že se v Mazthorilu děje něco opravdu ošklivého. Zdá se, že je to něco pro tebe, tak se jdi podívat, co můžeš udělat, abys to vyřešil. Ti modří draci toho o arkánech vědí hodně, třeba ti za to něco dají.\n\nSlyšel jsem, že jsi opravdu pilně sbíral esoterické znalosti. Našel jsem tyhle svitky, mohly by se hodit.",
}
addon.data.quest["q85613_name"] = {
m = "Paragoni moci: Vindikátorova zbrojnice",
}
addon.data.quest["q85613_objective"] = {
m = "Přineste Jin'rokh the Breakerovi Primal Hakkari Armsplint. Musíš mít také u kmene Zandalar pověst stejnou nebo vyšší než Přátelská.\n\nJin'rokh Breaker se nachází na ostrově Yojamba, Stranglethorn Vale.",
}
addon.data.quest["q85613_description"] = {
m = "Pomsta je moc. Zandalarský mstitel je takovou silou. Kmen má mnoho nepřátel. Mstitel na nich vymáhá odplatu. Žádný zločin proti nám nezůstane nepotrestán. Mstitel tento trest vykoná. Naši nepřátelé se bojí naší pomsty. Měli by. Navždy se budou bát.\n\nStaňte se jedním z našich mstitelů. Hledejte Paragony moci uvnitř Zul'Gurubu. Zabijte Hakkarovy přisluhovače a ve jménu kmene se domáhejte pomsty. Budeš odměněn.",
}
addon.data.quest["q85613_progress"] = {
m = "Přinesl jsi Paragony moci? Byla požadována pomsta ve jménu Zandalaru?",
}
addon.data.quest["q85613_completion"] = {
m = "Dnes jsi vykonal velkou pomstu. Přijal jsi podobu mstitele. Srazil jsi na kolena přisluhovače Boha krve.\n\nVezmi si tohle. Bude to živit tvou pomstu v budoucnu. Nyní jsi přítelem Zandalaru.",
}
addon.data.quest["q85620_name"] = {
m = "Paragons of Power: The Freethinker's Breastplate (Paragony moci: Náprsenka volnomyšlenkáře)",
}
addon.data.quest["q85620_objective"] = {
m = "Přineste Jin'rokhovi Breakerovi primární hakkárský tabard. Zároveň musíš mít u kmene Zandalar pověst stejnou nebo vyšší než Uctívaný.\n\nJin'rokh Breaker se nachází na ostrově Yojamba ve Stranglethorn Vale.",
}
addon.data.quest["q85620_description"] = {
m = "Bojové vybavení vám dává sílu v kmeni. Volnomyšlenkáři jsou tímto způsobem poctěni. Jsou to horlivci. Své hrudní pláty napouštějí mocným mojo. Pokud jejich přesvědčení tváří v tvář nepříteli ochabne, jejich náprsní plát to neudělá.\n\nMusíš být mezi námi ctěn, abys takový náprsní štít vlastnil. Jdi do Zul'Gurubu. Vezmi si Paragony moci, které potřebuji. Vezmi Paragony nejbolestivěji od bláznů uvnitř. Přines mi je. Prokaž svou hodnotu volnomyšlenkáře jednou provždy.",
}
addon.data.quest["q85634_name"] = {
m = "Paragons of Power: Bláznova nárameníka",
}
addon.data.quest["q85634_objective"] = {
m = "Přineste Falthirovi Bezzrakému prvotní hakkárskou zbrojní sponu. Musíš mít také u kmene Zandalar pověst stejnou nebo vyšší než Přátelská.\n\nFalthir the Sightless se nachází na ostrově Yojamba, Stranglethorn Vale.",
}
addon.data.quest["q85634_description"] = {
m = "Šílenci ze Zandalaru jsou podobní lumpům, ale ze všeho nejvíc je jim blízké šílenství, chaos, nepředvídatelnost existence. Na bitevním poli nahánějí hrůzu, v divokých dobách po rozštěpení kmenů zasévali mezi naše nepřátele semínka zmatku a chaosu. Bez nich bychom tu dnes nebyli.\n\nPřiveď mi Paragony moci ze Zul'Gurubu, které hledám, a já ti poskytnu první z ceněných zbrojí šíleného člověka. Přijměte šílenství!",
}
addon.data.quest["q85634_progress"] = {
m = "Vyhledej šílenství z nitra Zul'Gurubu a zastíni ho svým vlastním, <name>! Udělat to znamená úspěch a úspěch znamená odměnu! Nedovolte, aby Krvavý bůh znovu zavládl!",
}
addon.data.quest["q85634_completion"] = {
m = "Výborně, <name>... tvé úspěchy v Zul'Gurubu ti vynesly právo nazývat kmen Zandalar přítelem. Postarám se o likvidaci Paragonů; za tvé úsilí přijmi prosím tuto odměnu!",
}
addon.data.quest["q85636_name"] = {
m = "Paragons of Power: The Madcap's Tunic (Šílená tunika)",
}
addon.data.quest["q85636_objective"] = {
m = "Přineste Falthirovi Bezzrakému primární hakkárskou egidu. Zároveň musíš mít u kmene Zandalar pověst stejnou nebo vyšší než Uctívaný.\n\nFalthir the Sightless se nachází na ostrově Yojamba, Stranglethorn Vale.",
}
addon.data.quest["q85636_description"] = {
m = "Moje oči mě už dávno zklamaly, ale nechybí mi. Dokonce i v kmeni, jako je ten náš - kde oděv vyjadřuje postavení a účel -, vyzařuje i ten nejsilnější oděv sílu, kterou prosté oči nevidí. Ceněná tunika zandalarských šílenců není výjimkou, vyzařuje syrovou sílu chaosu a šílenství, kterou jsou schopni ovládat.\n\nParagony moci, které potřebuji, leží v Zul'Gurubu; přines mi, co hledám, a já tě odměním tvou vlastní legendární tunikou... takovou, jaká se sluší na tkalce šílenství.",
}
addon.data.quest["q85636_progress"] = {
m = "Vítej zpět na Ostrově, <name>... vrátil ses vítězně s Paragony moci v závěsu?",
}
addon.data.quest["q85636_completion"] = {
m = "Působivé... dnes jste dokázali to, co si málokdo myslel, že je možné. Tvá úcta v kmeni je zajištěna na celý život, <name>. Zasloužil sis právo obléknout tuniku blázna - učiň tak s naším požehnáním.",
}
addon.data.quest["q85658_name"] = {
m = "Aby to všichni viděli",
}
addon.data.quest["q85658_objective"] = {
m = "Vyhledejte Overlorda Runthaka v Údolí síly.",
}
addon.data.quest["q85658_description"] = {
m = "Vládce Runthak očekává váš příchod do Údolí síly.\n\n<Thrall tě zdraví.>\n\nNenechávej své publikum čekat, hrdino.",
}
addon.data.quest["q85658_completion"] = {
m = "Vyberte si svou odměnu a začněte slavit své slavné vítězství.",
}
addon.data.quest["q85619_name"] = {
m = "Paragony moci: Pás volnomyšlenkářů",
}
addon.data.quest["q85619_objective"] = {
m = "Přineste Jin'rokhovi Zlomenému prvotní hakkari šál. Musíš mít také u kmene Zandalar pověst stejnou nebo vyšší než Čestný.\n\nJin'rokh Breaker se nachází na ostrově Yojamba ve Stranglethorn Vale.",
}
addon.data.quest["q85619_description"] = {
m = "Vaše víra je nám cizí, pohane. Starověcí Zandalarští byli kdysi označeni za kacíře. Bylo to v době, kdy byla Gurubašská říše silná. Pohané se odvážili vzdorovat Hakkarovu knězi. Pohané byli tehdy pronásledováni a zabíjeni jako škůdci. Tito pohané nikdy nezaváhali ve svém boji proti Krvavému bohu. Ctíme cenu, kterou zaplatili. Jsou to volnomyšlenkáři.\n\nZničte Hakkarovy přisluhovače v Zul'Gurubu. Přiveďte mi Paragony moci, které hledám. Úspěch bude skvěle odměněn.\n\nJdi.",
}
addon.data.quest["q85619_progress"] = {
m = "Vaše přítomnost znamená vítězství? Máte Paragony? Kapou z tebe zbytky nepřátel?",
}
addon.data.quest["q85619_completion"] = {
m = "Vaše čest je v kmeni zajištěna. Tvrdíš, že v Zul'Gurubu zemřelo mnoho lidí. Nepřátelé padají před tvým přesvědčením. Nepřátelé padají před tvou mocí.\n\nTo je pás volnomyšlenkáře. Je to symbol cti. Je to mocné kouzlo. Nyní je tvůj.",
}
addon.data.quest["q85617_name"] = {
m = "Značka hrdiny",
}
addon.data.quest["q85617_progress"] = {
m = "Král uznal tvou existenci, <cM3>. Jsi první svého druhu, kterého Rastakhan přijal jako skutečného spojence Zandalaru.\n\nZa své úsilí budeš velmi odměněn. Představ svou značku a já použiji poslední zesílení.",
f = "Král uznal tvou existenci, <cF4>. Jsi první svého druhu, kterého Rastakhan přijal jako skutečného spojence Zandalaru.\n\nZa své úsilí budeš velmi odměněna. Představte svou značku a já použiji poslední zesílení.",
}
addon.data.quest["q85617_completion"] = {
m = "Ostražitost, čest, věrnost, statečnost... Všechny tyto vlastnosti ztělesňujete a stejně tak i vaše značka.",
}
addon.data.quest["q85607_name"] = {
m = "Paragony moci: Augurův hábit",
}
addon.data.quest["q85607_objective"] = {
m = "Přineste Maywiki ze Zuldazaru primární hakkárský tabard. Musíš mít také u kmene Zandalar pověst stejnou nebo vyšší než Uctívaný.\n\nMaywiki ze Zuldazaru se nachází na ostrově Yojamba ve Stranglethorn Vale.",
}
addon.data.quest["q85607_description"] = {
m = "Všichni zandalarští věrozvěsti nosí charakteristickou náprsní část zvanou hauberk. Je opatřena nejjemnějším hedvábím a látkami, protkanými silnými řetězy. Je to symbol nejen jejich božství, ale také jejich autority, mon. Nikdy není moudré zkřížit cestu někomu, jehož život je zasvěcen rozhovoru s duchy...\n\nPřines mi nabídku Paragonů moci z nitra Zul'Gurubu a dokaž nám svou cenu. Udělej to a já ti dám jeden z nejlepších hauberků, jaké by naši augurští kdy mohli nosit!",
}
addon.data.quest["q85628_name"] = {
m = "Paragoni moci: Démonické roucho",
}
addon.data.quest["q85628_objective"] = {
m = "Přineste Al'tabimu Vševidoucímu prvotní hakkárský kossack. Zároveň musíš mít u kmene Zandalar pověst stejnou nebo vyšší než Uctívaný.\n\nVševidoucí Al'tabim se nachází na ostrově Yojamba ve Stranglethorn Vale.",
}
addon.data.quest["q85628_description"] = {
m = "Nejvyšším symbolem moci v kmeni je oděv, který nosíme v boji. V démonickém rouchu se spojila jemná runová tkanina a ničivě mocné mojo do jediné látky. Říká se, že vizáž roucha vzbuzuje strach v myslích všech, kdo ho spatří... zejména démonů, které démonik nakonec ovládne.\n\nZe Zul'Gurubu mi musíš přinést velmi specifickou sadu Paragonů moci. Bude to obtížné... ale tvůj úspěch ti zajistí, že získáš roucho pro sebe.",
}
addon.data.quest["q85628_progress"] = {
m = "Paragoni moci... vrátili jste se s nimi? Teprve až je budeme mít, podělíme se s tebou o nejvyšší symbol démonické moci, <name>.",
}
addon.data.quest["q85628_completion"] = {
m = "Působivé - vaše vítězství v Zul'Gurubu nás - ne, celý svět - ujistilo, že Hakkar nezvítězí. Možná přijde čas, kdy se s Bohem krve utkáš přímo... a pokud se tak stane, věz, že tvá úcta v kmeni Zandalarů je zajištěna.\n\nJo, a tohle prosté roucho by ti taky mělo pomoct, myslím.\n\n<Al'tabim na tebe vědoucně mrkne.>",
}
addon.data.quest["q85605_name"] = {
m = "Paragoni moci: Augurova nárameníka",
}
addon.data.quest["q85605_objective"] = {
m = "Přineste Maywiki ze Zuldazaru Primal Hakkari Armsplint. Musíš mít také pověst stejnou nebo vyšší než Přátelská u kmene Zandalar.\n\nMaywiki ze Zuldazaru se nachází na ostrově Yojamba, Stranglethorn Vale.",
}
addon.data.quest["q85605_description"] = {
m = "Věštci našeho kmene jsou uctíváni pro svůj dar božského zraku, ya mon. Nejsou to čarodějové; tráví svůj čas odléváním kostí nebo čtením listů, aby získali vhled - ne zaříkáváním lidí. Jako šaman už něco víš o síle věštby; my Zandalar si ceníme vhledu, který kmeni dávají.\n\nPřines mi nabídku Paragonů moci zevnitř Zul'Gurubu a dokaž nám svou cenu. Udělej to pro nás a já ti dám nárameníky, které si naši auguré cení nade všechny ostatní!",
}
addon.data.quest["q85605_progress"] = {
m = "Máš Paragony moci ze Zul'Gurubu, které potřebuji? Tyhle náramky stojí za jakoukoli námahu, kterou budeš muset vynaložit!",
}
addon.data.quest["q85605_completion"] = {
m = "Zdá se, že máš v sobě trochu zandalarského augura. Víme o činech, které jsi v Zul'Gurubu dělal pro nás, mon. Tihle Paragoni moci budou mít velký význam pro pomoc zandalarskému kmeni - kmeni, který můžeš považovat za své přátele. Vezmi si tyhle náramky, <name>; zasloužíš si je a ještě něco navíc!",
}
addon.data.quest["q85627_name"] = {
m = "Paragons of Power: The Demoniac's Mantle (Plášť démona)",
}
addon.data.quest["q85627_objective"] = {
m = "Přineste Al'tabimu Vševidoucímu prvotní hakkari šerpu. Zároveň musíš mít u kmene Zandalar pověst stejnou nebo vyšší než Čestný.\n\nVševidoucí Al'tabim se nachází na ostrově Yojamba ve Stranglethorn Vale.",
}
addon.data.quest["q85627_description"] = {
m = "Démon se snaží přímo ztělesnit moc, ne ji jen vlastnit. Nejeden z našich démonů prohrál boj s démonem; v době, kdy nás ohrožují naši nepřátelé - zejména v Zul'Gurubu - stojí síla, kterou je démon schopen na naše nepřátele vypustit, za tu oběť. Naše přežití závisí na rozdrcení těch, kteří by nás chtěli zničit; pád Gurubašské říše nás to naučil.\n\nVydej se do Zul'Gurubu a získej Paragony moci, které potřebujeme. Udělej to a cenný démonický předmět bude tvůj.",
}
addon.data.quest["q85627_progress"] = {
m = "Získal Paragony moci ze Zul'Gurubu? Zatímco my si vezmeme latentní moc z těchto předmětů a uděláme z nich své vlastní, vám dáme vaši vlastní odměnu moci, pokud budete úspěšní...",
}
addon.data.quest["q85627_completion"] = {
m = "Dobrá práce, <name>. Paragony moci ze Zul'Gurubu by měly sloužit jako připomínka promarněné moci. Gurubaši byli na svém vrcholu silní, ale nechali se jí pohltit. Démoni vědí, že hra, kterou hrají, je hodně podobná, ale uvolněná síla je často právě tím, co potřebují k přežití.\n\nPoužij tento plášť jako čestný spojenec Zandalaru... dobře ti poslouží.",
}
addon.data.quest["q85614_name"] = {
m = "Paragony moci: Pás mstitele",
}
addon.data.quest["q85614_objective"] = {
m = "Přineste Jin'rokhovi Zlomiteli primární hakkariovský pás. Zároveň musíš mít u kmene Zandalar reputaci stejnou nebo vyšší než Čestný.\n\nJin'rokh Breaker se nachází na ostrově Yojamba ve Stranglethorn Vale.",
}
addon.data.quest["q85614_description"] = {
m = "V Zul'Gurubu čeká konečná pomsta. Hakkar nesmí znovu povstat. Hakkar zničil Gurubašskou říši zevnitř. Žádná oběť nestačila. Trollové jsou jen stínem bývalé slávy. Vím, že je to kvůli Hakkarovi.\n\nStaň se mstitelem, kterým jsi měl být. Způsobte zkázu přisluhovačům zla. Zul'Gurub musí okusit zandalarskou pomstu. Přines mi důkaz v Paragonech moci. Obdržíš pás mstitele. Získáš skutečnou moc.\n\nJdi.",
}
addon.data.quest["q85614_progress"] = {
m = "Přinesl jsi Paragony moci? Zničili jste nepřátele kmene? Hakkar musí poznat hněv mstitele!",
}
addon.data.quest["q85614_completion"] = {
m = "Cesta mstitele je ti nyní známa. Přinesl jsi kmeni čest. Přinesl jsi čest sám sobě. Přinesl jsi bolest našim nepřátelům.\n\nPás mstitele je tvůj. Jistě se sjednocuješ s cestou mstitele.",
}
addon.data.quest["q85618_name"] = {
m = "Paragoni moci: Svobodomyslní zbrojnoši",
}
addon.data.quest["q85618_objective"] = {
m = "Přineste si Jin'rokh the Breaker Primal Hakkari Bindings. Musíš mít také pověst stejnou nebo vyšší než Přátelská u kmene Zandalar.\n\nJin'rokh Breaker se nachází na ostrově Yojamba, Stranglethorn Vale.",
}
addon.data.quest["q85618_description"] = {
m = "Jsi pohan. Pohané mají v kmeni své místo. Pohané jsou volnomyšlenkáři Zandalaru. Svobodomyslní se nebojí útlaku. Svobodomyslní umírají za to, v co věří. Víme, že bys zemřel za to, v co věříš. To si zaslouží naše uznání. Tím si zasloužíš šanci se dále osvědčit.\n\nMusíme mít Vzory moci. Jdi do Zul'Gurubu. Zabij Hakkarovy přisluhovače. Vrať se, až budeš mít, co hledám. Vyzvedni si první bojovou výbavu zandalarského volnomyšlenkáře.\n\nJdi.",
}
addon.data.quest["q85618_progress"] = {
m = "Vrátili jste se? Máte Paragony moci? Ztrácíte můj čas?\n\nDoufám, že ne, pohane.",
}
addon.data.quest["q85618_completion"] = {
m = "Děláte toho pro nás hodně. Z tvých rukou kape krev Hakkarových přisluhovačů. Jsi přítelem kmene.\n\nNos tyto náramky. Jsou to zbroje volnomyšlenkářů. Tohle je to, co myslím skutečnou mocí.",
}
addon.data.quest["q85638_name"] = {
m = "Paragons of Power: Predátorova nárameníka",
}
addon.data.quest["q85638_objective"] = {
m = "Přiveď následující Paragony moci ze Zul'Gurubu k Falthirovi Bezzrakému: A Primal Hakkari Bindings. Dále musíš mít u kmene Zandalar pověst stejnou nebo vyšší než Přátelská.\n\nFalthir the Sightless se nachází na ostrově Yojamba, Stranglethorn Vale.",
}
addon.data.quest["q85638_description"] = {
m = "V temných dobách po pádu Gurubašské říše využívali zandalarští dravci svou zdatnost k obživě kmene. Lovci tvrdí, že jsou podobní predátorům našeho kmene - usilovat o lov znamená ztělesňovat podstatu predátora, ano. Tvůj lov v Zul'Gurubu nám však ukáže, jak se skutečně řadíš mezi naše nejlepší dravce.\n\nPřines mi vzorek Vzorů moci ze Zul'Gurubu. Udělej to a uděláš první kroky k tomu, aby ses stal předposledním dravcem.",
}
addon.data.quest["q85638_progress"] = {
m = "Ulovte v Zul'Gurubu ty, kteří by chtěli vlastnit Paragony moci, <name>. Jsou tvou kořistí; vlastní to, co musíme mít oba.",
}
addon.data.quest["q85638_completion"] = {
m = "Ano... Nepotřebuji žádnou vizi, abych cítil přítomnost Paragonů moci. Tvůj úspěch v Zul'Gurubu zapůsobil na mnoho lidí z kmene. Nejenže tě považujeme za přítele Zandalaru, ale také tě považujeme za natolik hodného, abys vlastnil dravčí nárameníky - mocné předměty a symbol toho, co znamená být dravcem. Výborně, <name>.",
}
addon.data.quest["q85606_name"] = {
m = "Paragony moci: Augurův pás",
}
addon.data.quest["q85606_objective"] = {
m = "Přineste Maywiki ze Zuldazaru primární hakkari pás. Musíš mít také u kmene Zandalar pověst stejnou nebo vyšší než Čestný.\n\nMaywiki ze Zuldazaru se nachází na ostrově Yojamba ve Stranglethorn Vale.",
}
addon.data.quest["q85606_description"] = {
m = "Auguři znají kouzlo živlů, mon. Používají je jako prostředek k vedení kmene ke slávě. V temných dnech poté, co se Gurubašská říše rozpadla, nás naši auguri vedli do bezpečného útočiště v jižních mořích. Také nás dovedli zpět sem do Údolí, přímo do srdce zla, které se vaří v Zul'Gurubu.\n\nPřines mi nabídku Paragonů moci zevnitř Zul'Gurubu a dokaž nám svou cenu. Udělej to a já ti dám opasek, který používají naši věštci - opasek s mocným mojo uvnitř!",
}
addon.data.quest["q85622_name"] = {
m = "Paragony moci: Zpovědníkova roucha",
}
addon.data.quest["q85622_objective"] = {
m = "Přineste Al'tabimu Vševidoucímu prvotní hakkárskou palici. Zároveň musíš mít u kmene Zandalar pověst stejnou nebo vyšší než Přátelská.\n\nVševidoucí Al'tabim se nachází na ostrově Yojamba v údolí Stranglethorn.",
}
addon.data.quest["q85622_description"] = {
m = "My, Zandalar, vkládáme moc do těch, kteří mluví s autoritou božství. Naši kněží jsou víc než jen léčitelé - jsou to naši zpovědníci. Zlo přichází jak z vnějších hrozeb - jako je Hakkar -, tak z nitra kmene. Naši zpovědníci působí jako soudci mezi námi a chrání nás před stejným zlem, které pohltilo Gurubaši zevnitř.\n\nVydej se do Zul'Gurubu a přiveď z Gurubaši Paragony moci. Nauč se, co znamená být zpovědníkem, a ochraňuj nás před zlem.",
}
addon.data.quest["q85622_progress"] = {
m = "Vrátil ses ze Zul'Gurubu? Podařilo se ti získat Paragony moci od Hakkarových přisluhovačů?",
}
addon.data.quest["q85622_completion"] = {
m = "Vynikající, <name>! Nebyl to malý výkon, když jste mi je přinesli. Bezpochyby jsi dnes působil jako zpovědník našeho kmene, který nás chrání před Hakkarovou hrozbou. Tyto zábaly se sluší na přítele kmene, jako jsi ty!",
}
addon.data.quest["q85706_name"] = {
m = "Kmenové zpracování kůže",
}
addon.data.quest["q85706_objective"] = {
m = "Přineste si do Se'Jib ve Stranglethorn Vale divokou koženou vestu a divokou koženou přilbu.\n\nSplněním tohoto úkolu získáte přístup ke kmenovému umění zpracování kůže.\n\nSplnění tohoto úkolu ti zabrání naučit se Zpracování kůže z dračích šupin a Zpracování kůže z živlů; než tak učiníš, ujisti se, že je to cesta, kterou se chceš vydat.",
}
addon.data.quest["q85706_description"] = {
m = "Naučit se zpracovávat kmenové kůže vyžaduje pochopení toho, jak je příroda skutečně prapůvodní; vím, že jsi již zvládl umění výroby divoké kožené zbroje, a jsem ochoten tvůj výcvik dokončit.\n\nVěz, <cM3>, že volbou této cesty souhlasíš s tím, že se nikdy nebudeš učit zpracování kůže z dračích šupin nebo živlů; je zde prostor pouze pro nácvik jednoho z těchto tří umění. Kromě toho mi přines nejlepší vzorky své divoké kožené zbroje. Odtud začneme tvé mistrovství.",
f = "Naučit se zpracovávat kmenové kůže vyžaduje pochopení toho, jak je příroda skutečně prapůvodní; vím, že jsi již zvládl umění výroby divoké kožené zbroje, a jsem ochoten tvůj výcvik dokončit.\n\nVěz, <cF4>, že volbou této cesty souhlasíš s tím, že se nikdy nebudeš učit zpracování kůže z dračích šupin ani z kůže živlů; je zde prostor pouze pro nácvik jednoho z těchto tří umění. Dále mi přines nejlepší vzorky své divoké kožené zbroje. Odtud začneme tvé mistrovství.",
}
addon.data.quest["q85706_progress"] = {
m = "Příroda je síla, kterou je třeba uklidnit, než se naučíte, jak její vůli přetvořit na kožené oděvy. Přines mi svou oběť této síle a já se postarám, abys byl vyslyšen.",
}
addon.data.quest["q85706_completion"] = {
m = "Dali jste své nejlepší oběti a příroda vám brzy dovolí, abyste ji přizpůsobili své vůli. Jakmile ukončím svou výuku, vaše dílo bude samo o sobě silou přírody.\n\nChcete-li se v umění vycvičit do budoucna, jednoduše se mnou promluvte a já vám zpřístupním všechny znalosti, které jste ještě nesvěřili jako své.",
}
addon.data.quest["q86679_name"] = {
m = "Zahaleni v noční můře",
}
addon.data.quest["q86679_objective"] = {
m = "Najděte někoho, kdo je schopen rozluštit význam předmětu pohlceného noční můrou.\n\nMožná by ti mohl pomoci druid s velkou mocí.",
}
addon.data.quest["q86679_description"] = {
m = "Z tohoto objektu prosakuje korupce.\n\nMezi tímto předmětem a draky vycházejícími ze Snu může být souvislost. Musíš najít někoho, kdo dokáže rozluštit význam tohoto předmětu. Možná by ti mohli dále pomoci druidové z Měsíční pláně nebo Cenarion Hold.",
}
addon.data.quest["q86673_name"] = {
m = "Pád Ossirianu",
}
addon.data.quest["q86673_objective"] = {
m = "Předej hlavu Ossiriana Neohroženého veliteli Mar'alithovi v Cenarion Hold v Silithu.",
}
addon.data.quest["q86673_description"] = {
m = "Strašlivá hrozba byla uložena k věčnému odpočinku. Krutý Ossirian byl poražen.\n\nObyvatelé Kalimdoru by si oddechli, kdyby se dozvěděli o tomto vítězství. Vezmi Ossirianovu hlavu a předej ji veliteli Mar'alithovi z Cenarion Hold.",
}
addon.data.quest["q86445_name"] = {
m = "Neptulonův hněv",
}
addon.data.quest["q86445_objective"] = {
m = "Použijte arkanitovou bójku ve víru Maelstromu v Zátoce bouří v Azšaře.",
}
addon.data.quest["q86445_description"] = {
m = "Už jsem se zmínil o špatných zprávách? Jmenuje se Maws: 100 stop smrti a zkázy. Na tuhle drobnost jsem asi zapomněl.\n\nPodle mé vynikající psycho-psionické jasnozřivosti zjistíte, že nejlepší místo, kam tuto bójku hodit, je u pobřeží Azshary, v Zátoce bouří.\n\nHledej vířící vír, nejspíš zahlcený troskami.\n\nMimochodem, doufám, že máš přátele.\n\nPokud se ti to nějakým zázrakem podaří, odnes úlomek žezla Anachronosovi.",
}
addon.data.quest["q86445_progress"] = {
m = "Čas běží, šampione.",
}
addon.data.quest["q86445_completion"] = {
m = "Dobrá práce, <name>. Brzy budu moci reformovat žezlo Pohyblivých písků.",
}
addon.data.quest["q86443_name"] = {
m = "Noční můra se projevuje",
}
addon.data.quest["q86443_objective"] = {
m = "Braňte Nighthaven před Eranikem. Nedovolte, aby strážce Remulos zahynul. Nezabíjejte Eranikuse. Braňte se sami. Čekejte na Tyrande.",
}
addon.data.quest["q86443_description"] = {
m = "Proti Eranikovi musíme být zdrženliví. Máme ho vykoupit, ne zničit.\n\nTyrande je již na cestě, aby nám v tomto úkolu pomohla. Musíme přečkat dračí údery a zachránit Nighthaven před jistou zkázou.\n\nBuďte na stráži! Ty a tvoji spojenci jste naší jedinou nadějí.",
}
addon.data.quest["q86443_completion"] = {
m = "Je vykoupen, <name>. Nyní se vrací do Snu, aby napravil to, co sám pokazil. Eranikus bude mocným spojencem Malfuriona a mého otce.\n\nTato výzbroj je pro tebe, <name>; dala mi ji sama Ysera. Uděláš dobře, když je využiješ ve svých bojích proti Qiraji.",
}
addon.data.quest["q86444_name"] = {
m = "Jediný recept",
}
addon.data.quest["q86444_objective"] = {
m = "Získejte zpět 8 ztracených kapitol Draconica pro blbce, spojte je s Magickou knižní vazbou a vraťte dokončenou knihu Draconica pro blbce: Díl II odevzdejte Narainu Soothfancymu v Tanarisu.",
}
addon.data.quest["q86444_description"] = {
m = "Měl jsem to vědět. Můj úhlavní nepřítel, doktor Weavil, se vrátil ke svým starým trikům! A teď, díky tvému selhání ve Winterspringu, Doktor Weavil zničil mou knihu! Jak chceš teď zachránit svět, hrdino?\n\nV dopise, který jsem obdržel, stálo, že jediný známý výtisk knihy 'Draconic for Dummies: II. díl' byl roztrhán na osm částí a rozptýlen do větru! Pokud se ti nějak podaří najít ty chybějící kapitoly, použij tuto kouzelnou vazbu, abys je dal dohromady a vrátil mi je.",
}
addon.data.quest["q86444_progress"] = {
m = "Kalhoty si oblékám stejně jako vy - po jedné nohavici. Až na to, že když mám kalhoty na sobě, dělám arkanitové bóje. Arkanitové bóje, zlato!",
}
addon.data.quest["q86444_completion"] = {
m = "Fantastické! Nemůžu uvěřit, že jste se s tím tak trápili! Jsi nějaký stroj? Na mém místě bych asi nechal svět vybuchnout.\n\nSkláním před vámi svůj turban, pane. A žádný dobrý skutek by neměl zůstat bez odměny.",
}

View file

@ -0,0 +1 @@
local _, addon = ...

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

3441
Addon/Data/classic_era/6.lua Normal file

File diff suppressed because it is too large Load diff

3401
Addon/Data/classic_era/7.lua Normal file

File diff suppressed because it is too large Load diff

3372
Addon/Data/classic_era/8.lua Normal file

File diff suppressed because it is too large Load diff

3370
Addon/Data/classic_era/9.lua Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

352
Addon/Data/retail/10.lua Normal file
View file

@ -0,0 +1,352 @@
local _, addon = ...
addon.data.speech["Cataloger Grilka_Show me your best dance moves!"] = {
m = "Ukažte mi své nejlepší taneční pohyby!",
}
addon.data.speech["Cataloger Grilka_Eyes on me! Now wave to your fans!"] = {
m = "Sledujte mě! A teď zamávej svým fanouškům!",
}
addon.data.speech["Cataloger Grilka_Wave to the camera! Wave to it, superstar!"] = {
m = "Zamávejte do kamery! Zamávej jí, superhvězdo!",
}
addon.data.speech["Cataloger Grilka_Let's see how you dance. Focus on me and dance up a storm!"] = {
m = "Podívejme se, jak tančíš. Soustřeďte se na mě a tančete jako bouře!",
}
addon.data.quest["q86703_name"] = {
m = "Pracujte na tom",
}
addon.data.quest["q86703_description"] = {
m = "Zkouška stylu nám dává příležitost vypadat dobře. <cM0>. Kamera se postará o to, abychom vypadali dobře i nadále. Takže se soustřeďte na mě a můj fotoaparát, dodržujte mé pokyny a já se postarám o to, abyste vypadali fantasticky!",
f = "Zkouška stylu nám dává příležitost vypadat dobře. <cF0>. Kamera se stará o to, abychom stále vypadali dobře. Takže se soustřeďte na mě a můj fotoaparát, dodržujte mé pokyny a já se postarám o to, abyste vypadali fantasticky!",
}
addon.data.quest["q86703_objective"] = {
m = "Soustřeďte se na fotografa a postupujte podle jeho pokynů.",
}
addon.data.quest["q86703_progress"] = {
m = "Soustřeďte se na mě a řiďte se mými pokyny.\n\nPostarám se, abys vypadala skvěle.",
}
addon.data.quest["q86703_completion"] = {
m = "Kamera nelže, <name>.\n\nJsi stylový <cM0>.",
f = "Kamera nelže, <name>.\n\nJsi jedna stylová <cF0>.",
}
addon.data.quest["q87417_progress"] = {
m = "Jak probíhá mise?",
}
addon.data.quest["q87417_completion"] = {
m = "Děkujeme, že jste všem lidem Khaz Algaru přinesli záblesk naděje.",
}
addon.data.quest["q87424_progress"] = {
m = "Viděl jsem, jak se ve vzdálené temnotě Hallowfallu pohybují příšery. Věci, které mě straší v nočních můrách.",
}
addon.data.quest["q89018_name"] = {
m = "Věrný zákazník: Silver",
}
addon.data.quest["q89018_completion"] = {
m = "Stoupáš ve světě! Zařídíme ti upgrade.",
}
addon.data.quest["q79561_progress"] = {
m = "Velký, s vidličkou v hlavě. Poznáte ho, až ho uvidíte.",
}
addon.data.quest["q84123_name"] = {
m = "Test",
}
addon.data.quest["q84123_description"] = {
m = "Test",
}
addon.data.quest["q84123_objective"] = {
m = "Test",
}
addon.data.quest["q85827_name"] = {
m = "Třpyt a lesk",
}
addon.data.quest["q85827_completion"] = {
m = "Děkujeme za pomoc při návratu Undermine na trať. Tady je něco za tvou námahu.",
}
addon.data.quest["q85945_progress"] = {
m = "Máme tu trh, který chceme ovládnout.",
}
addon.data.quest["q85805_completion"] = {
m = "Tady máte!",
}
addon.data.quest["q85914_progress"] = {
m = "Snažte se nezmrazit žádné důležité kousky. Nenabízíme lékařskou péči.",
}
addon.data.quest["q85819_name"] = {
m = "Zvětralé hřebeny",
}
addon.data.quest["q85819_completion"] = {
m = "Děkujeme, že jste pomohli vrátit Undermine na správnou cestu. Tady je něco za tvou námahu.",
}
addon.data.quest["q85553_progress"] = {
m = "Budeme potřebovat čas, abychom oddělili prášek od kraba, tak je sem rychle přivezte!",
}
addon.data.quest["q85553_completion"] = {
m = "Podívejte se na to! Dost masa na nasycení celé posádky a ještě něco navíc.\n\nJen musíme být opravdu opatrní, abychom z něj dostali všechen ten střelný prach. Nerad bych, aby někdo přišel o ruku, až ho bude chtít uvařit.",
}
addon.data.quest["q85824_name"] = {
m = "Valorstones",
}
addon.data.quest["q85824_completion"] = {
m = "Děkujeme, že jste pomohli vrátit Undermine na správnou cestu. Tady je něco za tvou námahu.",
}
addon.data.quest["q85825_name"] = {
m = "Vyřezávané erby",
}
addon.data.quest["q85825_completion"] = {
m = "Děkujeme, že jste pomohli vrátit Undermine na správnou cestu. Tady je něco za tvou námahu.",
}
addon.data.quest["q85823_name"] = {
m = "Vyřezávané erby",
}
addon.data.quest["q85823_completion"] = {
m = "Děkujeme, že jste pomohli vrátit Undermine na správnou cestu. Tady je něco za tvou námahu.",
}
addon.data.quest["q86535_progress"] = {
m = "Podívejte se na tento teleport. Není nádherná?",
}
addon.data.quest["q86203_progress"] = {
m = "Ukončil jsi operaci?",
f = "Ukončila jsi operaci?",
}
addon.data.quest["q86203_completion"] = {
m = "Rada jistě ráda uslyší, že Waterworks je opět v pozemských rukou.\n\nDobrá práce, cizinče.",
}
addon.data.speech["Lindormi_Your most dangerous Keystones are now resilient to failure."] = {
m = "Vaše nejnebezpečnější klíče jsou nyní odolné vůči selhání.",
}
addon.data.speech["Lindormi_When you require a more relaxing task, speak to me and I can grant you an easier Keystone anytime."] = {
m = "Když budete potřebovat více relaxační úkol, promluvte si se mnou a mohu vám poskytnout jednodušší Keystone kdykoli.",
}
addon.data.quest["q87327_progress"] = {
m = "Dosáhli jste mnoha úspěchů. Vaše činy jsou legendární.",
}
addon.data.quest["q87327_completion"] = {
m = "Protože ti Xal'atathovy náhlé, ale nevyhnutelné zrady nedělají problém, ujistím se, že ti odteď budu dávat jen opravdu odolné klíče.\n\nNevadí však, když mě požádáš o nějaký jednodušší. Každý si občas potřebuje odpočinout.",
}
addon.data.quest["q87284_completion"] = {
m = "< Když uvolníš Zářivou ozvěnu, zhmotní se ti před očima vize minulosti. Sama Světová duše se s tebou dělí o své vzpomínky.>",
}
addon.data.quest["q88880_completion"] = {
m = "Vedl sis dobře, kamaráde. Tohle je tvoje.",
}
addon.data.quest["q88871_completion"] = {
m = "Ahoj, tohle je pro tebe.",
}
addon.data.quest["q88875_completion"] = {
m = "Něco pro vás máme.",
}
addon.data.quest["q88874_completion"] = {
m = "Něco pro vás máme.",
}
addon.data.quest["q88877_completion"] = {
m = "Tady je váš podíl, vše nad rámec zákona.",
}
addon.data.speech["Orweyna_We put an end to the Black Blood weapons. It is enough for now."] = {
m = "Skoncovali jsme se zbraněmi Černé krve. Prozatím to stačí.",
}
addon.data.speech["Orweyna_When I follow my own visions, it will not be as narrowly as before."] = {
m = "Až se budu řídit vlastními vizemi, nebude to tak úzce jako dříve.",
}
addon.data.speech["Orweyna_Not just because of your vision, but because of theirs. My goddess needed me to see that."] = {
m = "Nejen kvůli vaší vizi, ale i kvůli jejich vizi. Moje bohyně potřebovala, abych to viděl.",
}
addon.data.speech["Orweyna_You say you don't know visions... yet you have a vision for your city's future. One you did not possess before returning home to help your people."] = {
m = "Říkáte, že neznáte vize... a přitom máte vizi budoucnosti svého města. Takovou, jakou jsi neměl, než ses vrátil domů, abys pomohl svému lidu.",
}
addon.data.speech["Orweyna_I cannot stay longer. My visions call me elsewhere."] = {
m = "Nemohu zůstat déle. Mé vize mě volají jinam.",
}
addon.data.speech["Nanny Talullah_<name> do the work, I don't break a nail... That's a win-win for me!"] = {
m = "<name> udělám práci, nezlomím ani hřebík... To je pro mě výhra!",
}
addon.data.speech["Nanny Talullah_Dollface, honeybunches. <name>'re my favorite driver. Don't tell the rest of 'em I said that."] = {
m = "Dollface, honeybunches. <name> jsi můj oblíbený řidič. Neříkejte ostatním, že jsem to řekl.",
}
addon.data.speech["Nanny Talullah_Good job, dollface. <name> made sure I got my cut of your tip, right?"] = {
m = "Dobrá práce, panenko. <name> se ujistil, že dostanu svůj podíl z tvého spropitného, že?",
}
addon.data.speech["Marty Zoomcart_<name>anwhile, I'll use my gob-given powers of vamping to stall for time."] = {
m = "<name> Mezitím využiji své schopnosti vampýra, kterou mi propůjčil gob, abych získal čas.",
}
addon.data.speech["Heaps Morale Booster_AND REMEMBER. IF YOU ATTACK THE GUARDS, THEY WILL BEAT YOU TO A PULP."] = {
m = "A PAMATUJTE. POKUD ZAÚTOČÍTE NA STRÁŽE, ZMLÁTÍ VÁS.",
}
addon.data.speech["Heaps Morale Booster_WHOEVER COLLECTS THE MOST CHITS BY THE END OF THE SHIFT WILL HAVE THEIR DEBTS FORGIVEN."] = {
m = "KDO DO KONCE SMĚNY NASBÍRÁ NEJVÍCE ŽETONŮ, TOMU BUDOU DLUHY ODPUŠTĚNY.",
}
addon.data.speech["Heaps Morale Booster_GOOD LUCK. HAVE FUN."] = {
m = "HODNĚ ŠTĚSTÍ. BAVTE SE.",
}
addon.data.speech["Heaps Morale Booster_THIS IS YOUR REMINDER TO MINE AS MANY CHITS FROM THESE ABANDONED SLOT MACHINES AS YOU CAN."] = {
m = "TÍMTO VÁM PŘIPOMÍNÁME, ABYSTE Z TĚCHTO OPUŠTĚNÝCH AUTOMATŮ VYTĚŽILI CO NEJVÍCE ŽETONŮ.",
}
addon.data.encounter["The Gobfather_normal_raid_a03b221c_00"] = {
m = "???||",
}
addon.data.encounter["The Gobfather_normal_raid_0dd77eb8_0000"] = {
m = "Bombfield|Important|Gobfather rozptýlí Primed Boomcrawlers, kteří se potulují <#1?> s. Šlápnutí na Primed Boomcrawlera způsobí jeho předčasnou detonaci a spustí Bomb Voyage.",
}
addon.data.encounter["The Gobfather_normal_raid_3df09614_000000"] = {
m = "Primed Boomcrawler||",
}
addon.data.encounter["The Gobfather_normal_raid_2dff6e6c_00000000"] = {
m = "Reinforced Plating||Zesílené opláštění snižuje poškození, které obdrží Primed Boomcrawlerovi, o <#1?>%.",
}
addon.data.encounter["The Gobfather_normal_raid_eeafee09_00000001"] = {
m = "Bomb Voyage||Primed Boomcrawler se odpálí, způsobí <#1?> Fire poškození a odhodí hráče v okruhu <#2?> yardů.",
}
addon.data.encounter["The Gobfather_normal_raid_a4190c2f_0001"] = {
m = "Death From Above||Gobfather vypustí ze svých raketometů příval raket, které způsobí <#1?> Fire poškození hráčům v okruhu <#2?> yardů od každého dopadu.",
}
addon.data.encounter["The Gobfather_normal_raid_b3ae61ca_0002"] = {
m = "Giga-Rocket Slam||Gobfather udeří obrovskou silou do země, způsobí všem hráčům <#1?> Fire poškození a odhodí je zpět.",
}
addon.data.encounter["The Gobfather_normal_raid_c5b3601a_0003"] = {
m = "Flaming Flames||Gobfather vypustí proud plamenů a způsobí hráčům v čelním kuželu <#1?> Fire poškození.",
}
addon.data.encounter["The Gobfather_normal_raid_09c97f46_0004"] = {
m = "Excessive Pollutants|Healer|Gobfather vypouští do vzduchu nebezpečné chemikálie, které způsobují <#1?> Nature poškození v intervalu <#2?> s.",
}
addon.data.encounter["The Gobfather_normal_raid_summary_instance"] = {
m = "Gobfather se nehodlá vzdát bez závěrečného boje, rozpráší Primed Boomcrawlers pomocí [Bombfield] a srazí hráče zpět pomocí [Giga-Rocket Slam]. Při energii <#1?> se vytasí se všemi prostředky a sesílá na hráče [Death From Above].",
}
addon.data.encounter["The Gobfather_normal_raid_summary_tank"] = {
m = "Primed Boomcrawlers explodují s [Bomb Voyage] po sešlápnutí. \nThe Gobfather způsobuje masivní poškození svými střelami [Death From Above]. \n[Flaming Flames] způsobují poškození hráčům před The Gobfatherem.",
}
addon.data.encounter["The Gobfather_normal_raid_summary_healer"] = {
m = "Boomcrawleři se základním nátěrem po sešlápnutí explodují pomocí [Bomb Voyage]. \n[Excessive Pollutants] neustále způsobuje poškození všem hráčům. \nGobfather způsobuje obrovské poškození svými střelami [Death From Above].",
}
addon.data.encounter["The Gobfather_normal_raid_summary_dps"] = {
m = "Primed Boomcrawlers explodují s [Bomb Voyage] po sešlápnutí. \nThe Gobfather způsobuje masivní poškození svými střelami [Death From Above]. \n[Flaming Flames] způsobují poškození hráčům před The Gobfatherem.",
}
addon.data.encounter["Shurrai_normal_raid_a03b221c_00"] = {
m = "???||",
}
addon.data.encounter["Shurrai_normal_raid_a3276252_0000"] = {
m = "Abyssal Strike|Tank|Shurrai udeří svůj aktuální cíl nekromanticky napuštěnou kotvou, způsobí <#1?> Plague poškození a použije absorpci léčení rovnající se výši nezměrného poškození.",
}
addon.data.encounter["Shurrai_normal_raid_16361c5b_0001"] = {
m = "Briny Vomit||Shurrai chrlí solanku a způsobuje <#1?> Frost poškození hráčům v okruhu <#2?> yardů od každého dopadu. Kaluže solanky přetrvávají a způsobují hráčům <#3?> Frost poškození v intervalu <#4?> s a zpomalují rychlost pohybu o <#5?> %.",
}
addon.data.encounter["Shurrai_normal_raid_2a89e69f_0002"] = {
m = "Dark Tide||Shurrai vyvolává <#1?> vlny, které se šíří směrem ven, způsobují <#2?> Frost poškození a odstrkují hráče. Tyto vlny rozpouštějí všechny kaluže Briny Vomit, kterými projdou.",
}
addon.data.encounter["Shurrai_normal_raid_44f7529e_0003"] = {
m = "Regurgitate Souls|Important|Shurrai regurgituje duše svých minulých obětí v intervalu <#1?> s po dobu <#2?> s, čímž způsobuje <#3?> Plague poškození všem hráčům a vyvrhuje masu zajatých duší, která způsobuje <#4?> Plague poškození hráčům v okruhu <#5?> yardů od dopadu. Každý dopad vyvolá <#6?> Drowned Arathi.",
}
addon.data.encounter["Shurrai_normal_raid_69996e5a_000300"] = {
m = "Shroud of the Drowned||Shurrai se zahalí do nekromantických energií a během Regurgitate Souls absorbuje <#1?> poškození po dobu <#2?> min v intervalu <#3?> s.",
}
addon.data.encounter["Shurrai_normal_raid_ad190ebe_000301"] = {
m = "Drowned Arathi||",
}
addon.data.encounter["Shurrai_normal_raid_12617f60_00030100"] = {
m = "Ocean's Reckoning|Disease|Po smrti způsobí zaklínač hráčům v okruhu <#2?> yardů <#1?> Plague poškození a další <#3?> Plague poškození v intervalu <#4?> s po dobu <#5?> s. Tento efekt se sčítá. Vypuštěné duše se také vrhnou zpět na svého věznitele a způsobí Shurraiovi <#6?> Plague poškození.",
}
addon.data.encounter["Shurrai_normal_raid_summary_instance"] = {
m = "Shurrai zasype hráče [Briny Vomit] a poté smyje hráče i zvratky pomocí [Dark Tide]. Při <#1?> energii Shurrai vrhne [Regurgitate Souls], vyvolá Drowned Arathi a zaštítí se [Shroud of the Drowned].",
}
addon.data.encounter["Shurrai_normal_raid_summary_tank"] = {
m = "[Abyssal Strike] aplikuje léčebnou absorpci odpovídající výši způsobeného poškození. \n[Dark Tide] odplaví kaluže [Briny Vomit]. \nDrowned Arathi udělují Shurraiovi při zabití značné poškození.",
}
addon.data.encounter["Shurrai_normal_raid_summary_healer"] = {
m = "Drowned Arathi způsobí po smrti [Ocean's Reckoning]. \n[Dark Tide] odplaví kaluže [Briny Vomit]. \nDrowned Arathi způsobí Shurraiovi po zabití značné poškození.",
}
addon.data.encounter["Shurrai_normal_raid_summary_dps"] = {
m = "[Dark Tide] odplaví kaluže [Briny Vomit]. \nDrowned Arathi způsobí Shurraiovi při zabití značné poškození.",
}
addon.data.encounter["Aggregation of Horrors_normal_raid_a03b221c_00"] = {
m = "???||",
}
addon.data.encounter["Aggregation of Horrors_normal_raid_29d445eb_0000"] = {
m = "Crystalline Barrage|Important|The Aggregation of Horrors vypouští ze svého těla zubaté střepy, které způsobují <#1?> Shadow poškození hráčům v okruhu <#2?> yardů od dopadu střepu.",
}
addon.data.encounter["Aggregation of Horrors_normal_raid_23974a30_0001"] = {
m = "Dark Awakening|DPS|The Aggregation of Horrors rozbije zem, způsobí <#1?> Shadow poškození všem hráčům v okruhu <#2?> yardů a přemění okolní střepy na Fractured Skardyn.",
}
addon.data.encounter["Aggregation of Horrors_normal_raid_a1059bb2_000100"] = {
m = "Fractured Skardyn||Skardyn se oddělil od těla Aggregation of Horrors.",
}
addon.data.encounter["Aggregation of Horrors_normal_raid_3466ff61_0002"] = {
m = "Voidquake|Healer|",
}
addon.data.encounter["Aggregation of Horrors_normal_raid_e7ede113_0003"] = {
m = "Crystal Strike|Tank|The Aggregation of Horrors udeří do svého aktuálního cíle a způsobí mu <#1?> Shadow poškození a další <#2?> Shadow poškození v intervalu <#3?> s po dobu <#4?> s.",
}
addon.data.encounter["Aggregation of Horrors_normal_raid_07bff7dc_0004"] = {
m = "Annihilation Barrage||The Aggregation of Horrors způsobí <#1?> Shadow poškození svému aktuálnímu cíli, pokud hráč není v dosahu boje zblízka.",
}
addon.data.encounter["Aggregation of Horrors_normal_raid_summary_instance"] = {
m = "The Aggregation of Horrors vyhazuje během [Crystalline Barrage] úlomky skály. Tyto úlomky vznikají z Fractured Skardyn během [Dark Awakening].",
}
addon.data.encounter["Aggregation of Horrors_normal_raid_summary_tank"] = {
m = "[Crystal Strike] uděluje těžké Shadow poškození při dopadu a v průběhu času. \n[Voidquake] uděluje Shadow poškození hráčům uvězněným ve vzdálenosti <#1?> yardů.",
}
addon.data.encounter["Aggregation of Horrors_normal_raid_summary_healer"] = {
m = "[Voidquake] uděluje Shadow poškození hráčům, kteří se nacházejí ve vzdálenosti <#1?> yardů. \n[Crystalline Barrage] uděluje velké množství poškození hráčům zasaženým střepinami.",
}
addon.data.encounter["Aggregation of Horrors_normal_raid_summary_dps"] = {
m = "[Voidquake] způsobuje Shadow poškození hráčům, kteří se nacházejí v okruhu <#1?> yardů. \nAggregation of Horrors vrhá [Annihilation Barrage], když se žádný z hráčů nenachází v boji zblízka. \nFunkce [Dark Awakening] vytváří Fractured Skardyn, kteří útočí na blízké hráče.",
}
addon.data.encounter["Kordac_normal_raid_a03b221c_00"] = {
m = "???||",
}
addon.data.encounter["Kordac_normal_raid_de3f3afb_0000"] = {
m = "Arcane Bombardment||Po dosažení <#1?> energie Kordac zasype oblast nesčetnými Arcane missiles, které způsobí <#2?> Arcane poškození všem hráčům v okruhu <#3?> yardů od dopadu.",
}
addon.data.encounter["Kordac_normal_raid_964943db_0001"] = {
m = "Overcharged Lasers||Kordak vystřelí lasery, které sledují několik hráčů po dobu <#1?> s, způsobují <#2?> Arcane poškození v intervalu <#3?> s a srážejí zpět hráče, kteří byli paprsky opáleni. Lasery za sebou zanechávají Overcharged Earth a Empowering Coalescence.",
}
addon.data.encounter["Kordac_normal_raid_682eceff_000100"] = {
m = "Overcharged Earth||Ničivá síla přetrvává v zemi a v intervalu <#2?> způsobí poškození Arcane <#1?>.",
}
addon.data.encounter["Kordac_normal_raid_5b63e678_000101"] = {
m = "Empowering Coalescence||Přebytečná Arcane power se spojí do polostabilních forem, které po shromáždění poskytují <#1?>% zvýšené poškození po dobu <#2?> s. Tento efekt se střádá.",
}
addon.data.encounter["Kordac_normal_raid_8b324485_0002"] = {
m = "Titanic Impact||Kordac před sebou rozbije zem pěstmi napuštěnými Arcane a způsobí <#1?> fyzické a <#2?> Arcane poškození. Hráči, kteří se ocitnou pod nárazem, jsou vystřeleni do vzduchu.",
}
addon.data.encounter["Kordac_normal_raid_297bd7aa_0003"] = {
m = "Supression Burst||Kordac napustí několik cílů supresivní magickou energií. Po <#1?> s energie exploduje a na <#3?> s umlčí a zklidní cíle a všechny hráče v okruhu <#2?> yardů.",
}
addon.data.encounter["Kordac_normal_raid_summary_instance"] = {
m = "Kordac brání Azeroth a zaměřuje se na hráče pomocí [Overcharged Lasers], které za sebou zanechávají [Overcharged Earth] a [Empowering Coalescence]. Po dosažení <#1?> Energy na něj sesype [Arcane Bombardment].",
}
addon.data.encounter["Kordac_normal_raid_summary_tank"] = {
m = "Kordacův [Titanic Impact] uděluje vysoké poškození a vystřeluje hráče do vzduchu. \n[Supression Burst] pacifikuje a umlčuje blízké hráče při detonaci.",
}
addon.data.encounter["Kordac_normal_raid_summary_healer"] = {
m = "[Overcharged Lasers] budou pronásledovat hráče a zanechají za sebou [Overcharged Earth]. \n[Supression Burst] po výbuchu zklidní a umlčí všechny hráče v blízkosti cíle.",
}
addon.data.encounter["Kordac_normal_raid_summary_dps"] = {
m = "[Empowering Coalescence] lze sbírat pro krátké zvýšení udělování poškození. \n[Overcharged Lasers] budou pronásledovat hráče a zanechají za sebou [Overcharged Earth].",
}
addon.data.encounter["Orta_normal_raid_a03b221c_00"] = {
m = "???||",
}
addon.data.encounter["Orta_normal_raid_b2cd00e6_0000"] = {
m = "Tectonic Roar|Important|Orta spustí silný řev, který způsobí <#1?> Sonic poškození všem hráčům a srazí je zpět. Řev způsobuje další <#2?> Sonic poškození v intervalu <#3?> s po dobu <#4?> s.",
}
addon.data.encounter["Orta_normal_raid_0156f9b0_0001"] = {
m = "Colossal Slam||Orta udeří do země, čímž způsobí hráčům v čelním kuželu <#1?> Nature poškození a vymrští je vysoko do vzduchu.",
}
addon.data.encounter["Orta_normal_raid_7bb400a9_0002"] = {
m = "Rupturing Runes|Healer,Magic|Orta vyvolává runu devastace v intervalu <#1?> s po dobu <#2?> s. Po spuštění runy omráčí hráče, který ji spustil, a navíc způsobí <#3?> Fire poškození každou <#4?> s po dobu <#5?> s.",
}
addon.data.encounter["Orta_normal_raid_28eff812_0003"] = {
m = "Mountain's Grasp|Important|Orta chytá blízké hráče, drtí je ve svém sevření a uděluje <#1?> Physical poškození. Jeho sevření umlčuje hráče a uděluje <#2?> Physical poškození v intervalu <#3?> s.",
}
addon.data.encounter["Orta_normal_raid_f9c15f37_000300"] = {
m = "Discard Weaklings||Orta odhazuje slabochy, které má v dosahu, od sebe vší silou.",
}
addon.data.encounter["Orta_normal_raid_summary_instance"] = {
m = "Orta zachrastí proti okovům své infekce, roztříští zem pomocí [Colossal Slam] a vyvolá [Rupturing Runes]. Při <#1?> energii Orta vyvolá [Tectonic Roar] a svým řevem srazí všechny hráče.",
}
addon.data.encounter["Orta_normal_raid_summary_tank"] = {
m = "[Rupturing Runes] po spuštění omráčí hráče. \n[Tectonic Roar] srazí hráče o značnou vzdálenost zpět. \nHráči, kteří se ocitnou v sevření [Mountain's Grasp], budou odhozeni [Discard Weaklings].",
}
addon.data.encounter["Orta_normal_raid_summary_healer"] = {
m = "[Rupturing Runes] po spuštění omráčí hráče. \n[Tectonic Roar] srazí hráče o značnou vzdálenost zpět. \nHráči, kteří se ocitnou v sevření [Mountain's Grasp], budou odhozeni [Discard Weaklings].",
}
addon.data.encounter["Orta_normal_raid_summary_dps"] = {
m = "[Rupturing Runes] po spuštění omráčí hráče. \n[Tectonic Roar] srazí hráče o značnou vzdálenost zpět. \nHráči, kteří se ocitnou v sevření [Mountain's Grasp], budou odhozeni [Discard Weaklings].",
}

171
Addon/Data/retail/11.lua Normal file
View file

@ -0,0 +1,171 @@
local _, addon = ...
addon.data.encounter["The Gobfather_normal_raid"] = {
{
key = "The Gobfather_normal_raid_a03b221c_00",
children = {
{
key = "The Gobfather_normal_raid_0dd77eb8_0000",
children = {
{
key = "The Gobfather_normal_raid_3df09614_000000",
children = {
{
key = "The Gobfather_normal_raid_2dff6e6c_00000000",
children = {},
},
{
key = "The Gobfather_normal_raid_eeafee09_00000001",
children = {},
},
},
},
},
},
{
key = "The Gobfather_normal_raid_a4190c2f_0001",
children = {},
},
{
key = "The Gobfather_normal_raid_b3ae61ca_0002",
children = {},
},
{
key = "The Gobfather_normal_raid_c5b3601a_0003",
children = {},
},
{
key = "The Gobfather_normal_raid_09c97f46_0004",
children = {},
},
},
},
}
addon.data.encounter["Shurrai_normal_raid"] = {
{
key = "Shurrai_normal_raid_a03b221c_00",
children = {
{
key = "Shurrai_normal_raid_a3276252_0000",
children = {},
},
{
key = "Shurrai_normal_raid_16361c5b_0001",
children = {},
},
{
key = "Shurrai_normal_raid_2a89e69f_0002",
children = {},
},
{
key = "Shurrai_normal_raid_44f7529e_0003",
children = {
{
key = "Shurrai_normal_raid_69996e5a_000300",
children = {},
},
{
key = "Shurrai_normal_raid_ad190ebe_000301",
children = {
{
key = "Shurrai_normal_raid_12617f60_00030100",
children = {},
},
},
},
},
},
},
},
}
addon.data.encounter["Aggregation of Horrors_normal_raid"] = {
{
key = "Aggregation of Horrors_normal_raid_a03b221c_00",
children = {
{
key = "Aggregation of Horrors_normal_raid_29d445eb_0000",
children = {},
},
{
key = "Aggregation of Horrors_normal_raid_23974a30_0001",
children = {
{
key = "Aggregation of Horrors_normal_raid_a1059bb2_000100",
children = {},
},
},
},
{
key = "Aggregation of Horrors_normal_raid_3466ff61_0002",
children = {},
},
{
key = "Aggregation of Horrors_normal_raid_e7ede113_0003",
children = {},
},
{
key = "Aggregation of Horrors_normal_raid_07bff7dc_0004",
children = {},
},
},
},
}
addon.data.encounter["Kordac_normal_raid"] = {
{
key = "Kordac_normal_raid_a03b221c_00",
children = {
{
key = "Kordac_normal_raid_de3f3afb_0000",
children = {},
},
{
key = "Kordac_normal_raid_964943db_0001",
children = {
{
key = "Kordac_normal_raid_682eceff_000100",
children = {},
},
{
key = "Kordac_normal_raid_5b63e678_000101",
children = {},
},
},
},
{
key = "Kordac_normal_raid_8b324485_0002",
children = {},
},
{
key = "Kordac_normal_raid_297bd7aa_0003",
children = {},
},
},
},
}
addon.data.encounter["Orta_normal_raid"] = {
{
key = "Orta_normal_raid_a03b221c_00",
children = {
{
key = "Orta_normal_raid_b2cd00e6_0000",
children = {},
},
{
key = "Orta_normal_raid_0156f9b0_0001",
children = {},
},
{
key = "Orta_normal_raid_7bb400a9_0002",
children = {},
},
{
key = "Orta_normal_raid_28eff812_0003",
children = {
{
key = "Orta_normal_raid_f9c15f37_000300",
children = {},
},
},
},
},
},
}

3164
Addon/Data/retail/2.lua Normal file

File diff suppressed because it is too large Load diff

3186
Addon/Data/retail/3.lua Normal file

File diff suppressed because it is too large Load diff

3289
Addon/Data/retail/4.lua Normal file

File diff suppressed because it is too large Load diff

3355
Addon/Data/retail/5.lua Normal file

File diff suppressed because it is too large Load diff

3205
Addon/Data/retail/6.lua Normal file

File diff suppressed because it is too large Load diff

3001
Addon/Data/retail/7.lua Normal file

File diff suppressed because it is too large Load diff

3001
Addon/Data/retail/8.lua Normal file

File diff suppressed because it is too large Load diff

3118
Addon/Data/retail/9.lua Normal file

File diff suppressed because it is too large Load diff

View file

@ -3,42 +3,56 @@ local _, addon = ...
-- Prepare API object
addon.API = {}
-- Prepare Data objects
addon.data = {};
addon.data.quest = {};
addon.data.item = {};
addon.data.book = {};
addon.data.speech = {}
addon.data.encounter = {}
-- Expose object as global for other addon integration
CzechQuestsAddon = {}
CzechQuestsAddon.data = addon.data
local function SetDefault(key, default)
if CzechQuestsAddon_Store.config[key] == nil then
CzechQuestsAddon_Store.config[key] = default
end
return CzechQuestsAddon_Store.config[key]
end
local function InitStore()
-- Init Store
CzechQuestsAddon_Store = CzechQuestsAddon_Store or {}
CzechQuestsAddon_Store.config = CzechQuestsAddon_Store.config or {}
-- General Settings
CzechQuestsAddon_Store.config.DEBUG_MODE = CzechQuestsAddon_Store.config.DEBUG_MODE or false
CzechQuestsAddon_Store.config.DEBUG_MODE = SetDefault("DEBUG_MODE", false)
-- Quest Settings
CzechQuestsAddon_Store.config.QUEST_ENABLED = CzechQuestsAddon_Store.config.QUEST_ENABLED or true
CzechQuestsAddon_Store.config.QUEST_DARK_MODE = CzechQuestsAddon_Store.config.QUEST_DARK_MODE or false
CzechQuestsAddon_Store.config.QUEST_HEADER_FONT_SIZE = CzechQuestsAddon_Store.config.QUEST_HEADER_FONT_SIZE or 18
CzechQuestsAddon_Store.config.QUEST_TEXT_FONT_SIZE = CzechQuestsAddon_Store.config.QUEST_TEXT_FONT_SIZE or 14
CzechQuestsAddon_Store.config.QUEST_HEADER_FONT_NAME = CzechQuestsAddon_Store.config.QUEST_HEADER_FONT_NAME or 'morpheus_cz.ttf'
CzechQuestsAddon_Store.config.QUEST_TEXT_FONT_NAME = CzechQuestsAddon_Store.config.QUEST_TEXT_FONT_NAME or 'frizquadratatt_cz.ttf'
CzechQuestsAddon_Store.config.QUEST_TEXTURE_ALPHA = CzechQuestsAddon_Store.config.QUEST_TEXTURE_ALPHA or 80
CzechQuestsAddon_Store.config.QUEST_TEXTURE_ALPHA_ONLY_MOVING = CzechQuestsAddon_Store.config.QUEST_TEXTURE_ALPHA_ONLY_MOVING or true
CzechQuestsAddon_Store.config.QUEST_ENABLED = SetDefault("QUEST_ENABLED", true)
CzechQuestsAddon_Store.config.QUEST_DARK_MODE = SetDefault("QUEST_DARK_MODE", false)
CzechQuestsAddon_Store.config.QUEST_HEADER_FONT_SIZE = SetDefault("QUEST_HEADER_FONT_SIZE", 18)
CzechQuestsAddon_Store.config.QUEST_TEXT_FONT_SIZE = SetDefault("QUEST_TEXT_FONT_SIZE", 14)
CzechQuestsAddon_Store.config.QUEST_HEADER_FONT_NAME = SetDefault("QUEST_HEADER_FONT_NAME", 'morpheus_cz.ttf')
CzechQuestsAddon_Store.config.QUEST_TEXT_FONT_NAME = SetDefault("QUEST_TEXT_FONT_NAME", 'frizquadratatt_cz.ttf')
CzechQuestsAddon_Store.config.QUEST_TEXTURE_ALPHA = SetDefault("QUEST_TEXTURE_ALPHA", 80)
CzechQuestsAddon_Store.config.QUEST_TEXTURE_ALPHA_ONLY_MOVING = SetDefault("QUEST_TEXTURE_ALPHA_ONLY_MOVING", true)
-- Speech Settings
CzechQuestsAddon_Store.config.SPEECH_ENABLED = CzechQuestsAddon_Store.config.SPEECH_ENABLED or true
CzechQuestsAddon_Store.config.SPEECH_TEXT_FONT_SIZE = CzechQuestsAddon_Store.config.SPEECH_TEXT_FONT_SIZE or 13
CzechQuestsAddon_Store.config.SPEECH_TEXT_FONT_NAME = CzechQuestsAddon_Store.config.SPEECH_TEXT_FONT_NAME or 'frizquadratatt_cz.ttf'
CzechQuestsAddon_Store.config.SPEECH_FRAME_WIDTH = CzechQuestsAddon_Store.config.SPEECH_FRAME_WIDTH or 320
CzechQuestsAddon_Store.config.SPEECH_ORIGINAL_WHEN_MISSING = CzechQuestsAddon_Store.config.SPEECH_ORIGINAL_WHEN_MISSING or false
CzechQuestsAddon_Store.config.SPEECH_MESSAGE_TEXTURE_ALPHA = CzechQuestsAddon_Store.config.SPEECH_MESSAGE_TEXTURE_ALPHA or 40
CzechQuestsAddon_Store.config.SPEECH_FRAME_POSITION_X = CzechQuestsAddon_Store.config.SPEECH_FRAME_POSITION_X or 0
CzechQuestsAddon_Store.config.SPEECH_FRAME_POSITION_Y = CzechQuestsAddon_Store.config.SPEECH_FRAME_POSITION_Y or 0
CzechQuestsAddon_Store.config.SPEECH_ENABLED = SetDefault("SPEECH_ENABLED", true)
CzechQuestsAddon_Store.config.SPEECH_TEXT_FONT_SIZE = SetDefault("SPEECH_TEXT_FONT_SIZE", 13)
CzechQuestsAddon_Store.config.SPEECH_TEXT_FONT_NAME = SetDefault("SPEECH_TEXT_FONT_NAME", 'frizquadratatt_cz.ttf')
CzechQuestsAddon_Store.config.SPEECH_FRAME_WIDTH = SetDefault("SPEECH_FRAME_WIDTH", 320)
CzechQuestsAddon_Store.config.SPEECH_ORIGINAL_WHEN_MISSING = SetDefault("SPEECH_ORIGINAL_WHEN_MISSING", false)
CzechQuestsAddon_Store.config.SPEECH_MESSAGE_TEXTURE_ALPHA = SetDefault("SPEECH_MESSAGE_TEXTURE_ALPHA", 40)
CzechQuestsAddon_Store.config.SPEECH_FRAME_POSITION_X = SetDefault("SPEECH_FRAME_POSITION_X", 0)
CzechQuestsAddon_Store.config.SPEECH_FRAME_POSITION_Y = SetDefault("SPEECH_FRAME_POSITION_Y", 0)
-- Encounter Settings
CzechQuestsAddon_Store.config.ENCOUNTER_ENABLED = SetDefault("ENCOUNTER_ENABLED", true)
CzechQuestsAddon_Store.config.ENCOUNTER_TEXT_FONT_SIZE = SetDefault("ENCOUNTER_TEXT_FONT_SIZE", 12)
CzechQuestsAddon_Store.config.ENCOUNTER_TEXT_FONT_NAME = SetDefault("ENCOUNTER_TEXT_FONT_NAME", 'frizquadratatt_cz.ttf')
end
-- Event handler frame
@ -49,6 +63,9 @@ local function OnEvent(self, event, addonName, ...)
addon.API.InitOptions()
addon.API.InitQuests()
addon.API.InitSpeeches()
if (WOW_PROJECT_ID ~= WOW_PROJECT_CLASSIC) then
addon.API.InitEncounters()
end
self:UnregisterEvent("ADDON_LOADED")
end
end

View file

@ -1,8 +1,8 @@
## Interface: 110100
## Title: CzechQuests
## Title: Czech Quests
## Notes: Addon displays texts of quests in Czech language
## Author: Roman Jaroš
## Version: 1.0.1
## Version: 1.1.0
## SavedVariables: CzechQuestsAddon_Store
## Category: Translations
## IconTexture: Interface\AddOns\CzechQuests\Assets\Icons\Logo
@ -11,9 +11,21 @@ CzechQuests.lua
Addon/Data/0.lua
Addon/Data/1.lua
Addon/Data/2.lua
Addon/Data/3.lua
Addon/Data/4.lua
Addon/Data/5.lua
Addon/Data/6.lua
Addon/Data/7.lua
Addon/Data/8.lua
Addon/Data/9.lua
Addon/Data/10.lua
Addon/Data/11.lua
Addon/Data/other.lua
Addon/Code/Shared.lua
Addon/Code/DataApi.lua
Addon/Code/Paragraphs.lua
Addon/Code/FontUtils.lua
@ -26,3 +38,7 @@ Addon/Code/Quest.lua
Addon/Code/SpeechDataApi.lua
Addon/Code/SpeechFrame.lua
Addon/Code/Speech.lua
Addon/Code/EncounterDataApi.lua
Addon/Code/EncounterFrame.lua
Addon/Code/Encounter.lua

View file

@ -1,8 +1,8 @@
## Interface: 11505
## Title: CzechQuests
## Interface: 11507
## Title: Czech Quests
## Notes: Addon displays texts of quests in Czech language as tooltip
## Author: Roman Jaroš
## Version: 1.0.1
## Version: 1.1.0
## SavedVariables: CzechQuestsAddon_Store
CzechQuests.lua
@ -13,9 +13,29 @@ Addon/Data/2.lua
Addon/Data/3.lua
Addon/Data/4.lua
Addon/Data/5.lua
Addon/Data/6.lua
Addon/Data/7.lua
Addon/Data/8.lua
Addon/Data/9.lua
Addon/Data/10.lua
Addon/Data/11.lua
Addon/Data/12.lua
Addon/Data/13.lua
Addon/Data/14.lua
Addon/Data/15.lua
Addon/Data/16.lua
Addon/Data/17.lua
Addon/Data/18.lua
Addon/Data/19.lua
Addon/Data/20.lua
Addon/Data/21.lua
Addon/Data/22.lua
Addon/Data/23.lua
Addon/Data/other.lua
Addon/Code/Shared.lua
Addon/Code/DataApi.lua
Addon/Code/Paragraphs.lua
Addon/Code/FontUtils.lua
@ -28,3 +48,6 @@ Addon/Code/Quest.lua
Addon/Code/SpeechDataApi.lua
Addon/Code/SpeechFrame.lua
Addon/Code/Speech.lua
Addon/Code/EncounterFrame.lua
Addon/Code/Encounter.lua

View file

@ -1,262 +0,0 @@
import * as fs from 'node:fs';
import * as path from 'node:path';
import axios from 'axios';
import dotenv from 'dotenv';
dotenv.config({ path: '.env' }).parsed;
const normalizeTranslation = (translation: string | null | undefined) => {
if (translation == null) {
return '';
}
return translation.replace(/\n/g, '\\n').replace(/"/g, "'");
};
const prepareLuaWithFemaleVersion = (quest: Quest, type: keyof Quest, key: string) => {
let text = '';
const value = quest[type] as string;
const normalizedMaleValue = normalizeTranslation(value?.[0]);
const normalizedFemaleValue = normalizeTranslation(value?.[1]);
if (normalizedMaleValue != '') {
text += '\t' + key + 'Male = "' + normalizedMaleValue + '", \n';
}
if (normalizedFemaleValue != '') {
text += '\t' + key + 'Female = "' + normalizedFemaleValue + '", \n';
}
return text;
};
const callTolgee = async <R>(
method: 'GET' | 'POST' | 'PUT' | 'DELETE' = 'GET',
path: string,
params?: any,
data?: any,
) => {
const args = process.argv.slice(2);
const projectId = args[1];
try {
return await axios<R>(`https://translate.romanjaros.local/v2/projects/${projectId}${path}`, {
method,
data,
params,
headers: {
'X-API-KEY': process.env.TOLGEE_PAT as string,
},
});
} catch (e) {
throw e;
}
};
function makeChunks(input: AddonData, chunkSize: number = 1000) {
const keys = Object.keys(input);
const result = [];
for (let i = 0; i < keys.length; i += chunkSize) {
const chunk = keys.slice(i, i + chunkSize).reduce((acc: AddonData, key) => {
acc[key] = input[key];
return acc;
}, {});
result.push(chunk);
}
return result;
}
const splitFirst = (text: string, delimiter: string) => {
const index = text.indexOf(delimiter);
if (index === -1) return text;
return text.slice(index + delimiter.length);
};
(async () => {
const args = process.argv.slice(2);
const addonDir = path.join(process.cwd(), `../Addon/Data/${args[0]}`);
const addonData: Record<string, Quest> = {};
let pageNumber = 0;
try {
// load all data from tolgee
while (true) {
const response = await callTolgee<TolgeeTranslationsResponse>('GET', `/translations`, {
filterTranslatedInLang: 'cs',
languages: 'cs,csf,en',
size: 2000,
page: pageNumber,
});
const translations = response.data?._embedded?.keys ?? [];
if (response.data?.page.totalPages > response.data?.page.number) {
pageNumber++;
// for each page from tolgee
for (const tolgeeKey of translations) {
addonData[tolgeeKey.keyName] = {
...addonData[tolgeeKey.keyName],
...(tolgeeKey.keyNamespace === 'name' && {
names: [
tolgeeKey.translations.cs.text,
tolgeeKey.translations.cs.text === tolgeeKey.translations.csf.text
? null
: tolgeeKey.translations.csf.text,
],
}),
...(tolgeeKey.keyNamespace === 'objective' && {
objectives: [
tolgeeKey.translations.cs.text,
tolgeeKey.translations.cs.text === tolgeeKey.translations.csf.text
? null
: tolgeeKey.translations.csf.text,
],
}),
...(tolgeeKey.keyNamespace === 'description' && {
descriptions: [
tolgeeKey.translations.cs.text,
tolgeeKey.translations.cs.text === tolgeeKey.translations.csf.text
? null
: tolgeeKey.translations.csf.text,
tolgeeKey.translations.en.text,
],
}),
...(tolgeeKey.keyNamespace === 'progress' && {
progresses: [
tolgeeKey.translations.cs.text,
tolgeeKey.translations.cs.text === tolgeeKey.translations.csf.text
? null
: tolgeeKey.translations.csf.text,
],
}),
...(tolgeeKey.keyNamespace === 'completion' && {
completions: [
tolgeeKey.translations.cs.text,
tolgeeKey.translations.cs.text === tolgeeKey.translations.csf.text
? null
: tolgeeKey.translations.csf.text,
],
}),
...(tolgeeKey.keyNamespace === 'speech' && {
speeches: [
tolgeeKey.translations.cs.text,
tolgeeKey.translations.cs.text === tolgeeKey.translations.csf.text
? null
: tolgeeKey.translations.csf.text,
tolgeeKey.translations.en.text,
],
}),
name: tolgeeKey.keyDescription,
id: tolgeeKey.keyName.replace('q', '').replace('i', ''),
isQuest: tolgeeKey.keyName.startsWith('q'),
isQuestItem: tolgeeKey.keyName.startsWith('i'),
};
}
} else {
break;
}
}
// split into chunks
const chunks = makeChunks(addonData);
// build addon file
chunks.forEach((chunk, index) => {
const fileName = path.join(addonDir, `${index++}.lua`);
try {
fs.unlinkSync(fileName);
} catch (e) {}
fs.appendFileSync(fileName, 'local _, addon = ...\n', 'utf8');
for (const [, czechQuest] of Object.entries(chunk)) {
// prepare variables
if (czechQuest.isQuest) {
let luaQuestRecord = '';
luaQuestRecord += `addon.data.quest[${czechQuest.id}] = {\n`;
luaQuestRecord += prepareLuaWithFemaleVersion(czechQuest, 'names', 'title');
luaQuestRecord += prepareLuaWithFemaleVersion(czechQuest, 'objectives', 'objective');
luaQuestRecord += prepareLuaWithFemaleVersion(czechQuest, 'descriptions', 'description');
luaQuestRecord += prepareLuaWithFemaleVersion(czechQuest, 'progresses', 'progress');
luaQuestRecord += prepareLuaWithFemaleVersion(czechQuest, 'completions', 'completion');
luaQuestRecord += `}\n`;
fs.appendFileSync(fileName, luaQuestRecord, 'utf8');
}
if (czechQuest.isQuestItem) {
const page = czechQuest.id.split('_page')?.[1] ?? null;
const variableId = `"${czechQuest.name}${page ? `__${page}` : ''}"`;
let luaQuestRecord = '';
luaQuestRecord += `addon.data.item[${variableId}] = {\n`;
luaQuestRecord += '\ttitle = "' + normalizeTranslation(czechQuest.name) + '", \n';
luaQuestRecord += '\ttext = "' + normalizeTranslation(czechQuest.descriptions?.[0]) + '", \n';
luaQuestRecord += `}\n`;
fs.appendFileSync(fileName, luaQuestRecord, 'utf8');
}
if (czechQuest.speeches) {
let luaQuestRecord = '';
const key = splitFirst(normalizeTranslation(czechQuest.speeches?.[2]) ?? '', ':').trim();
luaQuestRecord += `addon.data.speech["${key}"] = {\n`;
luaQuestRecord += '\ttext = "' + normalizeTranslation(czechQuest.speeches?.[0]).trim() + '", \n';
luaQuestRecord += `}\n`;
fs.appendFileSync(fileName, luaQuestRecord, 'utf8');
}
}
});
} catch (e) {
throw e;
}
})();
type AddonData = Record<string, Quest>;
type Quest = {
id: string;
name: string;
names?: (string | null)[];
descriptions?: (string | null)[];
progresses?: (string | null)[];
completions?: (string | null)[];
objectives?: (string | null)[];
speeches?: (string | null)[];
isQuest: boolean;
isQuestItem: boolean;
};
type TolgeeKeysData = {
keyId: number;
keyName: string;
keyNamespace: string;
keyDescription: string;
keyTags: TolgeeTag[];
translations: {
en: {
id: number;
text: string;
state: 'REVIEWED' | 'TRANSLATED';
};
cs: {
id: number;
text: string | null;
state: 'REVIEWED' | 'TRANSLATED';
};
csf: {
id: number;
text: string | null;
state: 'REVIEWED' | 'TRANSLATED';
};
};
};
type TolgeeTag = {
name: string;
};
type TolgeeTranslationsResponse = {
_embedded: {
keys: TolgeeKeysData[];
};
page: {
size: number;
totalElements: number;
totalPages: number;
number: number;
};
};

3
renovate.json Normal file
View file

@ -0,0 +1,3 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json"
}

Binary file not shown.

Before

(image error) Size: 930 KiB

Binary file not shown.

Before

(image error) Size: 647 KiB

Binary file not shown.

Before

(image error) Size: 452 KiB

Binary file not shown.

Before

(image error) Size: 620 KiB

20
sync.sh
View file

@ -1,20 +0,0 @@
#!/bin/bash
#wow_source_folder="retail"
#wow_destiny_folder="retail"
#wow_destiny_folder="retail"
#wow_destiny_folder="beta"
wow_source_folder="classic_era"
wow_destiny_folder="classic_era"
src_folder="."
dest_folder="/Applications/World of Warcraft/_${wow_destiny_folder}_/Interface/AddOns/CzechQuests"
fswatch -o "$src_folder" | while read -r change; do
rsync -avu --delete "$src_folder" "$dest_folder" --exclude={'.*','*.png','*.sh','*.md','Addon/Data/**','downloader/**',"lib/**","Jenkinsfile"}
rsync -au --delete "$src_folder/Addon/Data/$wow_source_folder/" "$dest_folder/Addon/Data/"
echo "Dest: $dest_folder"
cp "$src_folder/Addon/Data/other.lua" "$dest_folder/Addon/Data/"
done