Skip to content

Commit c2f095a

Browse files
committed
Merge remote-tracking branch 'origin/main' into ItemValue-Fixes
2 parents ec2c59e + 3f80906 commit c2f095a

File tree

5 files changed

+86
-30
lines changed

5 files changed

+86
-30
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22
.vscode/
33
.vs/
44
/*.code-workspace
5+
.idea

src/DataValidation.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -247,8 +247,8 @@ def preFillCheckIfEnoughItemsForValue(world: World, multiworld: MultiWorld):
247247
# compare whats available vs requested but only if there's anything requested
248248
if values_requested:
249249
errors = []
250-
existing_items = [item for item in get_items_for_player(multiworld, player, True) if item.code is not None and
251-
item.classification == ItemClassification.progression or item.classification == ItemClassification.progression_skip_balancing]
250+
existing_items = [item for item in get_items_for_player(multiworld, player, True) if
251+
item.code is not None and ItemClassification.progression in item.classification]
252252
for value, val_count in values_requested.items():
253253
items_value = get_items_with_value(world, multiworld, value, player)
254254
found_count = 0

src/ManualClient.py

Lines changed: 53 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from __future__ import annotations
22
import time
33
import sys
4-
from typing import Any
4+
from typing import Any, Optional
55
import typing
66
from worlds import AutoWorldRegister, network_data_package
77
import json
@@ -192,11 +192,11 @@ def on_package(self, cmd: str, args: dict):
192192
logger.info(f"Slot data: {args['slot_data']}")
193193

194194
self.ui.build_tracker_and_locations_table()
195-
self.ui.update_tracker_and_locations_table(update_highlights=True)
195+
self.ui.request_update_tracker_and_locations_table(update_highlights=True)
196196
elif cmd in {"ReceivedItems"}:
197-
self.ui.update_tracker_and_locations_table(update_highlights=True)
197+
self.ui.request_update_tracker_and_locations_table(update_highlights=True)
198198
elif cmd in {"RoomUpdate"}:
199-
self.ui.update_tracker_and_locations_table(update_highlights=False)
199+
self.ui.request_update_tracker_and_locations_table(update_highlights=False)
200200

201201
def on_deathlink(self, data: typing.Dict[str, typing.Any]) -> None:
202202
super().on_deathlink(data)
@@ -206,12 +206,12 @@ def on_deathlink(self, data: typing.Dict[str, typing.Any]) -> None:
206206

207207
def on_tracker_updated(self, reachable_locations: list[str]):
208208
self.tracker_reachable_locations = reachable_locations
209-
self.ui.update_tracker_and_locations_table(update_highlights=True)
209+
self.ui.request_update_tracker_and_locations_table(update_highlights=True)
210210

211211
def on_tracker_events(self, events: list[str]):
212212
self.tracker_reachable_events = events
213213
if events:
214-
self.ui.update_tracker_and_locations_table(update_highlights=True)
214+
self.ui.request_update_tracker_and_locations_table(update_highlights=True)
215215

216216
def run_gui(self):
217217
"""Import kivy UI system from make_gui() and start running it as self.ui_task."""
@@ -282,6 +282,9 @@ class ManualManager(ui):
282282
active_item_accordion = 0
283283
active_location_accordion = 0
284284

285+
update_requested_time: Optional[float] = None
286+
update_requested_highlights: bool = False
287+
285288
ctx: ManualContext
286289

287290
def __init__(self, ctx):
@@ -369,7 +372,7 @@ def update_hints(self):
369372

370373
if rebuild:
371374
self.build_tracker_and_locations_table()
372-
self.update_tracker_and_locations_table()
375+
self.request_update_tracker_and_locations_table()
373376

374377
def build_tracker_and_locations_table(self):
375378
self.tracker_and_locations_panel.clear_widgets()
@@ -438,6 +441,9 @@ def build_tracker_and_locations_table(self):
438441
if not victory_categories:
439442
victory_categories.add("(No Category)")
440443

444+
for category in self.listed_locations:
445+
self.listed_locations[category].sort(key=self.ctx.location_names.lookup_in_game)
446+
441447
items_length = len(self.ctx.items_received)
442448
tracker_panel_scrollable = TrackerLayoutScrollable(do_scroll=(False, True), bar_width=10)
443449
tracker_panel = TreeView(root_options=dict(text="Items Received (%d)" % (items_length)), size_hint_y=None)
@@ -501,6 +507,19 @@ def build_tracker_and_locations_table(self):
501507
self.tracker_and_locations_panel.add_widget(tracker_panel_scrollable)
502508
self.tracker_and_locations_panel.add_widget(locations_panel_scrollable)
503509

510+
def check_for_requested_update(self):
511+
current_time = time.time()
512+
513+
# wait 0.25 seconds before executing update, in case there are multiple update requests coming in
514+
if self.update_requested_time and current_time - self.update_requested_time >= 0.25:
515+
self.update_requested_time = None
516+
self.update_tracker_and_locations_table(self.update_requested_highlights)
517+
self.update_requested_highlights = False
518+
519+
def request_update_tracker_and_locations_table(self, update_highlights=False):
520+
self.update_requested_time = time.time()
521+
self.update_requested_highlights = update_highlights or self.update_requested_highlights # if any of the requests wanted highlights, do highlight
522+
504523
def update_tracker_and_locations_table(self, update_highlights=False):
505524
items_length = len(self.ctx.items_received)
506525
locations_length = len(self.ctx.missing_locations)
@@ -532,7 +551,10 @@ def update_tracker_and_locations_table(self, update_highlights=False):
532551
category_count = 0
533552
category_unique_name_count = 0
534553

535-
# Label (for existing item listings)
554+
existing_item_labels = []
555+
bold_item_labels = []
556+
557+
# for items that were already listed, determine if the qty changed. if it did, add them to the list to be bolded
536558
for item in category_grid.children:
537559
if type(item) is Label:
538560
# Get the item name from the item Label, minus quantity, then do a lookup for count
@@ -544,28 +566,37 @@ def update_tracker_and_locations_table(self, update_highlights=False):
544566
# Update the label quantity
545567
item.text="%s (%s)" % (item_name, item_count)
546568

547-
if update_highlights:
548-
item.bold = True if old_item_text != item.text else False
569+
if update_highlights and (old_item_text != item.text):
570+
bold_item_labels.append(item_name)
571+
572+
existing_item_labels.append(item_name)
573+
574+
# instead of reusing existing item listings, clear it all out and re-draw with the sorted list
575+
category_grid.clear_widgets()
576+
self.listed_items[category_name].clear()
549577

550-
if item_count > 0:
551-
category_count += item_count
552-
category_unique_name_count += 1
578+
# Label (for all item listings)
579+
sorted_items_received = sorted([
580+
i.item for i in self.ctx.items_received
581+
], key=self.ctx.item_names.lookup_in_game)
553582

554-
# Label (for new item listings)
555-
for network_item in self.ctx.items_received:
556-
item_name = self.ctx.item_names.lookup_in_game(network_item.item)
583+
for network_item in sorted_items_received:
584+
item_name = self.ctx.item_names.lookup_in_game(network_item)
557585
item_data = self.ctx.get_item_by_name(item_name)
558586

559587
if "category" not in item_data or not item_data["category"]:
560588
item_data["category"] = ["(No Category)"]
561589

562-
if category_name in item_data["category"] and network_item.item not in self.listed_items[category_name]:
563-
item_count = len(list(i for i in self.ctx.items_received if i.item == network_item.item))
590+
if category_name in item_data["category"] and network_item not in self.listed_items[category_name]:
591+
item_count = len(list(i for i in self.ctx.items_received if i.item == network_item))
564592
item_text = Label(text="%s (%s)" % (item_name, item_count),
565593
size_hint=(None, None), height=30, width=400, bold=True)
566594

595+
# if the item was previously listed and was bold, or if it wasn't previously listed at all, make it bold
596+
item_text.bold = (update_highlights and (item_name in bold_item_labels or item_name not in existing_item_labels))
597+
567598
category_grid.add_widget(item_text)
568-
self.listed_items[category_name].append(network_item.item)
599+
self.listed_items[category_name].append(network_item)
569600

570601
category_count += item_count
571602
category_unique_name_count += 1
@@ -687,6 +718,9 @@ def victory_button_callback(self, button):
687718

688719
async def game_watcher_manual(ctx: ManualContext):
689720
while not ctx.exit_event.is_set():
721+
if ctx.ui:
722+
ctx.ui.check_for_requested_update()
723+
690724
if ctx.syncing == True:
691725
sync_msg = [{'cmd': 'Sync'}]
692726
if ctx.locations_checked:

src/__init__.py

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import os
44
import json
55
from typing import Callable, Optional
6+
import webbrowser
67

78
import requests
89
import Utils
@@ -66,6 +67,9 @@ class ManualWorld(World):
6667
location_name_groups = location_name_groups
6768
victory_names = victory_names
6869

70+
# UT (the universal-est of trackers) can now generate without a YAML
71+
ut_can_gen_without_yaml = True
72+
6973
def get_filler_item_name(self) -> str:
7074
return hook_get_filler_item_name(self, self.multiworld, self.player) or self.filler_item_name
7175

@@ -211,16 +215,15 @@ def create_item(self, name: str) -> Item:
211215
classification = ItemClassification.filler
212216

213217
if "trap" in item and item["trap"]:
214-
classification = ItemClassification.trap
218+
classification |= ItemClassification.trap
215219

216220
if "useful" in item and item["useful"]:
217-
classification = ItemClassification.useful
218-
219-
if "progression" in item and item["progression"]:
220-
classification = ItemClassification.progression
221+
classification |= ItemClassification.useful
221222

222223
if "progression_skip_balancing" in item and item["progression_skip_balancing"]:
223-
classification = ItemClassification.progression_skip_balancing
224+
classification |= ItemClassification.progression_skip_balancing
225+
elif "progression" in item and item["progression"]:
226+
classification |= ItemClassification.progression
224227

225228
item_object = ManualItem(name, classification,
226229
self.item_name_to_id[name], player=self.player)
@@ -384,12 +387,21 @@ def adjust_filler_items(self, item_pool, traps):
384387
item_pool.append(extra_item)
385388
elif extras < 0:
386389
logging.warning(f"{self.game} has more items than locations. {abs(extras)} non-progression items will be removed at random.")
390+
# Filler is only assigned if the item doesn't have any other tags, so it only has to be covered by itself.
391+
# Skip Balancing is also not covered due to how it's only supported when paired with Progression.
392+
# As a result, these cover every possible combination can be removed.
387393
fillers = [item for item in item_pool if item.classification == ItemClassification.filler]
388394
traps = [item for item in item_pool if item.classification == ItemClassification.trap]
389395
useful = [item for item in item_pool if item.classification == ItemClassification.useful]
396+
# Useful + Trap is classified separately so that it can have a unique priority ranking.
397+
useful_traps = [item for item in item_pool if
398+
ItemClassification.progression not in item.classification
399+
and ItemClassification.useful in item.classification
400+
and ItemClassification.trap in item.classification]
390401
self.random.shuffle(fillers)
391402
self.random.shuffle(traps)
392403
self.random.shuffle(useful)
404+
self.random.shuffle(useful_traps)
393405
for _ in range(0, abs(extras)):
394406
popped = None
395407
if fillers:
@@ -398,6 +410,8 @@ def adjust_filler_items(self, item_pool, traps):
398410
popped = traps.pop()
399411
elif useful:
400412
popped = useful.pop()
413+
elif useful_traps:
414+
popped = useful_traps.pop()
401415
else:
402416
logging.warning("Could not remove enough non-progression items from the pool.")
403417
break
@@ -446,7 +460,7 @@ def __init__(self, display_name: str, script_name: Optional[str] = None, func: O
446460
self.version = version
447461

448462
def add_client_to_launcher() -> None:
449-
version = 2024_11_03 # YYYYMMDD
463+
version = 2024_11_22 # YYYYMMDD
450464
found = False
451465

452466
if "manual" not in icon_paths:
@@ -456,15 +470,21 @@ def add_client_to_launcher() -> None:
456470
with open(icon_paths["manual"], 'wb') as f:
457471
f.write(requests.get(icon_url).content)
458472

473+
discord_component = None
459474
for c in components:
460475
if c.display_name == "Manual Client":
461476
found = True
462477
if getattr(c, "version", 0) < version: # We have a newer version of the Manual Client than the one the last apworld added
463478
c.version = version
464479
c.func = launch_client
465480
c.icon = "manual"
466-
return
481+
elif c.display_name == "Manual Discord Server":
482+
discord_component = c
483+
467484
if not found:
468485
components.append(VersionedComponent("Manual Client", "ManualClient", func=launch_client, version=version, file_identifier=SuffixIdentifier('.apmanual'), icon="manual"))
486+
if not discord_component:
487+
components.append(Component("Manual Discord Server", "ManualDiscord", func=lambda: webbrowser.open("https://discord.gg/hm4rQnTzQ5"), icon="discord", component_type=Type.ADJUSTER))
488+
469489

470490
add_client_to_launcher()

src/data/game.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,6 @@
2828
"yaml_option": ["start_with_deadpool"]
2929
}
3030
],
31-
"death_link": false
31+
"death_link": false,
32+
"starting_index": 1
3233
}

0 commit comments

Comments
 (0)