Passed
Push — depfu/update/npm/lodash-4.17.1... ( 152c97 )
by
unknown
04:58
created

TextService.convertEngToHTML   F

Complexity

Conditions 15

Size

Total Lines 77
Code Lines 50

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 15
eloc 50
dl 0
loc 77
rs 2.9998
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like TextService.convertEngToHTML often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
import { TextSearch } from './text/TextSearch';
2
import { Text } from './../../assets/data/text.d';
3
import { GameDataService } from './gameData.service';
4
/**
5
   Copyright 2018 June Hanabi
6
7
   Licensed under the Apache License, Version 2.0 (the "License");
8
   you may not use this file except in compliance with the License.
9
   You may obtain a copy of the License at
10
11
       http://www.apache.org/licenses/LICENSE-2.0
12
13
   Unless required by applicable law or agreed to in writing, software
14
   distributed under the License is distributed on an "AS IS" BASIS,
15
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
   See the License for the specific language governing permissions and
17
   limitations under the License.
18
 */
19
20
/*
21
 * This is quite complicated because I need to take a regular string that
22
 * represents an array of bytes to convert to however each byte it converts to
23
 * could be 1 or more characters in length.
24
 *
25
 * I honestly don't know of any way to do this except very slow impratical uses
26
 * but given it's only ever 7-10 bytes long it shouldn't be too hard.
27
 *
28
 * 1. Search the start of the string for all ~255 codes, stop on the first
29
 *    occurence
30
 * 2. Convert it to a correct byte code
31
 * 3. Splice string
32
 * 4. Repeat until done
33
*/
34
35
import { Injectable } from '@angular/core';
36
37
declare var window: {
38
    text: any;
39
}
40
41
@Injectable({
42
    providedIn: 'root'
43
})
44
export class TextService {
45
46
    constructor(
47
        public gd: GameDataService
48
    ) {
49
        window.text = this;
50
51
        const text: Text[] = this.gd.file("text").data;
52
        this.rawTrans = text;
53
        for (let i = 0; i < text.length; i++) {
54
            // Get translate pair entry
55
            const transPair: Text = text[i];
56
57
            // Cache inside direct lookup caches for easier lookup
58
            this.indToEng[transPair.code] = transPair;
59
            this.engToIndex[transPair.eng] = transPair;
60
        }
61
    }
62
63
    get search(): TextSearch {
64
        return new TextSearch(this.gd.file("text").data);
65
    }
66
67
    // Converts a string filled with english typable in-game text code
68
    // representations to raw in-game code
69
    // Only converts 10 bytes with of in-game code
70
    // If fed strings not in the representation list, the unknown characters will
71
    // be ignored thus possibly corrupting output
72
    // Possibly very slow
73
    public convertToCode = (str: string, maxLength: number = 10, autoEnd: boolean = true): Uint8Array => {
74
75
        let code = [];
76
        let lastCode = 0;
77
78
        if ((typeof str !== 'string') && autoEnd)
79
            return new Uint8Array([0x50]);
80
        else if ((typeof str !== 'string') && !autoEnd)
81
            return new Uint8Array();
82
83
        while (str.length !== 0) {
84
85
            let match = false;
86
87
            for (let i = 0; i < this.rawTrans.length; i++) {
88
89
                // Find a starting match
90
                const transPair = this.rawTrans[i];
91
                if (!str.startsWith(transPair.eng))
92
                    continue;
93
94
                match = true;
95
96
                // Slice off match from string start
97
                str = str.substring(transPair.eng.length);
98
99
                // Append code to code array and set last code
100
                code.push(transPair.code);
101
                lastCode = transPair.code;
102
103
                // Break early
104
                break;
105
            }
106
107
            // If no match then strip unknown character and continue
108
            if (match === false)
109
                str = str.substring(1);
110
111
            // Stop here if code array is at 10 bytes or a stop code was manually
112
            // set (0x50)
113
            if (code.length === maxLength ||
114
                lastCode === 0x50)
115
                break;
116
        }
117
118
        // Append terminator
119
        if (autoEnd)
120
            code.push(0x50);
121
122
        return new Uint8Array(code);
123
    }
124
125
    // Much easier and faster, just expand the in-game code to it's english
126
    // representation directly
127
    public convertFromCode = (codes: Uint8Array, maxLength: number = 10): string => {
128
        let eng = "";
129
130
        for (let i = 0; i < codes.length; i++) {
131
            const code = codes[i];
132
133
            // Don't include the end terminator
134
            // stop here if there is one
135
            if (code === 0x50)
136
                break;
137
138
            if (this.indToEng[code] === undefined)
139
                continue;
140
141
            eng += this.indToEng[code].eng;
142
143
            // If we're done with the 10th character assume 11th is terminator
144
            //and stop here
145
            if (i === maxLength)
146
                break;
147
        }
148
149
        return eng;
150
    }
151
152
    // Converts an english format string to code represented as how it would be
153
    // in-game
154
    public convertEngToHTML(msg: string, maxChars: number, rival: string = "BLUE", player: string = "RED") {
155
        // Convert string to char codes
156
        let charCodes = Array.from(this.convertToCode(msg, maxChars, false));
157
158
        // Pre-pass
159
        for (let i = 0; i < charCodes.length; i++) {
160
            const char = charCodes[i];
161
            // <pkmn>
162
            if (char === 0x4A) {
163
                charCodes.splice(i, 1, 0xE1, 0xE2);
164
            }
165
            // <player>
166
            else if (char === 0x52) {
167
                const playerName = Array.from(this.convertToCode(player, 7, false));
168
                charCodes.splice(i, 1, ...playerName);
169
            }
170
            // <rival>
171
            else if (char === 0x53) {
172
                const rivalName = Array.from(this.convertToCode(rival, 7, false));
173
                charCodes.splice(i, 1, ...rivalName);
174
            }
175
            // POK<e>
176
            else if (char === 0x54) {
177
                const str = Array.from(this.convertToCode("POK<e>", 10, false));
178
                charCodes.splice(i, 1, ...str);
179
            }
180
            // <......>
181
            else if (char === 0x56) {
182
                const str = Array.from(this.convertToCode("<...><...>", 10, false));
183
                charCodes.splice(i, 1, ...str);
184
            }
185
            // <targ>
186
            else if (char === 0x59) {
187
                const str = Array.from(this.convertToCode("CHARIZARD", 100, false));
188
                charCodes.splice(i, 1, ...str);
189
            }
190
            // <user>
191
            else if (char === 0x5A) {
192
                const str = Array.from(this.convertToCode("Enemy BLASTOISE", 100, false));
193
                charCodes.splice(i, 1, ...str);
194
            }
195
            // <pc>
196
            else if (char === 0x5B) {
197
                const str = Array.from(this.convertToCode("PC", 100, false));
198
                charCodes.splice(i, 1, ...str);
199
            }
200
            // <tm>
201
            else if (char === 0x5C) {
202
                const str = Array.from(this.convertToCode("TM", 100, false));
203
                charCodes.splice(i, 1, ...str);
204
            }
205
            // <trainer>
206
            else if (char === 0x5D) {
207
                const str = Array.from(this.convertToCode("TRAINER", 100, false));
208
                charCodes.splice(i, 1, ...str);
209
            }
210
            // <rocket>
211
            else if (char === 0x5E) {
212
                const str = Array.from(this.convertToCode("ROCKET", 100, false));
213
                charCodes.splice(i, 1, ...str);
214
            }
215
        }
216
217
        const fontStr = [];
218
        for (let i = 0; i < charCodes.length; i++) {
219
            const char = charCodes[i];
220
221
            if (this.indToEng[char].useTilemap)
222
                fontStr.push(`<div class="pr pr-pic pr-${char.toString(16).toUpperCase().padStart(2, "0")}"></div>`);
223
            else
224
                fontStr.push(`<div class="pr pr-${char.toString(16).toUpperCase().padStart(2, "0")}"></div>`);
225
        }
226
227
        return fontStr.join('');
228
    }
229
230
    // Table of raw translation data
231
    public rawTrans: Text[];
232
233
    // Code Index to English Representation
234
    // Sparse array of code indexes containing representation strings
235
    public indToEng: Text[] = [];
236
237
    // Representation string to code points
238
    // Object of representation strings containing code values
239
    public engToIndex: {
240
        [key: string]: Text
241
    } = {};
242
}
243