albibong 1.0.3__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/__init__.py +10 -4
- albibong/assets/boom_small.mp3 +0 -0
- albibong/classes/character.py +29 -9
- 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/logger.py +1 -1
- albibong/classes/packet_handler.py +6 -4
- albibong/classes/world_data.py +14 -278
- albibong/gui_dist/Albibong.png +0 -0
- 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 +5 -5
- albibong/requirements.txt +2 -1
- albibong/resources/EventCode.py +578 -577
- albibong/resources/event_code.json +578 -577
- albibong/resources/items.json +16421 -16051
- albibong/threads/http_server.py +2 -2
- albibong/threads/sniffer_thread.py +1 -0
- albibong/threads/websocket_server.py +2 -0
- {albibong-1.0.3.dist-info → albibong-1.0.5.dist-info}/METADATA +3 -2
- albibong-1.0.5.dist-info/RECORD +64 -0
- {albibong-1.0.3.dist-info → albibong-1.0.5.dist-info}/WHEEL +1 -1
- albibong-1.0.3.dist-info/RECORD +0 -49
- {albibong-1.0.3.dist-info → albibong-1.0.5.dist-info}/entry_points.txt +0 -0
- {albibong-1.0.3.dist-info → albibong-1.0.5.dist-info}/licenses/LICENSE +0 -0
|
@@ -3,8 +3,9 @@ import traceback
|
|
|
3
3
|
|
|
4
4
|
from scapy.all import UDP, Packet
|
|
5
5
|
|
|
6
|
+
from albibong.classes.event_handler import EventHandler
|
|
6
7
|
from albibong.classes.logger import Logger
|
|
7
|
-
from albibong.classes.world_data import
|
|
8
|
+
from albibong.classes.world_data import get_world_data
|
|
8
9
|
from albibong.photon_packet_parser import (
|
|
9
10
|
EventData,
|
|
10
11
|
OperationRequest,
|
|
@@ -33,20 +34,21 @@ class PacketHandler:
|
|
|
33
34
|
self.on_event, self.on_request, self.on_response
|
|
34
35
|
)
|
|
35
36
|
self.world_data = get_world_data()
|
|
37
|
+
self.event_handler = EventHandler()
|
|
36
38
|
|
|
37
39
|
@log_payload
|
|
38
40
|
def on_event(self, payload: EventData):
|
|
39
|
-
self.
|
|
41
|
+
self.event_handler.on_event(self.world_data, payload.parameters)
|
|
40
42
|
return payload
|
|
41
43
|
|
|
42
44
|
@log_payload
|
|
43
45
|
def on_request(self, payload: OperationRequest):
|
|
44
|
-
self.
|
|
46
|
+
self.event_handler.on_request(self.world_data, payload.parameters)
|
|
45
47
|
return payload
|
|
46
48
|
|
|
47
49
|
@log_payload
|
|
48
50
|
def on_response(self, payload: OperationResponse):
|
|
49
|
-
self.
|
|
51
|
+
self.event_handler.on_response(self.world_data, payload.parameters)
|
|
50
52
|
return payload
|
|
51
53
|
|
|
52
54
|
def handle(self, packet: Packet):
|
albibong/classes/world_data.py
CHANGED
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
import json
|
|
2
|
-
import os
|
|
3
|
-
from collections import deque
|
|
4
1
|
from uuid import UUID
|
|
5
2
|
|
|
6
3
|
from albibong.classes.character import Character
|
|
@@ -8,13 +5,6 @@ from albibong.classes.coords import Coords
|
|
|
8
5
|
from albibong.classes.dungeon import Dungeon
|
|
9
6
|
from albibong.classes.item import Item
|
|
10
7
|
from albibong.classes.location import Location
|
|
11
|
-
from albibong.classes.utils import Utils
|
|
12
|
-
from albibong.resources.EventCode import EventCode
|
|
13
|
-
from albibong.resources.OperationCode import OperationCode
|
|
14
|
-
from albibong.threads.websocket_server import send_event
|
|
15
|
-
|
|
16
|
-
FILENAME = os.path.join(os.path.expanduser("~"), "Albibong/list_dungeon.json")
|
|
17
|
-
os.makedirs(os.path.dirname(FILENAME), exist_ok=True)
|
|
18
8
|
|
|
19
9
|
|
|
20
10
|
class WorldData:
|
|
@@ -37,272 +27,6 @@ class WorldData:
|
|
|
37
27
|
self.party_members: set[str] = set()
|
|
38
28
|
self.is_dps_meter_running: bool = True
|
|
39
29
|
|
|
40
|
-
def handle_response(self, parameters):
|
|
41
|
-
if 253 in parameters:
|
|
42
|
-
if parameters[253] == OperationCode.JOIN.value:
|
|
43
|
-
self.handle_join_response(parameters)
|
|
44
|
-
elif parameters[253] == OperationCode.CHANGE_CLUSTER.value:
|
|
45
|
-
self.set_location(parameters)
|
|
46
|
-
|
|
47
|
-
def handle_event(self, parameters):
|
|
48
|
-
if 252 in parameters:
|
|
49
|
-
if parameters[252] == EventCode.OTHER_GRABBED_LOOT.value:
|
|
50
|
-
if 2 in parameters and parameters[2] in self.characters:
|
|
51
|
-
char: Character = self.characters[parameters[2]]
|
|
52
|
-
char.update_loot(parameters)
|
|
53
|
-
if self.current_dungeon and parameters[2] == self.me.username:
|
|
54
|
-
self.current_dungeon.update_loot(parameters)
|
|
55
|
-
elif parameters[252] == EventCode.UPDATE_FAME.value:
|
|
56
|
-
self.me.update_fame(parameters)
|
|
57
|
-
if self.current_dungeon:
|
|
58
|
-
self.current_dungeon.update_fame(parameters)
|
|
59
|
-
elif parameters[252] == EventCode.UPDATE_RE_SPEC_POINTS.value:
|
|
60
|
-
self.me.update_re_spec(parameters)
|
|
61
|
-
if self.current_dungeon:
|
|
62
|
-
self.current_dungeon.update_re_spec(parameters)
|
|
63
|
-
elif parameters[252] == EventCode.CHARACTER_EQUIPMENT_CHANGED.value:
|
|
64
|
-
self.change_character_equipment(parameters)
|
|
65
|
-
elif (
|
|
66
|
-
parameters[252] == EventCode.HEALTH_UPDATE.value
|
|
67
|
-
and self.is_dps_meter_running
|
|
68
|
-
):
|
|
69
|
-
self.update_dps_meter(parameters)
|
|
70
|
-
elif (
|
|
71
|
-
parameters[252] == EventCode.PARTY_JOINED.value
|
|
72
|
-
or parameters[252] == EventCode.PARTY_PLAYER_JOINED.value
|
|
73
|
-
or parameters[252] == EventCode.PARTY_PLAYER_LEFT.value
|
|
74
|
-
or parameters[252] == EventCode.PARTY_DISBANDED.value
|
|
75
|
-
):
|
|
76
|
-
self.update_party_member(parameters)
|
|
77
|
-
elif parameters[252] == EventCode.NEW_CHARACTER.value:
|
|
78
|
-
self.create_character(
|
|
79
|
-
id=parameters[0],
|
|
80
|
-
uuid=parameters[7],
|
|
81
|
-
username=parameters[1],
|
|
82
|
-
guild=parameters[8] if 8 in parameters else "",
|
|
83
|
-
alliance=parameters[49] if 49 in parameters else "",
|
|
84
|
-
coords=(
|
|
85
|
-
Coords(parameters[15][0], parameters[15][1])
|
|
86
|
-
if 15 in parameters
|
|
87
|
-
else Coords(0, 0)
|
|
88
|
-
),
|
|
89
|
-
equipments=parameters[38] if 38 in parameters else [],
|
|
90
|
-
)
|
|
91
|
-
...
|
|
92
|
-
|
|
93
|
-
def handle_request(self, parameters):
|
|
94
|
-
if 253 in parameters:
|
|
95
|
-
if parameters[253] == OperationCode.MOVE.value and self.me:
|
|
96
|
-
self.me.update_coords(parameters)
|
|
97
|
-
...
|
|
98
|
-
|
|
99
|
-
def end_current_dungeon(self):
|
|
100
|
-
if self.current_dungeon:
|
|
101
|
-
list_dungeon = deque()
|
|
102
|
-
|
|
103
|
-
try:
|
|
104
|
-
with open(FILENAME) as json_file:
|
|
105
|
-
list_dungeon = deque(json.load(json_file))
|
|
106
|
-
except:
|
|
107
|
-
pass
|
|
108
|
-
|
|
109
|
-
self.current_dungeon.get_elapsed_time()
|
|
110
|
-
list_dungeon.appendleft(Dungeon.serialize(self.current_dungeon))
|
|
111
|
-
|
|
112
|
-
with open(FILENAME, "w") as json_file:
|
|
113
|
-
json.dump(list(list_dungeon), json_file)
|
|
114
|
-
|
|
115
|
-
event = {
|
|
116
|
-
"type": "update_dungeon",
|
|
117
|
-
"payload": {"list_dungeon": list(list_dungeon)},
|
|
118
|
-
}
|
|
119
|
-
send_event(event)
|
|
120
|
-
self.current_dungeon = None
|
|
121
|
-
|
|
122
|
-
def start_current_dungeon(self, type, name):
|
|
123
|
-
if self.current_dungeon == None:
|
|
124
|
-
new_dungeon = Dungeon(type, name)
|
|
125
|
-
self.current_dungeon = new_dungeon
|
|
126
|
-
|
|
127
|
-
def set_dungeon_status(self, check_map, map_type_splitted):
|
|
128
|
-
if "EXPEDITION" in map_type_splitted or "DUNGEON" in map_type_splitted:
|
|
129
|
-
self.start_current_dungeon(type=check_map.type, name=check_map.name)
|
|
130
|
-
elif (
|
|
131
|
-
"EXPEDITION" not in map_type_splitted or "DUNGEON" not in map_type_splitted
|
|
132
|
-
):
|
|
133
|
-
self.end_current_dungeon()
|
|
134
|
-
return False
|
|
135
|
-
|
|
136
|
-
def set_location(self, parameters):
|
|
137
|
-
self.change_equipment_log = {}
|
|
138
|
-
|
|
139
|
-
if 1 in parameters:
|
|
140
|
-
check_map = Location.get_location_from_code(parameters[1])
|
|
141
|
-
map_type_splitted = set(check_map.type.split("_"))
|
|
142
|
-
self.set_dungeon_status(check_map, map_type_splitted)
|
|
143
|
-
|
|
144
|
-
if "ISLAND" in map_type_splitted or "HIDEOUT" in map_type_splitted:
|
|
145
|
-
check_map.name = f"{parameters[2]}'s {check_map.name}"
|
|
146
|
-
self.current_map = check_map
|
|
147
|
-
|
|
148
|
-
elif 0 in parameters:
|
|
149
|
-
check_map = Location.get_location_from_code(parameters[0])
|
|
150
|
-
map_type_splitted = set(check_map.type.split("_"))
|
|
151
|
-
is_dungeon = self.set_dungeon_status(check_map, map_type_splitted)
|
|
152
|
-
if is_dungeon == False:
|
|
153
|
-
self.current_map = Location.get_location_from_code(parameters[0])
|
|
154
|
-
|
|
155
|
-
event = {
|
|
156
|
-
"type": "update_location",
|
|
157
|
-
"payload": {
|
|
158
|
-
"map": self.current_map.name if self.current_map else "None",
|
|
159
|
-
"dungeon": (
|
|
160
|
-
self.current_dungeon.name if self.current_dungeon else "None"
|
|
161
|
-
),
|
|
162
|
-
},
|
|
163
|
-
}
|
|
164
|
-
send_event(event)
|
|
165
|
-
|
|
166
|
-
def update_party_member(self, parameters):
|
|
167
|
-
if parameters[252] == EventCode.PARTY_JOINED.value:
|
|
168
|
-
self.party_members = set(parameters[5])
|
|
169
|
-
elif parameters[252] == EventCode.PARTY_DISBANDED.value:
|
|
170
|
-
self.party_members = {self.me.username}
|
|
171
|
-
elif parameters[252] == EventCode.PARTY_PLAYER_JOINED.value:
|
|
172
|
-
self.party_members.add(parameters[2])
|
|
173
|
-
elif parameters[252] == EventCode.PARTY_PLAYER_LEFT.value:
|
|
174
|
-
uuid = UUID(bytes=bytes(parameters[1]))
|
|
175
|
-
if uuid in self.char_uuid_to_username:
|
|
176
|
-
name = self.char_uuid_to_username[uuid]
|
|
177
|
-
if name == self.me.username:
|
|
178
|
-
self.party_members = {self.me.username}
|
|
179
|
-
event = {
|
|
180
|
-
"type": "update_dps",
|
|
181
|
-
"payload": {"party_members": self.serialize_party_members()},
|
|
182
|
-
}
|
|
183
|
-
send_event(event)
|
|
184
|
-
|
|
185
|
-
def update_dps_meter(self, parameters):
|
|
186
|
-
if 6 in parameters and parameters[6] in self.char_id_to_username:
|
|
187
|
-
username = self.char_id_to_username[parameters[6]]
|
|
188
|
-
if username in self.party_members:
|
|
189
|
-
char: Character = self.characters[username]
|
|
190
|
-
char.handle_health_update(parameters)
|
|
191
|
-
event = {
|
|
192
|
-
"type": "update_dps",
|
|
193
|
-
"payload": {"party_members": self.serialize_party_members()},
|
|
194
|
-
}
|
|
195
|
-
send_event(event)
|
|
196
|
-
|
|
197
|
-
def change_character_equipment(self, parameters):
|
|
198
|
-
if 2 in parameters:
|
|
199
|
-
if parameters[0] in self.char_id_to_username:
|
|
200
|
-
if self.char_id_to_username[parameters[0]] != "not initialized":
|
|
201
|
-
char = self.characters[self.char_id_to_username[parameters[0]]]
|
|
202
|
-
if char.username in self.party_members:
|
|
203
|
-
char.update_equipment(parameters[2])
|
|
204
|
-
event = {
|
|
205
|
-
"type": "update_dps",
|
|
206
|
-
"payload": {
|
|
207
|
-
"party_members": self.serialize_party_members()
|
|
208
|
-
},
|
|
209
|
-
}
|
|
210
|
-
send_event(event)
|
|
211
|
-
else:
|
|
212
|
-
self.change_equipment_log[parameters[0]] = parameters[2]
|
|
213
|
-
|
|
214
|
-
def handle_join_response(self, parameters):
|
|
215
|
-
# set my character
|
|
216
|
-
self.convert_id_to_name(old_id=self.me.id, new_id=parameters[0], char=self.me)
|
|
217
|
-
self.me.uuid = Utils.convert_int_arr_to_uuid(parameters[1])
|
|
218
|
-
self.me.username = parameters[2]
|
|
219
|
-
self.me.guild = parameters[57] if 57 in parameters else ""
|
|
220
|
-
self.me.alliance = parameters[77] if 77 in parameters else ""
|
|
221
|
-
if self.me.id in self.change_equipment_log:
|
|
222
|
-
self.me.update_equipment(self.change_equipment_log[self.me.id])
|
|
223
|
-
|
|
224
|
-
# put self in characters list
|
|
225
|
-
self.characters[self.me.username] = self.me
|
|
226
|
-
self.char_uuid_to_username[self.me.uuid] = self.me.username
|
|
227
|
-
|
|
228
|
-
# put self in party
|
|
229
|
-
self.party_members.add(self.me.username)
|
|
230
|
-
|
|
231
|
-
# set map my character is currently in
|
|
232
|
-
if parameters[8][0] == "@":
|
|
233
|
-
area = parameters[8].split("@")
|
|
234
|
-
if area[1] == "RANDOMDUNGEON":
|
|
235
|
-
check_map = Location.get_location_from_code(area[1])
|
|
236
|
-
self.start_current_dungeon(type=check_map.type, name=check_map.name)
|
|
237
|
-
|
|
238
|
-
event_char = {
|
|
239
|
-
"type": "init_character",
|
|
240
|
-
"payload": {
|
|
241
|
-
"username": self.me.username,
|
|
242
|
-
"fame": self.me.fame_gained,
|
|
243
|
-
"re_spec": self.me.re_spec_gained,
|
|
244
|
-
"silver": self.me.silver_gained,
|
|
245
|
-
"weapon": self.me.equipment[0].image,
|
|
246
|
-
},
|
|
247
|
-
}
|
|
248
|
-
event_map = {
|
|
249
|
-
"type": "update_location",
|
|
250
|
-
"payload": {
|
|
251
|
-
"map": self.current_map.name if self.current_map else "None",
|
|
252
|
-
"dungeon": (
|
|
253
|
-
Dungeon.serialize(self.current_dungeon)
|
|
254
|
-
if self.current_dungeon
|
|
255
|
-
else None
|
|
256
|
-
),
|
|
257
|
-
},
|
|
258
|
-
}
|
|
259
|
-
event_party = {
|
|
260
|
-
"type": "update_dps",
|
|
261
|
-
"payload": {"party_members": self.serialize_party_members()},
|
|
262
|
-
}
|
|
263
|
-
send_event(event_map)
|
|
264
|
-
send_event(event_char)
|
|
265
|
-
send_event(event_party)
|
|
266
|
-
|
|
267
|
-
def convert_id_to_name(self, old_id, new_id, char: Character):
|
|
268
|
-
if old_id in self.char_id_to_username:
|
|
269
|
-
self.char_id_to_username.pop(old_id) # delete old relative id
|
|
270
|
-
char.id = new_id
|
|
271
|
-
self.char_id_to_username[char.id] = char.username # add new relative id
|
|
272
|
-
|
|
273
|
-
def create_character(
|
|
274
|
-
self,
|
|
275
|
-
id: int,
|
|
276
|
-
uuid: list[int],
|
|
277
|
-
username: str,
|
|
278
|
-
guild: str,
|
|
279
|
-
alliance: str,
|
|
280
|
-
equipments: list[str] = [],
|
|
281
|
-
coords: Coords = Coords(0, 0),
|
|
282
|
-
):
|
|
283
|
-
|
|
284
|
-
# initiate character
|
|
285
|
-
if username not in self.characters:
|
|
286
|
-
char: Character = Character(
|
|
287
|
-
id=id,
|
|
288
|
-
uuid=Utils.convert_int_arr_to_uuid(uuid),
|
|
289
|
-
username=username,
|
|
290
|
-
guild=guild,
|
|
291
|
-
alliance=alliance,
|
|
292
|
-
coords=coords,
|
|
293
|
-
)
|
|
294
|
-
char.update_equipment(equipments)
|
|
295
|
-
self.characters[char.username] = char
|
|
296
|
-
self.char_id_to_username[char.id] = char.username
|
|
297
|
-
self.char_uuid_to_username[char.uuid] = char.username
|
|
298
|
-
|
|
299
|
-
# change map
|
|
300
|
-
else:
|
|
301
|
-
char: Character = self.characters[username]
|
|
302
|
-
char.update_equipment(equipments)
|
|
303
|
-
char.coords = coords
|
|
304
|
-
self.convert_id_to_name(old_id=char.id, new_id=id, char=char)
|
|
305
|
-
|
|
306
30
|
def serialize_party_members(self):
|
|
307
31
|
serialized = []
|
|
308
32
|
|
|
@@ -332,10 +56,18 @@ class WorldData:
|
|
|
332
56
|
if total_heal > 0
|
|
333
57
|
else 0
|
|
334
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
|
+
)
|
|
335
67
|
weapon = (
|
|
336
68
|
Item.serialize(char.equipment[0])["image"]
|
|
337
69
|
if char.equipment != []
|
|
338
|
-
else "
|
|
70
|
+
else "/No Equipment.png"
|
|
339
71
|
)
|
|
340
72
|
|
|
341
73
|
# member character not initialized
|
|
@@ -345,7 +77,9 @@ class WorldData:
|
|
|
345
77
|
damage_percent = 0
|
|
346
78
|
healing_dealt = 0
|
|
347
79
|
heal_percent = 0
|
|
348
|
-
|
|
80
|
+
combat_duration = 0
|
|
81
|
+
dps = 0
|
|
82
|
+
weapon = "/No Equipment.png"
|
|
349
83
|
|
|
350
84
|
data = {
|
|
351
85
|
"username": username,
|
|
@@ -353,6 +87,8 @@ class WorldData:
|
|
|
353
87
|
"damage_percent": damage_percent,
|
|
354
88
|
"healing_dealt": healing_dealt,
|
|
355
89
|
"heal_percent": heal_percent,
|
|
90
|
+
"combat_duration": combat_duration,
|
|
91
|
+
"dps": dps,
|
|
356
92
|
"weapon": weapon,
|
|
357
93
|
}
|
|
358
94
|
serialized.append(data)
|
|
Binary file
|
|
@@ -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}
|