-
Notifications
You must be signed in to change notification settings - Fork 0
/
IronmonConnect.lua
268 lines (232 loc) · 9.32 KB
/
IronmonConnect.lua
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
local function IronmonConnect()
local self = {}
self.version = "1.4"
self.name = "Ironmon Connect"
self.author = "Omnyist Productions"
self.description = "Uses BizHawk's socket functionality to provide run data to an external source."
self.github = "omnypro/ironmon-connect"
self.url = string.format("https://github.com/%s", self.github or "")
self.seed = nil
--------------------------------------
-- INTERNAL SCRIPT FUNCTIONS BELOW
--------------------------------------
-- Checkpoint Data
local Checkpoints = {
"RIVAL1",
"FIRSTTRAINER",
"RIVAL2",
"BROCK",
"RIVAL3",
"RIVAL4",
"MISTY",
"SURGE",
"RIVAL5",
"ROCKETHIDEOUT",
"ERIKA",
"KOGA",
"RIVAL6",
"SILPHCO",
"SABRINA",
"BLAINE",
"GIOVANNI",
"RIVAL7",
"LORELAI",
"BRUNO",
"AGATHA",
"LANCE",
"CHAMP"
}
-- Variables
self.currentCheckpointIndex = 1
self.currentCheckpoint = Checkpoints[self.currentCheckpointIndex]
self.checkpointsNotified = {}
-- Functions
local function send(data)
packet = FileManager.JsonLibrary.encode(data)
comm.socketServerSend(packet)
end
local function sendCheckpointNotification(index, checkpoint)
local payload = {
["type"] = "checkpoint",
["metadata"] = {
["id"] = index,
["name"] = checkpoint,
["seed"] = self.seed,
},
}
send(payload)
end
function self.initializeCheckpoints()
-- Send notification of our initial state.
local payload = {
["type"] = "checkpoint",
["metadata"] = {
["id"] = 0,
["name"] = "START",
},
}
send(payload)
for checkpoint, _ in pairs(Checkpoints) do
self.checkpointsNotified[checkpoint] = false
end
end
function self.handleCheckpoint()
-- Progression Flags
local Progression = {
RIVAL1 = Program.hasDefeatedTrainer(326) or Program.hasDefeatedTrainer(327) or Program.hasDefeatedTrainer(328),
FIRSTTRAINER = Program.hasDefeatedTrainer(102) or Program.hasDefeatedTrainer(115),
RIVAL2 = Program.hasDefeatedTrainer(329) or Program.hasDefeatedTrainer(330) or Program.hasDefeatedTrainer(331),
BROCK = Program.hasDefeatedTrainer(414),
RIVAL3 = Program.hasDefeatedTrainer(332) or Program.hasDefeatedTrainer(333) or Program.hasDefeatedTrainer(334),
RIVAL4 = Program.hasDefeatedTrainer(426) or Program.hasDefeatedTrainer(427) or Program.hasDefeatedTrainer(428),
MISTY = Program.hasDefeatedTrainer(415),
SURGE = Program.hasDefeatedTrainer(416),
RIVAL5 = Program.hasDefeatedTrainer(429) or Program.hasDefeatedTrainer(430) or Program.hasDefeatedTrainer(431),
ROCKETHIDEOUT = Program.hasDefeatedTrainer(348),
ERIKA = Program.hasDefeatedTrainer(417),
KOGA = Program.hasDefeatedTrainer(418),
RIVAL6 = Program.hasDefeatedTrainer(432) or Program.hasDefeatedTrainer(433) or Program.hasDefeatedTrainer(434),
SILPHCO = Program.hasDefeatedTrainer(349),
SABRINA = Program.hasDefeatedTrainer(420),
BLAINE = Program.hasDefeatedTrainer(419),
GIOVANNI = Program.hasDefeatedTrainer(350),
RIVAL7 = Program.hasDefeatedTrainer(435) or Program.hasDefeatedTrainer(436) or Program.hasDefeatedTrainer(437),
LORELAI = Program.hasDefeatedTrainer(410) or Program.hasDefeatedTrainer(735),
BRUNO = Program.hasDefeatedTrainer(411) or Program.hasDefeatedTrainer(736),
AGATHA = Program.hasDefeatedTrainer(412) or Program.hasDefeatedTrainer(737),
LANCE = Program.hasDefeatedTrainer(413) or Program.hasDefeatedTrainer(738),
CHAMP = Program.hasDefeatedTrainer(438) or Program.hasDefeatedTrainer(439) or Program.hasDefeatedTrainer(440)
}
local nextCheckpoint = Checkpoints[self.currentCheckpointIndex]
local condition = Progression[nextCheckpoint]
if condition and nextCheckpoint == self.currentCheckpoint and not self.checkpointsNotified[nextCheckpoint] then
console.log("> IMC: Current checkpoint: " .. self.currentCheckpointIndex .. " > " .. self.currentCheckpoint)
sendCheckpointNotification(self.currentCheckpointIndex, nextCheckpoint)
self.checkpointsNotified[nextCheckpoint] = true
self.currentCheckpointIndex = self.currentCheckpointIndex + 1 -- Move to the next checkpoint
self.currentCheckpoint = Checkpoints[self.currentCheckpointIndex] -- Update the current checkpoint
end
end
-- Location Tracking
self.currentLocation = 0
function self.handleLocation()
local currentLocation = TrackerAPI.getMapId()
if currentLocation ~= self.currentLocation then
local location = {
["type"] = "location",
["metadata"] = {
["id"] = TrackerAPI.getMapId()
}
}
send(location) -- Send the location data
self.currentLocation = currentLocation -- Update the current location
end
end
--------------------------------------
-- INTENRAL TRACKER FUNCTIONS BELOW
--------------------------------------
function self.isPlayingFRLG()
return GameSettings.game == 3
end
function self.handleSeed()
self.seed = Main.currentSeed
console.log("> IMC: Seed number is now " .. self.seed .. ".")
local seed = {
["type"] = "seed",
["metadata"] = {
["count"] = Main.currentSeed
}
}
send(seed)
end
function self.resetSeedVars()
self.initializeCheckpoints()
self.currentCheckpointIndex = 1
self.currentCheckpoint = Checkpoints[self.currentCheckpointIndex]
self.checkpointsNotified = {}
self.currentLocation = 0
self.seed = nil
end
-- To properly determine when new items are acquired, need to load them in first at least once.
local loadedVarsThisSeed
-- Executed when the user clicks the "Check for Updates" button while viewing the extension details within the Tracker's UI
-- Returns [true, downloadUrl] if an update is available (downloadUrl auto opens in browser for user); otherwise returns [false, downloadUrl]
-- Remove this function if you choose not to implement a version update check for your extension
function self.checkForUpdates()
-- Update the pattern below to match your version. You can check what this looks like by visiting the latest release url on your repo
local versionResponsePattern = '"tag_name":%s+"%w+(%d+%.%d+)"' -- matches "1.0" in "tag_name": "v1.0"
local versionCheckUrl = string.format("https://api.github.com/repos/%s/releases/latest", self.github or "")
local downloadUrl = string.format("%s/releases/latest", self.url or "")
local compareFunc = function(a, b) return a ~= b and not Utils.isNewerVersion(a, b) end -- if current version is *older* than online version
local isUpdateAvailable = Utils.checkForVersionUpdate(versionCheckUrl, self.version, versionResponsePattern, compareFunc)
return isUpdateAvailable, downloadUrl
end
-- Executed only once: When the extension is enabled by the user, and/or when the Tracker first starts up, after it loads all other required files and code
function self.startup()
console.log(string.format("> IMC: Version %s successfully loaded.", self.version))
console.log(string.format("> IMC: Using settings file: %s", Options.FILES["Settings File"]))
console.log("> IMC: Connected to server: " .. comm.socketServerGetInfo())
-- Output an init message to help verify things are working on that end.
local payload = {
["type"] = "init",
["metadata"] = {
["version"] = self.version,
["game"] = GameSettings.game,
},
}
send(payload)
-- Populate the current seed number, which should exist upon startup.
self.handleSeed()
-- Initialize the checkpoint notification flags.
self.initializeCheckpoints()
end
-- Executed once every 30 frames, after most data from game memory is read in
function self.afterProgramDataUpdate()
-- Once per seed, when the player is able to move their character, initiate the seed data.
if not self.isPlayingFRLG() or not Program.isValidMapLocation() then
return
elseif not loadedVarsThisSeed then
self.resetSeedVars()
loadedVarsThisSeed = true
console.log("> IMC: Seed variables reset.")
end
self.handleCheckpoint()
self.handleLocation()
end
-- Executed once every 30 frames, after any battle related data from game memory is read in
function self.afterBattleDataUpdate()
-- [ADD CODE HERE]
end
-- Executed once every 30 frames or after any redraw event is scheduled (i.e. most button presses)
function self.afterRedraw()
-- [ADD CODE HERE]
end
-- Executed before a button's onClick() is processed, and only once per click per button
-- Param: button: the button object being clicked
function self.onButtonClicked(button)
-- [ADD CODE HERE]
end
-- Executed after a new battle begins (wild or trainer), and only once per battle
function self.afterBattleBegins()
-- [ADD CODE HERE]
end
-- Executed after a battle ends, and only once per battle
function self.afterBattleEnds()
-- [ADD CODE HERE]
end
-- [Bizhawk only] Executed each frame (60 frames per second)
-- CAUTION: Avoid unnecessary calculations here, as this can easily affect performance.
function self.inputCheckBizhawk()
-- Uncomment to use, otherwise leave commented out
-- local mouseInput = input.getmouse() -- lowercase 'input' pulls directly from Bizhawk API
-- local joypadButtons = Input.getJoypadInputFormatted() -- uppercase 'Input' uses Tracker formatted input
-- [ADD CODE HERE]
end
-- Executed each frame of the game loop, after most data from game memory is read in but before any natural redraw events occur
-- CAUTION: Avoid code here if possible, as this can easily affect performance. Most Tracker updates occur at 30-frame intervals, some at 10-frame.
function self.afterEachFrame()
-- [ADD CODE HERE]
end
return self
end
return IronmonConnect