level.ts 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. /**
  2. * This module represents the levels for the game. Each level consists of lines
  3. * that you have to complete. Each line has the kanji of the line, which is used
  4. * solely for display and the kana of the line which the input is based.
  5. */
  6. namespace level {
  7. export interface Line {
  8. kanji: string,
  9. kana: string,
  10. start?: number,
  11. end?: number
  12. }
  13. export interface Level {
  14. name: string,
  15. creator?: string,
  16. genre?: string,
  17. difficulty?: string,
  18. audio?: string,
  19. lines: Line[]
  20. }
  21. export interface LevelSet {
  22. name: string,
  23. levels: Level[]
  24. }
  25. export function loadFromJson(url: string): Promise<LevelSet[]> {
  26. return window.fetch(url)
  27. .then(response => response.json())
  28. }
  29. let parser = new DOMParser();
  30. function parseXML(response: Response): Promise<Document> {
  31. return response.text().then(text => {
  32. let normalized = text.replace(/[“”]/g, '"');
  33. return parser.parseFromString(normalized, "text/xml");
  34. });
  35. }
  36. export function loadFromTM(base: string): Promise<LevelSet[]> {
  37. return window.fetch(base+'/folderlist.xml')
  38. .then(parseXML)
  39. .then(dom => parseTMFolderList(base, dom))
  40. }
  41. function parseTMFolderList(base: string, dom: Document): Promise<LevelSet[]> {
  42. let folderList = dom.querySelectorAll('folder');
  43. let promises = [];
  44. for (let i = 0; i < folderList.length; ++i) {
  45. let folder = folderList[i];
  46. let name = folder.getAttribute('name');
  47. let path = folder.getAttribute('path');
  48. let promise = window.fetch(base+'/'+path)
  49. .then(parseXML)
  50. .then(dom => parseTMFolder(base, name, dom))
  51. promises.push(promise);
  52. }
  53. return Promise.all(promises);
  54. }
  55. function parseTMFolder(base: string, name: string, dom: Document): Promise<LevelSet> {
  56. let musicList = dom.querySelectorAll('musicinfo');
  57. let promises = [];
  58. for (let i = 0; i < musicList.length; ++i) {
  59. let musicInfo = musicList[i];
  60. let xmlPath = base+'/'+musicInfo.getAttribute('xmlpath');
  61. let audioPath = base+'/'+musicInfo.getAttribute('musicpath');
  62. function getData(tag: string): string | null {
  63. let elem = musicInfo.querySelector(tag);
  64. if (elem === null) {
  65. return null;
  66. } else {
  67. return elem.textContent;
  68. }
  69. }
  70. let name = getData('musicname');
  71. let creator = getData('artist');
  72. let genre = getData('genre');
  73. let difficulty = getData('level');
  74. let promise = window.fetch(xmlPath)
  75. .then(parseXML)
  76. .then(parseTMSong)
  77. .then(lines => {
  78. return {
  79. name,
  80. creator,
  81. genre,
  82. difficulty,
  83. audio: audioPath,
  84. lines
  85. }
  86. })
  87. promises.push(promise);
  88. }
  89. return Promise.all(promises)
  90. .then(levels => {
  91. return { name, levels }
  92. })
  93. }
  94. function parseTMSong(dom: Document): Line[] {
  95. let kanjiList = dom.querySelectorAll('nihongoword');
  96. let kanaList = dom.querySelectorAll('word');
  97. let intervalList = dom.querySelectorAll('interval');
  98. let lines: Line[] = [];
  99. let time = 0;
  100. for (let i = 0; i < intervalList.length; ++i) {
  101. let start = time;
  102. time += parseInt(intervalList[i].textContent) / 1000
  103. lines.push({
  104. kanji: kanjiList[i].textContent,
  105. kana: kanaList[i].textContent,
  106. start: start,
  107. end: time
  108. })
  109. }
  110. return lines;
  111. }
  112. }