This repository has been archived by the owner on May 29, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
311 lines (288 loc) · 12.7 KB
/
index.js
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
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
const { promisify } = require("util");
const readdir = promisify(require("fs").readdir);
const path = require("path");
module.exports = function TeraGuide(mod){
const { player } = mod.require.library;
// Extra stuff that we need
const extras = {
guides: [], // The list of guides that we have
active_guide: false, // The current active guide, if it doesn't exist, it should be false
lastLocation: 0, // The last location we were at
verbose: null, // If the dungeon has been disabled
spawning: true, // If the dungeon has object spawning disabled
sp: null, // for sp guides
es: null, // for es guides
mobHP: {}, // Mob hps
bonfire: false, // bonfire stuff
entity: false, // For using spawning inside of functions for guides
uint64: 0xFFFFFFFA, // unint64 for spawning objects
spawnHandler: require(path.resolve(__dirname, "./modules/spawnHandler.js")),
sendMessage: require(path.resolve(__dirname, "./modules/sendMessage.js")),
eventHandler: require(path.resolve(__dirname, "./modules/eventHandler.js")),
despawnAll: require(path.resolve(__dirname, "./modules/despawnAll.js")),
spawnedObjects: new Map(),
debug: { // Debug object for debugging stuff later
abnormal: false,
skill: false,
hp: false,
message: false,
quest: false
},
hookData: {
hooks: {}, // An object that contains all our hook information
hookArray: [], // An array of our currently loaded hooks
loaded: false, // If the hooks are currently loaded
load: function(){ // Function to load hooks
if(this.loaded || this.hookArray.length) return;
for(let h in this.hooks){
h = this.hooks[h];
this.hookArray.push(mod.hook(h.name, h.vers, h.func.bind(null, mod, extras)));
}
this.loaded = true;
},
unload: function(){ // Function to unload hooks
if(!this.loaded || !this.hookArray.length) return;
for(const h of this.hookArray){
mod.unhook(h);
}
this.hookArray = [];
this.loaded = false;
}
}
};
const init = async () => {
// Load the ids of the available guides
const guideFiles = await readdir(path.resolve(__dirname, "./guides/"));
for(const file of guideFiles){
if(!file.endsWith(".js")) continue;
const guideName = file.split(".")[0];
extras.guides.push(guideName);
// If the dungeon doesn't exist within the settings, we can add it, though we're missing it's name, we'll deal with that in just a second.
if(!mod.settings.dungeons[guideName]) mod.settings.dungeons[guideName] = { name: undefined, verbose: true, spawnObject: true };
// We can however apply these 2 names
if(guideName === "3020") mod.settings.dungeons[guideName].name = "Sea of Honor";
if(guideName === "3030") mod.settings.dungeons[guideName].name = "Commander's Residence";
}
// Grab a list of dungeon names, and apply them to settings
let allDungeons;
const dungeons = new Map();
try {
const resOne = await mod.queryData("/EventMatching/EventGroup/Event@type=?", ["Dungeon"], true, true, ["id"]);
allDungeons = resOne.map(e => {
const zoneId = e.children.find(x => x.name == "TargetList").children.find(x => x.name == "Target").attributes.id;
let dungeon = dungeons.get(zoneId);
if(!dungeon){
dungeon = { id: zoneId, name: "" };
dungeons.set(zoneId, dungeon);
}
return dungeon;
});
const resTwo = await mod.queryData("/StrSheet_Dungeon/String@id=?", [[... dungeons.keys()]], true);
for(const res of resTwo){
const id = res.attributes.id.toString();
const name = res.attributes.string.toString();
if(!mod.settings.dungeons[id]) continue;
mod.settings.dungeons[id].name = name;
}
} catch (e){
mod.warn(`Unable to get the list of dungeon names, some dungeons may be named "undefined"`);
}
// Load "game" events
const gameFiles = await readdir(path.resolve(__dirname, "./events/game/"));
for(const file of gameFiles){
if(!file.endsWith(".js")) continue;
try {
const event = require(path.resolve(__dirname, `./events/game/${file}`));
const eventName = file.split(".")[0];
mod.game.on(eventName, event.bind(null, mod, extras));
delete require.cache[require.resolve(path.resolve(__dirname, `./events/game/${file}`))];
} catch (e){
mod.error(`Unable to load "game" event ${file}:\n${e}`);
}
}
// Load hooks
const hookFiles = await readdir(path.resolve(__dirname, "./events/hooks/"));
for(const file of hookFiles){
if(!file.endsWith(".js")) continue;
try {
const hookFile = require(path.resolve(__dirname, `./events/hooks/${file}`));
const hookName = file.split(".")[0];
extras.hookData.hooks[hookName] = {
name: hookName,
vers: hookFile.version,
func: hookFile.func
};
delete require.cache[require.resolve(path.resolve(__dirname, `./events/hooks/${file}`))];
} catch (e){
mod.error(`Unable to load "hook" ${file}:\n${e}`);
}
}
// Load "me" events
const meFiles = await readdir(path.resolve(__dirname, "./events/me/"));
for(const file of meFiles){
if(!file.endsWith(".js")) continue;
try {
const event = require(path.resolve(__dirname, `./events/me/${file}`));
const eventName = file.split(".")[0];
mod.game.me.on(eventName, event.bind(null, mod, extras));
delete require.cache[require.resolve(path.resolve(__dirname, `./events/me/${file}`))];
} catch (e){
mod.error(`Unable to load "me" event ${file}:\n${e}`);
}
}
};
init();
// Honestly chat colors are unnessary but eh, fight me. I wanted this to look fancy.
const cg = '</font><font color="#00ff00">'; // Green
const cr = '</font><font color="#ff0000">'; // red
const cw = '</font><font color="#ffffff">'; // white
const cp = '</font><font color="#ae60ff">'; // Purple
const cmd = mod.command;
cmd.add("guide", { // Add chat commands to change mod settings
"$none": () => {
cmd.message(`Guide Settings:\n${cw}` +
`Guide enabled: ${mod.settings.enabled ? cg : cr}${mod.settings.enabled}${cw}\n` +
`TTS Enabled: ${mod.settings.tts ? cg : cr}${mod.settings.tts}${cw}\n` +
`Notice Chat: ${mod.settings.notice ? cg : cr}${mod.settings.notice}`);
},
"help": () => { // Enable and disable the module
cmd.message(`Guide Commands:\n${cw}` +
`Toggle - Enables and disables the guide\n` +
`Notice -\n` +
`TTS - Enables and disables Text-To-Speach\n` +
`Notice - Enables and disables sending messages to notice chat\n` +
`Verbose - Enables and disables a specific dungeon guide\n` +
`Objects - Enables and disables spawning objects in a dungeon\n` +
`Debug - Enables and disables debugging of skills, abnormals etc\n` +
`Test - Allows you to test event keys`);
},
"toggle": () => { // Enable and disable the module
mod.settings.enabled = !mod.settings.enabled;
cmd.message(`Guide has been ${mod.settings.enabled ? cg : cr}${mod.settings.enabled ? "en" : "dis"}abled`);
},
"tts": () => { // Enable and disable tts
mod.settings.tts = !mod.settings.tts;
cmd.message(`TTS has been ${mod.settings.tts ? cg : cr}${mod.settings.tts ? "en" : "dis"}abled`);
},
"notice": () => { // Enable and disable whether or not the message is sent to party notices
mod.settings.notice = !mod.settings.notice;
cmd.message(`Send to notice chat has been ${mod.settings.notice ? cg : cr}${mod.settings.notice ? "en" : "dis"}abled`);
},
"verbose": (args) => { // Enable and disable a specific dungeon guide
if(parseInt(args)) args = parseInt(args);
if(isNaN(args)) return;
let foundDungeon = false;
for(const dungeon of mod.settings.dungeons){
if(dungeon.id !== args) continue;
foundDungeon = true;
dungeon.verbose = !dungeon.verbose;
return cmd.message(`Spawning objects in ${cp}${dungeon.name}${cw} has been ${dungeon.verbose ? cg : cr}${dungeon.verbose ? "en" : "dis"}abled`);
}
if(!foundDungeon) return cmd.message(`That dungeon doesn't seem to exist, please try again!`);
},
"objects": (args) => { // Enable and disable the spawning of objects inside a specific dungeon
if(parseInt(args)) args = parseInt(args);
if(isNaN(args)) return;
let foundDungeon = false;
for(const dungeon of mod.settings.dungeons){
if(dungeon.id !== args) return;
foundDungeon = true;
dungeon.spawnObject = !dungeon.spawnObject;
return cmd.message(`Spawning objects in ${cp}${dungeon.name}${cw} has been ${dungeon.spawnObject ? cg : cr}${dungeon.spawnObject ? "en" : "dis"}abled`);
}
if(!foundDungeon) return cmd.message(`That dungeon doesn't seem to exist, please try again!`);
},
"debug": (args) => { // Enable and disable key debugging messages
const argsSplit = args.split(" ");
const subCommand = argsSplit[0];
if(!subCommand){
cmd.message(`Debugging Settings:\n` +
`</font><font color="#e05555">Abnormals: ${extras.debug.abnormal ? cg : cr}${extras.debug.abnormal ? "en" : "dis"}abled\n` +
`</font><font color="#e0cd55">Boss Skills: ${extras.debug.skill ? cg : cr}${extras.debug.skill ? "en" : "dis"}abled\n` +
`</font><font color="#9357de">Boss HP: ${extras.debug.hp ? cg : cr}${extras.debug.hp ? "en" : "dis"}abled\n` +
`</font><font color="#c74cb2">Dungeon Message: ${extras.debug.message ? cg : cr}${extras.debug.message ? "en" : "dis"}abled\n` +
`</font><font color="#4cc1c7">Quest Balloons: ${extras.debug.quest ? cg : cr}${extras.debug.quest ? "en" : "dis"}abled`);
}
switch(subCommand){
case "abnormal":
case "abnormals":
extras.debug.abnormal = !extras.debug.abnormal;
cmd.message(`Abnormal debugging has been ${extras.debug.abnormal ? cg : cr}${extras.debug.abnormal ? "en" : "dis"}abled`);
break;
case "skill":
case "skills":
extras.debug.skill = !extras.debug.skill;
cmd.message(`Mob skill debugging has been ${extras.debug.skill ? cg : cr}${extras.debug.skill ? "en" : "dis"}abled`);
break;
case "hp":
extras.debug.hp = !extras.debug.hp;
cmd.message(`Mob HP debugging has been ${extras.debug.hp ? cg : cr}${extras.debug.hp ? "en" : "dis"}abled`);
break;
case "dm":
extras.debug.message = !extras.debug.message;
cmd.message(`Dungeon message debugging has been ${extras.debug.message ? cg : cr}${extras.debug.message ? "en" : "dis"}abled`);
break;
case "qb":
extras.debug.quest = !extras.debug.quest;
cmd.message(`Quest balloon debugging has been ${extras.debug.quest ? cg : cr}${extras.debug.quest ? "en" : "dis"}abled`);
break;
default:
cmd.message(`${subCommand} is not a valid debugging type.`);
}
},
"campfire": (args) => { // Spawn a bonfire because WHY WOULDN'T YOU WANT THIS???
let type = 1;
switch(args){
case "normal": type = 1; break;
case "friend":
case "friendly":
case "santa": type = 6; break;
case "blue": type = 8; break;
case "purple": type = 9; break;
case "sacrifice": type = 10; break;
case "remove":
case "despawn": type = -1; break;
default: type = 1; break;
}
function despawnBonfire(){
mod.send("S_DESPAWN_BONFIRE", 2, { gameId: 0xCEDE5683 });
extras.bonfire = false;
mod.command.message("Despawned the campfire");
}
if(type === -1){
despawnBonfire();
} else {
if(extras.bonfire) despawnBonfire();
extras.spawnHandler(mod, extras, {
spawnType: "S_SPAWN_BONFIRE",
spawnVersion: 2,
despawnType: "S_DESPAWN_BONFIRE",
despawnVersion: 2,
bonfireType: type,
bonfireID: 0xCEDE5683,
duration: 600000,
ent: {
loc: player.loc
}
});
extras.bonfire = true;
mod.command.message("Spawned a campfire");
}
},
"test": (args) => { // Test a key with the player as the target entity
cmd.message(`Running event with key "${args}"`);
extras.eventHandler(mod, extras, { event: args, target: false, ent: player });
}
});
this.destructor = async () => { // When the mod gets unloaded
extras.despawnAll(mod, extras);
mod.clearAllTimeouts(); // Clear all timers
mod.clearAllIntervals();
cmd.remove("guide"); // Remove chat command
delete require.cache[require.resolve(path.resolve(__dirname, "./modules/spawnHandler.js"))]; // Remove the spawnHandler requirement
delete require.cache[require.resolve(path.resolve(__dirname, "./modules/sendMessage.js"))]; // Remove the sendMessage requirement
delete require.cache[require.resolve(path.resolve(__dirname, "./modules/eventHandler.js"))]; // Remove the eventHandler requirement
delete require.cache[require.resolve(path.resolve(__dirname, "./modules/despawnAll.js"))]; // Remove the eventHandler requirement
extras.hookData.unload(); // Attempt unloading all hooks
};
};