albibong 1.0.4__py3-none-any.whl → 1.0.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- albibong/classes/character.py +26 -4
- albibong/classes/event_handler/__init__.py +116 -0
- albibong/classes/event_handler/handle_event_character_equipment_changed.py +24 -0
- albibong/classes/event_handler/handle_event_health.py +35 -0
- albibong/classes/event_handler/handle_event_in_combat_state_update.py +17 -0
- albibong/classes/event_handler/handle_event_new_character.py +44 -0
- albibong/classes/event_handler/handle_event_other_grabbed_loot.py +14 -0
- albibong/classes/event_handler/handle_event_party.py +38 -0
- albibong/classes/event_handler/handle_event_update_fame.py +7 -0
- albibong/classes/event_handler/handle_event_update_re_spec_points.py +11 -0
- albibong/classes/event_handler/handle_operation_change_cluster.py +43 -0
- albibong/classes/event_handler/handle_operation_join.py +78 -0
- albibong/classes/event_handler/handle_operation_move.py +8 -0
- albibong/classes/event_handler/world_data_utils.py +102 -0
- albibong/classes/item.py +1 -1
- albibong/classes/packet_handler.py +6 -4
- albibong/classes/world_data.py +14 -318
- albibong/gui_dist/assets/{index-BFSx0nua.css → index-DZvgNqlG.css} +1 -1
- albibong/gui_dist/assets/{index-DAndaN_4.js → index-E7pha23k.js} +20 -20
- albibong/gui_dist/index.html +2 -2
- albibong/threads/websocket_server.py +2 -0
- {albibong-1.0.4.dist-info → albibong-1.0.5.dist-info}/METADATA +2 -2
- {albibong-1.0.4.dist-info → albibong-1.0.5.dist-info}/RECORD +26 -13
- {albibong-1.0.4.dist-info → albibong-1.0.5.dist-info}/WHEEL +1 -1
- {albibong-1.0.4.dist-info → albibong-1.0.5.dist-info}/entry_points.txt +0 -0
- {albibong-1.0.4.dist-info → albibong-1.0.5.dist-info}/licenses/LICENSE +0 -0
albibong/classes/world_data.py
CHANGED
|
@@ -1,22 +1,10 @@
|
|
|
1
|
-
import json
|
|
2
|
-
import os
|
|
3
|
-
from collections import deque
|
|
4
|
-
import threading
|
|
5
1
|
from uuid import UUID
|
|
6
|
-
from playsound import playsound
|
|
7
2
|
|
|
8
3
|
from albibong.classes.character import Character
|
|
9
4
|
from albibong.classes.coords import Coords
|
|
10
5
|
from albibong.classes.dungeon import Dungeon
|
|
11
6
|
from albibong.classes.item import Item
|
|
12
7
|
from albibong.classes.location import Location
|
|
13
|
-
from albibong.classes.utils import Utils
|
|
14
|
-
from albibong.resources.EventCode import EventCode
|
|
15
|
-
from albibong.resources.OperationCode import OperationCode
|
|
16
|
-
from albibong.threads.websocket_server import send_event
|
|
17
|
-
|
|
18
|
-
FILENAME = os.path.join(os.path.expanduser("~"), "Albibong/list_dungeon.json")
|
|
19
|
-
os.makedirs(os.path.dirname(FILENAME), exist_ok=True)
|
|
20
8
|
|
|
21
9
|
|
|
22
10
|
class WorldData:
|
|
@@ -39,310 +27,6 @@ class WorldData:
|
|
|
39
27
|
self.party_members: set[str] = set()
|
|
40
28
|
self.is_dps_meter_running: bool = True
|
|
41
29
|
|
|
42
|
-
def handle_response(self, parameters):
|
|
43
|
-
if 253 in parameters:
|
|
44
|
-
if parameters[253] == OperationCode.JOIN.value:
|
|
45
|
-
self.handle_join_response(parameters)
|
|
46
|
-
elif parameters[253] == OperationCode.CHANGE_CLUSTER.value:
|
|
47
|
-
self.set_location(parameters)
|
|
48
|
-
|
|
49
|
-
def handle_event(self, parameters):
|
|
50
|
-
if 252 in parameters:
|
|
51
|
-
if parameters[252] == EventCode.OTHER_GRABBED_LOOT.value:
|
|
52
|
-
if 2 in parameters and parameters[2] in self.characters:
|
|
53
|
-
char: Character = self.characters[parameters[2]]
|
|
54
|
-
char.update_loot(parameters)
|
|
55
|
-
if self.current_dungeon and parameters[2] == self.me.username:
|
|
56
|
-
self.current_dungeon.update_loot(parameters)
|
|
57
|
-
elif parameters[252] == EventCode.UPDATE_FAME.value:
|
|
58
|
-
self.me.update_fame(parameters)
|
|
59
|
-
if self.current_dungeon:
|
|
60
|
-
self.current_dungeon.update_fame(parameters)
|
|
61
|
-
elif parameters[252] == EventCode.UPDATE_RE_SPEC_POINTS.value:
|
|
62
|
-
self.me.update_re_spec(parameters)
|
|
63
|
-
if self.current_dungeon:
|
|
64
|
-
self.current_dungeon.update_re_spec(parameters)
|
|
65
|
-
elif parameters[252] == EventCode.CHARACTER_EQUIPMENT_CHANGED.value:
|
|
66
|
-
self.change_character_equipment(parameters)
|
|
67
|
-
elif (
|
|
68
|
-
parameters[252] == EventCode.HEALTH_UPDATE.value
|
|
69
|
-
and self.is_dps_meter_running
|
|
70
|
-
):
|
|
71
|
-
self.handle_health_update(parameters)
|
|
72
|
-
elif (
|
|
73
|
-
parameters[252] == EventCode.HEALTH_UPDATES.value
|
|
74
|
-
and self.is_dps_meter_running
|
|
75
|
-
):
|
|
76
|
-
self.handle_health_updates(parameters)
|
|
77
|
-
elif (
|
|
78
|
-
parameters[252] == EventCode.PARTY_JOINED.value
|
|
79
|
-
or parameters[252] == EventCode.PARTY_PLAYER_JOINED.value
|
|
80
|
-
or parameters[252] == EventCode.PARTY_PLAYER_LEFT.value
|
|
81
|
-
or parameters[252] == EventCode.PARTY_DISBANDED.value
|
|
82
|
-
):
|
|
83
|
-
self.update_party_member(parameters)
|
|
84
|
-
elif parameters[252] == EventCode.NEW_CHARACTER.value:
|
|
85
|
-
self.create_character(
|
|
86
|
-
id=parameters[0],
|
|
87
|
-
uuid=parameters[7],
|
|
88
|
-
username=parameters[1],
|
|
89
|
-
guild=parameters[8] if 8 in parameters else "",
|
|
90
|
-
alliance=parameters[49] if 49 in parameters else "",
|
|
91
|
-
coords=(
|
|
92
|
-
Coords(parameters[15][0], parameters[15][1])
|
|
93
|
-
if 15 in parameters
|
|
94
|
-
else Coords(0, 0)
|
|
95
|
-
),
|
|
96
|
-
equipments=parameters[38] if 38 in parameters else [],
|
|
97
|
-
)
|
|
98
|
-
...
|
|
99
|
-
|
|
100
|
-
def handle_request(self, parameters):
|
|
101
|
-
if 253 in parameters:
|
|
102
|
-
if parameters[253] == OperationCode.MOVE.value and self.me:
|
|
103
|
-
self.me.update_coords(parameters)
|
|
104
|
-
...
|
|
105
|
-
|
|
106
|
-
def end_current_dungeon(self):
|
|
107
|
-
if self.current_dungeon:
|
|
108
|
-
list_dungeon = deque()
|
|
109
|
-
|
|
110
|
-
try:
|
|
111
|
-
with open(FILENAME) as json_file:
|
|
112
|
-
list_dungeon = deque(json.load(json_file))
|
|
113
|
-
except:
|
|
114
|
-
pass
|
|
115
|
-
|
|
116
|
-
self.current_dungeon.get_elapsed_time()
|
|
117
|
-
list_dungeon.appendleft(Dungeon.serialize(self.current_dungeon))
|
|
118
|
-
|
|
119
|
-
with open(FILENAME, "w") as json_file:
|
|
120
|
-
json.dump(list(list_dungeon), json_file)
|
|
121
|
-
|
|
122
|
-
event = {
|
|
123
|
-
"type": "update_dungeon",
|
|
124
|
-
"payload": {"list_dungeon": list(list_dungeon)},
|
|
125
|
-
}
|
|
126
|
-
send_event(event)
|
|
127
|
-
self.current_dungeon = None
|
|
128
|
-
|
|
129
|
-
def start_current_dungeon(self, type, name):
|
|
130
|
-
if self.current_dungeon == None:
|
|
131
|
-
new_dungeon = Dungeon(type, name)
|
|
132
|
-
self.current_dungeon = new_dungeon
|
|
133
|
-
|
|
134
|
-
def set_dungeon_status(self, check_map, map_type_splitted):
|
|
135
|
-
if "EXPEDITION" in map_type_splitted or "DUNGEON" in map_type_splitted:
|
|
136
|
-
self.start_current_dungeon(type=check_map.type, name=check_map.name)
|
|
137
|
-
elif (
|
|
138
|
-
"EXPEDITION" not in map_type_splitted or "DUNGEON" not in map_type_splitted
|
|
139
|
-
):
|
|
140
|
-
self.end_current_dungeon()
|
|
141
|
-
return False
|
|
142
|
-
|
|
143
|
-
def set_location(self, parameters):
|
|
144
|
-
self.change_equipment_log = {}
|
|
145
|
-
|
|
146
|
-
if 1 in parameters:
|
|
147
|
-
check_map = Location.get_location_from_code(parameters[1])
|
|
148
|
-
map_type_splitted = set(check_map.type.split("_"))
|
|
149
|
-
self.set_dungeon_status(check_map, map_type_splitted)
|
|
150
|
-
|
|
151
|
-
if "ISLAND" in map_type_splitted or "HIDEOUT" in map_type_splitted:
|
|
152
|
-
check_map.name = f"{parameters[2]}'s {check_map.name}"
|
|
153
|
-
self.current_map = check_map
|
|
154
|
-
|
|
155
|
-
elif 0 in parameters:
|
|
156
|
-
check_map = Location.get_location_from_code(parameters[0])
|
|
157
|
-
map_type_splitted = set(check_map.type.split("_"))
|
|
158
|
-
is_dungeon = self.set_dungeon_status(check_map, map_type_splitted)
|
|
159
|
-
if is_dungeon == False:
|
|
160
|
-
self.current_map = Location.get_location_from_code(parameters[0])
|
|
161
|
-
|
|
162
|
-
event = {
|
|
163
|
-
"type": "update_location",
|
|
164
|
-
"payload": {
|
|
165
|
-
"map": self.current_map.name if self.current_map else "None",
|
|
166
|
-
"dungeon": (
|
|
167
|
-
self.current_dungeon.name if self.current_dungeon else "None"
|
|
168
|
-
),
|
|
169
|
-
},
|
|
170
|
-
}
|
|
171
|
-
send_event(event)
|
|
172
|
-
|
|
173
|
-
def update_party_member(self, parameters):
|
|
174
|
-
if parameters[252] == EventCode.PARTY_JOINED.value:
|
|
175
|
-
self.party_members = set(parameters[5])
|
|
176
|
-
elif parameters[252] == EventCode.PARTY_DISBANDED.value:
|
|
177
|
-
self.party_members = {self.me.username}
|
|
178
|
-
elif parameters[252] == EventCode.PARTY_PLAYER_JOINED.value:
|
|
179
|
-
self.party_members.add(parameters[2])
|
|
180
|
-
elif parameters[252] == EventCode.PARTY_PLAYER_LEFT.value:
|
|
181
|
-
uuid = UUID(bytes=bytes(parameters[1]))
|
|
182
|
-
if uuid in self.char_uuid_to_username:
|
|
183
|
-
name = self.char_uuid_to_username[uuid]
|
|
184
|
-
if name == self.me.username:
|
|
185
|
-
self.party_members = {self.me.username}
|
|
186
|
-
event = {
|
|
187
|
-
"type": "update_dps",
|
|
188
|
-
"payload": {"party_members": self.serialize_party_members()},
|
|
189
|
-
}
|
|
190
|
-
send_event(event)
|
|
191
|
-
|
|
192
|
-
def handle_health_update(self, parameters):
|
|
193
|
-
|
|
194
|
-
nominal = parameters[2] if 2 in parameters else 0
|
|
195
|
-
target = parameters[0]
|
|
196
|
-
inflictor = parameters[6]
|
|
197
|
-
|
|
198
|
-
self.update_damage_or_heal(target, inflictor, nominal)
|
|
199
|
-
|
|
200
|
-
def update_damage_or_heal(self, target, inflictor, nominal):
|
|
201
|
-
|
|
202
|
-
if inflictor not in self.char_id_to_username:
|
|
203
|
-
# character not initialized yet
|
|
204
|
-
return
|
|
205
|
-
|
|
206
|
-
username = self.char_id_to_username[inflictor]
|
|
207
|
-
|
|
208
|
-
if username == "not initialized":
|
|
209
|
-
# self not initialized
|
|
210
|
-
return
|
|
211
|
-
|
|
212
|
-
char: Character = self.characters[username]
|
|
213
|
-
|
|
214
|
-
if nominal < 0:
|
|
215
|
-
if target == inflictor:
|
|
216
|
-
# suicide
|
|
217
|
-
return
|
|
218
|
-
char.update_damage_dealt(abs(nominal))
|
|
219
|
-
else:
|
|
220
|
-
char.update_heal_dealt(nominal)
|
|
221
|
-
|
|
222
|
-
event = {
|
|
223
|
-
"type": "update_dps",
|
|
224
|
-
"payload": {"party_members": self.serialize_party_members()},
|
|
225
|
-
}
|
|
226
|
-
send_event(event)
|
|
227
|
-
|
|
228
|
-
def handle_health_updates(self, parameters):
|
|
229
|
-
|
|
230
|
-
for i in range(len(parameters[2])):
|
|
231
|
-
nominal = parameters[2][i]
|
|
232
|
-
target = parameters[0]
|
|
233
|
-
inflictor = parameters[6][i]
|
|
234
|
-
|
|
235
|
-
self.update_damage_or_heal(target, inflictor, nominal)
|
|
236
|
-
|
|
237
|
-
def change_character_equipment(self, parameters):
|
|
238
|
-
if 2 in parameters:
|
|
239
|
-
if parameters[0] in self.char_id_to_username:
|
|
240
|
-
if self.char_id_to_username[parameters[0]] != "not initialized":
|
|
241
|
-
char = self.characters[self.char_id_to_username[parameters[0]]]
|
|
242
|
-
if char.username in self.party_members:
|
|
243
|
-
char.update_equipment(parameters[2])
|
|
244
|
-
event = {
|
|
245
|
-
"type": "update_dps",
|
|
246
|
-
"payload": {
|
|
247
|
-
"party_members": self.serialize_party_members()
|
|
248
|
-
},
|
|
249
|
-
}
|
|
250
|
-
send_event(event)
|
|
251
|
-
else:
|
|
252
|
-
self.change_equipment_log[parameters[0]] = parameters[2]
|
|
253
|
-
|
|
254
|
-
def handle_join_response(self, parameters):
|
|
255
|
-
# set my character
|
|
256
|
-
self.convert_id_to_name(old_id=self.me.id, new_id=parameters[0], char=self.me)
|
|
257
|
-
self.me.uuid = Utils.convert_int_arr_to_uuid(parameters[1])
|
|
258
|
-
self.me.username = parameters[2]
|
|
259
|
-
self.me.guild = parameters[57] if 57 in parameters else ""
|
|
260
|
-
self.me.alliance = parameters[77] if 77 in parameters else ""
|
|
261
|
-
if self.me.id in self.change_equipment_log:
|
|
262
|
-
self.me.update_equipment(self.change_equipment_log[self.me.id])
|
|
263
|
-
|
|
264
|
-
# put self in characters list
|
|
265
|
-
self.characters[self.me.username] = self.me
|
|
266
|
-
self.char_uuid_to_username[self.me.uuid] = self.me.username
|
|
267
|
-
|
|
268
|
-
# put self in party
|
|
269
|
-
self.party_members.add(self.me.username)
|
|
270
|
-
|
|
271
|
-
# set map my character is currently in
|
|
272
|
-
if parameters[8][0] == "@":
|
|
273
|
-
area = parameters[8].split("@")
|
|
274
|
-
if area[1] == "RANDOMDUNGEON":
|
|
275
|
-
check_map = Location.get_location_from_code(area[1])
|
|
276
|
-
self.start_current_dungeon(type=check_map.type, name=check_map.name)
|
|
277
|
-
|
|
278
|
-
event_char = {
|
|
279
|
-
"type": "init_character",
|
|
280
|
-
"payload": {
|
|
281
|
-
"username": self.me.username,
|
|
282
|
-
"fame": self.me.fame_gained,
|
|
283
|
-
"re_spec": self.me.re_spec_gained,
|
|
284
|
-
"silver": self.me.silver_gained,
|
|
285
|
-
"weapon": self.me.equipment[0].image,
|
|
286
|
-
},
|
|
287
|
-
}
|
|
288
|
-
event_map = {
|
|
289
|
-
"type": "update_location",
|
|
290
|
-
"payload": {
|
|
291
|
-
"map": self.current_map.name if self.current_map else "None",
|
|
292
|
-
"dungeon": (
|
|
293
|
-
Dungeon.serialize(self.current_dungeon)
|
|
294
|
-
if self.current_dungeon
|
|
295
|
-
else None
|
|
296
|
-
),
|
|
297
|
-
},
|
|
298
|
-
}
|
|
299
|
-
event_party = {
|
|
300
|
-
"type": "update_dps",
|
|
301
|
-
"payload": {"party_members": self.serialize_party_members()},
|
|
302
|
-
}
|
|
303
|
-
send_event(event_map)
|
|
304
|
-
send_event(event_char)
|
|
305
|
-
send_event(event_party)
|
|
306
|
-
|
|
307
|
-
def convert_id_to_name(self, old_id, new_id, char: Character):
|
|
308
|
-
if old_id in self.char_id_to_username:
|
|
309
|
-
self.char_id_to_username.pop(old_id) # delete old relative id
|
|
310
|
-
char.id = new_id
|
|
311
|
-
self.char_id_to_username[char.id] = char.username # add new relative id
|
|
312
|
-
|
|
313
|
-
def create_character(
|
|
314
|
-
self,
|
|
315
|
-
id: int,
|
|
316
|
-
uuid: list[int],
|
|
317
|
-
username: str,
|
|
318
|
-
guild: str,
|
|
319
|
-
alliance: str,
|
|
320
|
-
equipments: list[str] = [],
|
|
321
|
-
coords: Coords = Coords(0, 0),
|
|
322
|
-
):
|
|
323
|
-
|
|
324
|
-
# initiate character
|
|
325
|
-
if username not in self.characters:
|
|
326
|
-
char: Character = Character(
|
|
327
|
-
id=id,
|
|
328
|
-
uuid=Utils.convert_int_arr_to_uuid(uuid),
|
|
329
|
-
username=username,
|
|
330
|
-
guild=guild,
|
|
331
|
-
alliance=alliance,
|
|
332
|
-
coords=coords,
|
|
333
|
-
)
|
|
334
|
-
char.update_equipment(equipments)
|
|
335
|
-
self.characters[char.username] = char
|
|
336
|
-
self.char_id_to_username[char.id] = char.username
|
|
337
|
-
self.char_uuid_to_username[char.uuid] = char.username
|
|
338
|
-
|
|
339
|
-
# change map
|
|
340
|
-
else:
|
|
341
|
-
char: Character = self.characters[username]
|
|
342
|
-
char.update_equipment(equipments)
|
|
343
|
-
char.coords = coords
|
|
344
|
-
self.convert_id_to_name(old_id=char.id, new_id=id, char=char)
|
|
345
|
-
|
|
346
30
|
def serialize_party_members(self):
|
|
347
31
|
serialized = []
|
|
348
32
|
|
|
@@ -372,10 +56,18 @@ class WorldData:
|
|
|
372
56
|
if total_heal > 0
|
|
373
57
|
else 0
|
|
374
58
|
)
|
|
59
|
+
duration = char.total_combat_duration
|
|
60
|
+
|
|
61
|
+
combat_duration = str(duration).split(".")[0]
|
|
62
|
+
dps = (
|
|
63
|
+
damage_dealt // duration.total_seconds()
|
|
64
|
+
if duration.total_seconds() != 0
|
|
65
|
+
else 0
|
|
66
|
+
)
|
|
375
67
|
weapon = (
|
|
376
68
|
Item.serialize(char.equipment[0])["image"]
|
|
377
69
|
if char.equipment != []
|
|
378
|
-
else "
|
|
70
|
+
else "/No Equipment.png"
|
|
379
71
|
)
|
|
380
72
|
|
|
381
73
|
# member character not initialized
|
|
@@ -385,7 +77,9 @@ class WorldData:
|
|
|
385
77
|
damage_percent = 0
|
|
386
78
|
healing_dealt = 0
|
|
387
79
|
heal_percent = 0
|
|
388
|
-
|
|
80
|
+
combat_duration = 0
|
|
81
|
+
dps = 0
|
|
82
|
+
weapon = "/No Equipment.png"
|
|
389
83
|
|
|
390
84
|
data = {
|
|
391
85
|
"username": username,
|
|
@@ -393,6 +87,8 @@ class WorldData:
|
|
|
393
87
|
"damage_percent": damage_percent,
|
|
394
88
|
"healing_dealt": healing_dealt,
|
|
395
89
|
"heal_percent": heal_percent,
|
|
90
|
+
"combat_duration": combat_duration,
|
|
91
|
+
"dps": dps,
|
|
396
92
|
"weapon": weapon,
|
|
397
93
|
}
|
|
398
94
|
serialized.append(data)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
*{box-sizing:border-box}:root{font-family:Inter,system-ui,Avenir,Helvetica,Arial,sans-serif;line-height:1.5;font-weight:400;color-scheme:light dark;color:#ffffffde;font-synthesis:none;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}p{margin:0}a{font-weight:500;color:#646cff;text-decoration:inherit}a:hover{color:#535bf2}#root,body{margin:auto;display:flex;flex-direction:column;justify-content:start;align-items:center;min-width:320px;min-height:100vh;color:#fff;width:100%}h1{font-size:2em;line-height:1}button{border-radius:8px;border:1px solid transparent;padding:.6em 1.2em;font-size:1em;font-weight:500;font-family:inherit;background-color:#1a1a1a;cursor:pointer;transition:border-color .25s}button:hover{border-color:#646cff}button:focus,button:focus-visible{outline:4px auto -webkit-focus-ring-color}@media (prefers-color-scheme: light){:root{color:#213547;background-color:#fff}a:hover{color:#747bff}button{background-color:#f9f9f9}}._dmgBar_zdqdf_1{background:linear-gradient(135deg,#ff6486,#6486ff);height:6px;border-radius:8px;margin-bottom:2px}._healBar_zdqdf_8{background:linear-gradient(135deg,#64ffde,#64ff90);height:2px;border-radius:4px}._dpsContainer_zdqdf_14{display:flex;flex-direction:column;justify-content:flex-start;width:100%;gap:4px;box-sizing:content-box;padding:16px}._dpsRow_zdqdf_24{display:flex;flex-direction:row;justify-content:space-between;align-items:center}._dpsNumber_zdqdf_31{width:128px;text-align:right}._hidden_zdqdf_36{display:none}._player_zdqdf_40{flex-grow:1}._checkboxColor_zdqdf_44{accent-color:#64d3ff}._container_pkz1i_1{display:flex;flex-direction:column;align-items:center;gap:8px;width:100%;gap:1.5rem}._snackbar_pkz1i_10{position:fixed;right:64px}._stats_pkz1i_15{display:flex;flex-direction:row;align-items:center;gap:.5rem}._options_pkz1i_22{display:flex;flex-direction:row;align-items:center;gap:2rem}._row_pkz1i_29{display:flex;width:100%;justify-content:space-between}._hidden_pkz1i_35{display:none}
|
|
1
|
+
*{box-sizing:border-box}:root{font-family:Inter,system-ui,Avenir,Helvetica,Arial,sans-serif;line-height:1.5;font-weight:400;color-scheme:light dark;color:#ffffffde;font-synthesis:none;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}p{margin:0}a{font-weight:500;color:#646cff;text-decoration:inherit}a:hover{color:#535bf2}#root,body{margin:auto;display:flex;flex-direction:column;justify-content:start;align-items:center;min-width:320px;min-height:100vh;color:#fff;width:100%}h1{font-size:2em;line-height:1}button{border-radius:8px;border:1px solid transparent;padding:.6em 1.2em;font-size:1em;font-weight:500;font-family:inherit;background-color:#1a1a1a;cursor:pointer;transition:border-color .25s}button:hover{border-color:#646cff}button:focus,button:focus-visible{outline:4px auto -webkit-focus-ring-color}@media (prefers-color-scheme: light){:root{color:#213547;background-color:#fff}a:hover{color:#747bff}button{background-color:#f9f9f9}}._dmgBar_zdqdf_1{background:linear-gradient(135deg,#ff6486,#6486ff);height:6px;border-radius:8px;margin-bottom:2px}._healBar_zdqdf_8{background:linear-gradient(135deg,#64ffde,#64ff90);height:2px;border-radius:4px}._dpsContainer_zdqdf_14{display:flex;flex-direction:column;justify-content:flex-start;width:100%;gap:4px;box-sizing:content-box;padding:16px}._dpsRow_zdqdf_24{display:flex;flex-direction:row;justify-content:space-between;align-items:center}._dpsNumber_zdqdf_31{width:128px;text-align:right}._hidden_zdqdf_36{display:none}._player_zdqdf_40{flex-grow:1}._checkboxColor_zdqdf_44{accent-color:#64d3ff}._dungeonContainer_3nxyx_1{border-radius:1rem;width:100%;padding:2rem;display:flex;flex-direction:column;gap:1rem}._tag_3nxyx_12{background-color:#64d3ff;padding:0 1rem;border-radius:1rem;color:#0f3c4e;font-weight:700}._stickToTop_3nxyx_20{z-index:10;position:sticky;top:64px;left:0;width:100%;padding:24px 0}._container_pkz1i_1{display:flex;flex-direction:column;align-items:center;gap:8px;width:100%;gap:1.5rem}._snackbar_pkz1i_10{position:fixed;right:64px}._stats_pkz1i_15{display:flex;flex-direction:row;align-items:center;gap:.5rem}._options_pkz1i_22{display:flex;flex-direction:row;align-items:center;gap:2rem}._row_pkz1i_29{display:flex;width:100%;justify-content:space-between}._hidden_pkz1i_35{display:none}
|