-
Notifications
You must be signed in to change notification settings - Fork 0
/
reader.py
221 lines (184 loc) · 11 KB
/
reader.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
import os, json
from replacer import nameTrans, formatDialogue, replaceNewLine
from pretty import prettyJSON
if not os.path.exists("inputs"):
os.mkdir("inputs")
if not os.path.exists("outputs"):
os.mkdir("outputs")
files = os.listdir("inputs")
verNum = "1.2.0" # Update this with new releases!!!
print("Parsing files...")
for item in files:
#grab original text
ref = open("inputs/" + item, encoding="utf-8")
parsed = ref.read()
ref.close()
#prettified output (for debugging/reference)
#prettyJSON(parsed, item)
try:
dict = json.loads(parsed)#converts json to dict format
except json.decoder.JSONDecodeError:
print("> Didn't parse " + item + " (file not in JSON format)")
except:
print("> Didn't parse " + item + " (failed to read JSON file)")
else:
newname = "outputs/" + item[0:item.find(".")] + "_parsed.txt"
if os.path.exists(newname):#deletes _parsed file if it already exists
os.remove(newname)
new_file = open(newname, "a", encoding="utf-8")
for group in dict:
if group.startswith("voice"):
new_file.write(group + "\t" + replaceNewLine(dict[group]["serif"].replace("@", "\n")) + "\n")#voice line jasons are so simple. bless
elif group.startswith("serifList"):
for x in dict[group]:
new_file.write(x["serifId"] + "\t" + replaceNewLine(x["serif"].replace("@", "\n")) + "\n")
elif group.startswith("group") or group.startswith("delete") or group.startswith("scene"):
new_file.write("---------------------------------------------\n[GROUP]\t" + group + "\n")
for x in dict[group]:
for y, z in x.items(): #i don't know if there's a way to do this without three goddamn levels of nesting no. twst's file formatting sucks
if y == "serif" and "text" in z.keys() and "speaker" in z.keys():# handles main dialogue (serifs)
if "visible" in z["speaker"].keys() and not z["speaker"]["visible"]: # handles serifs w/o a speaker
new_file.write("SFX\t" + formatDialogue(z["text"]) + "\n")
elif "callNext" in z.keys() and not z["callNext"]: # handles bits of dialogue separated by other actions of some sort
new_file.write(nameTrans(z["speaker"]["text"]) + "\t" + formatDialogue(z["text"]))
elif "callClear" in z.keys() and not z["callClear"]: # other half of the callNext code
new_file.write(formatDialogue(z["text"]) + "\n")
else:
new_file.write(nameTrans(z["speaker"]["text"]) + "\t" + formatDialogue(z["text"]) + "\n")
elif y == "serif" and not "text" in z.keys(): # skips serifs without text
pass
elif y == "choice": # handles choices
count = 1
for obj in z:
new_file.write("[CHOICE]\t" + str(count) + ": " + formatDialogue(obj["text"]) + " (GOTO: " + obj["goTo"] + ")\n")
count+=1
elif y == "goTo":
new_file.write("[GOTO]\t" + z["goTo"] + "\n") # handles pathing
elif y == "title" and "textWhite" in z.keys() and "textGold" in z.keys(): # handles titles
if "episode" in z.keys() and "storyNum" in z["episode"].keys(): # handles titles for episodes
new_file.write("[TITLE]\tEpisode " + z["episode"]["storyNum"] + ": " + z["textWhite"] + "\n\t" + z["textGold"] + "\n")
elif "prologue" in z.keys() and "storyNum" in z["prologue"].keys(): # handles titles for the prologue
new_file.write("[TITLE]\tPrologue " + z["prologue"]["storyNum"] + ": " + z["textWhite"] + "\n\t" + z["textGold"] + "\n")
elif "eventEpisode" in z.keys() and "storyNum" in z["eventEpisode"].keys(): # handles titles for events
new_file.write("[TITLE]\tEvent Episode " + z["eventEpisode"]["storyNum"] + ": " + z["textWhite"] + "\n\t" + z["textGold"] + "\n")
elif "eventTitle" in z.keys() and "storyNum" in z["eventTitle"].keys(): # ...also handles titles for events
new_file.write("[TITLE]\tEvent Episode " + z["eventTitle"]["storyNum"] + ": " + z["textWhite"] + "\n\t" + z["textGold"] + "\n")
elif "personal" in z.keys() and "rarity" in z["personal"].keys() and "anotherName" in z["personal"].keys(): # handles titles for personal stories
new_file.write("[TITLE]\t" + z["textGold"] + " " + z["personal"]["rarity"] + ": " + z["personal"]["anotherName"] + "\n\t" + z["textWhite"] + "\n")
elif "talk" in z.keys() and "text" in z["talk"].keys(): # handles titles for chats
new_file.write("[TITLE]\t" + z["textGold"] + " Chat: " + z["talk"]["text"] + "\n\t" + z["textWhite"] + "\n")
else: # handles other titles
new_file.write("[TITLE]\t" + z["textWhite"] + "\n\t" + z["textGold"] + "\n")
elif y == "title" and not "textWhite" in z.keys(): # skips titles without text
pass
elif y == "text" and "text" in z.keys(): # handles generic "text" content
new_file.write("[TEXT]\t" + formatDialogue(z["text"]) + "\n")
elif y == "place":
if "jp" in z.keys() and "en" in z.keys(): # handles place titles
new_file.write("[PLACE]\t" + z["jp"] + "\n\t" + z["en"] + "\n")
elif not "jp" in z.keys(): # skips places without text
pass
elif y == "narration":
if "text" in z.keys(): # handles narration boxes
new_file.write("[NARRATION]\t" + z["text"] + "\n")
elif "fadeOut" in z.keys():
pass
elif "delete" in z.keys() and z["delete"]:
pass
elif y == "telop":
if "text" in z.keys(): #handles "telops"
new_file.write("[TELOP]\t" + z["text"] + "\n")
elif not "text" in z.keys(): # skips telops without text
pass
elif y == "balloon":
if "text" in z.keys() and "speaker" in z.keys(): # handles speech balloons (in rhythmics and battle cutscenes)
new_file.write(nameTrans(z["speaker"]) + "\t" + formatDialogue(z["text"]) + "\n")
elif not "text" in z.keys(): # skips balloons without text
pass
elif y == "cardSprite":
if "cardId" in z.keys(): # handles card graphics
if "delete" in z.keys() and z["delete"]:
new_file.write("[CARD]\tHide Card " + str(z["cardId"]) + "\n")
elif "isGroovy" in z.keys() and z["isGroovy"]:
new_file.write("[CARD]\tShow Card " + str(z["cardId"]) + " Groovy\n")
else:
new_file.write("[CARD]\tShow Card " + str(z["cardId"]) + "\n")
elif "delete" in z.keys() and z["delete"] == True:
new_file.write("[CARD]\tHide Card\n")
elif y == "sprite":
if "path" in z.keys(): # handles item sprites
new_file.write("[SPRITE]\tShow " + z["id"] + " (" + z["path"][z["path"].rfind("/") + 1:] + ")\n")
elif "fadeOut" in z.keys():
new_file.write("[SPRITE]\tFade out " + z["id"] + "\n")
elif "visible" in z.keys() and z["visible"] == True:
new_file.write("[SPRITE]\tShow " + z["id"] + "\n")
elif "visible" in z.keys() and z["visible"] == False:
new_file.write("[SPRITE]\tHide " + z["id"] + "\n")
elif "delete" in z.keys() and z["delete"]:
new_file.write("[SPRITE]\tHide " + z["id"] + "\n")
elif y == "movie" and "path" in z.keys(): # handles movies
new_file.write("[MOVIE]\t" + z["path"] + "\n")
elif y == "mirrorMovie":
if "delete" in z.keys() and z["delete"] == True: # handles movies but for the mirrors
pass
elif "mirrorId" in z.keys() and not "animation" in z.keys():
new_file.write("[MIRROR]\tMovie " + str(z["mirrorId"]) + "\n")
else:
pass
elif y == "runMovieView" and "queueId" in z.keys():
new_file.write("[MOVIE]\tGOTO: " + z["queueId"] + "\n")
elif y == "reminiscence" and "play" in z.keys() and "path" in z["play"].keys() and "queueId" in z["play"].keys(): #handles uh, reminsiscences
new_file.write("[REMIN]\t" + z["play"]["path"][z["play"]["path"].rfind("/")+1:z["play"]["path"].rfind(".")] + ": " + z["play"]["queueId"] + "\n")
elif y == "blot":
if "dormitoryId" in z.keys() and "animation" in z.keys() and "phase" in z["animation"].keys(): # handles (over)blot animations
new_file.write("[BLOT]\tDorm " + str(z["dormitoryId"]) + " Phase " + str(z["animation"]["phase"]) + "\n")
elif "animation" in z.keys() and "phase" in z["animation"].keys():
new_file.write("[BLOT]\tPhase " + str(z["animation"]["phase"]) + "\n")
elif "dormitoryId" in z.keys() and not "animation" in z.keys():
pass
elif "delete" in z.keys() and z["delete"]:
pass
elif y == "overBlot":
if "dormitoryId" in z.keys() and "animation" in z.keys():
new_file.write("[BLOT]\tDorm " + str(z["dormitoryId"]) + " Overblot\n")
elif "dormitoryId" in z.keys() and not "animation" in z.keys():
pass
elif "delete" in z.keys() and z["delete"]:
pass
elif y == "live2d" or y == "moveCamera" or y == "systemUI" or y == "run" or y == "bgm" or y == "advBgOperator" or y == "touch" or y == "wait" or y == "zoomCamera" or y == "se" or y == "curtain" or y == "spine" or y == "spineCharacter" or y == "sd" or y == "spfx" or y == "shakeCamera" or y == "voice" or y == "transition" or y == "spriteUI" or y == "emotion" or y == "vibration" or y == "advBg" or y == "shakeLoopCamera": # skips a bunch of boring animation/visual logicistical code
pass
else: # for debugging mostly and to catch types i missed
new_file.write(y + "\t(no code to handle this type of object yet, sorry! --Ylime)\n")
elif group.startswith("word") or group.startswith("w") or group.startswith("cut") or group.startswith("c") or group.startswith("motion"): # this applies to both the intro text and also rhythmics. yes <3
if group.startswith("create"):
pass
else:
groupPrinted = False;
for x in dict[group]:
if(groupPrinted == False and ("balloon" in x.keys() or "narration" in x.keys())):
new_file.write("[" + group + "]\n");
groupPrinted = True;
for y, z in x.items():
if y == "balloon":
if "text" in z.keys() and "targetId" in z.keys():
new_file.write(z["targetId"] + "\t" + formatDialogue(z["text"]) + "\n")
elif "delete" in z.keys() and z["delete"]:
pass
elif y == "narration":
if "text" in z.keys():
new_file.write("[NARRATION]\t" + replaceNewLine(z["text"]) + "\n")
elif not "text" in z.keys():
pass
elif y == "voice" or y == "voiceWait" or y == "wait" or y == "spineCharacter" or y == "moveCamera" or y == "zoomCamera" or y == "emotion" or y == "spfxTriggerKicker" or y == "spfxTargetPointFollower" or y == "spine":
pass
else:
new_file.write(y + "\t" + str(z) + "(no code to handle this type of object yet, sorry! --Ylime)\n")
elif group.startswith("initialize"): # skips past rhythmic animations
new_file.write("(no dialogue in this type of JSON object!)\n")
break
else:
new_file.write("(no code to handle this type of JSON file yet, sorry! --Ylime)\n")
new_file.write("---------------------------------------------\nTwstStoryReader v" + verNum + " by Ylimegirl\nhttps://github.com/Ylimegirl/TwstStoryReader")
new_file.close()
print("> Parsed " + item)
print("Finished parsing all files.")