@@ -78,7 +78,7 @@ def __init__(self, host: str, port: int, server_password: str, password: str, lo
78
78
self .connect_names = {} # names of slots clients can connect to
79
79
self .allow_forfeits = {}
80
80
self .remote_items = set ()
81
- self .locations = {}
81
+ self .locations : typing . Dict [ int , typing . Dict [ int , typing . Tuple [ int , int ]]] = {}
82
82
self .host = host
83
83
self .port = port
84
84
self .server_password = server_password
@@ -114,6 +114,11 @@ def __init__(self, host: str, port: int, server_password: str, password: str, lo
114
114
self .minimum_client_versions : typing .Dict [int , Utils .Version ] = {}
115
115
self .seed_name = ""
116
116
117
+ def get_hint_cost (self , slot ):
118
+ if self .hint_cost :
119
+ return max (0 , int (self .hint_cost * 0.01 * len (self .locations [slot ])))
120
+ return 0
121
+
117
122
def load (self , multidatapath : str , use_embedded_server_options : bool = False ):
118
123
with open (multidatapath , 'rb' ) as f :
119
124
data = f .read ()
@@ -132,7 +137,7 @@ def _load(self, decoded_obj: dict, use_embedded_server_options: bool):
132
137
133
138
mdata_ver = decoded_obj ["minimum_versions" ]["server" ]
134
139
if mdata_ver > Utils ._version_tuple :
135
- raise RuntimeError (f"Supplied Multidata requires a server of at least version { mdata_ver } ,"
140
+ raise RuntimeError (f"Supplied Multidata (.archipelago) requires a server of at least version { mdata_ver } ,"
136
141
f"however this server is of version { Utils ._version_tuple } " )
137
142
clients_ver = decoded_obj ["minimum_versions" ].get ("clients" , {})
138
143
self .minimum_client_versions = {}
@@ -437,10 +442,6 @@ def get_received_items(ctx: Context, team: int, player: int) -> typing.List[Netw
437
442
return ctx .received_items .setdefault ((team , player ), [])
438
443
439
444
440
- def tuplize_received_items (items ):
441
- return [NetworkItem (item .item , item .location , item .player ) for item in items ]
442
-
443
-
444
445
def send_new_items (ctx : Context ):
445
446
for client in ctx .endpoints :
446
447
if client .auth : # can't send to disconnected client
@@ -449,22 +450,22 @@ def send_new_items(ctx: Context):
449
450
asyncio .create_task (ctx .send_msgs (client , [{
450
451
"cmd" : "ReceivedItems" ,
451
452
"index" : client .send_index ,
452
- "items" : tuplize_received_items ( items ) [client .send_index :]}]))
453
+ "items" : items [client .send_index :]}]))
453
454
client .send_index = len (items )
454
455
455
456
456
457
def forfeit_player (ctx : Context , team : int , slot : int ):
457
458
# register any locations that are in the multidata
458
- all_locations = { location_id for location_id , location_slot in ctx .locations if location_slot == slot }
459
+ all_locations = set ( ctx .locations [ slot ])
459
460
ctx .notify_all ("%s (Team #%d) has forfeited" % (ctx .player_names [(team , slot )], team + 1 ))
460
461
register_location_checks (ctx , team , slot , all_locations )
461
462
462
463
463
464
def get_remaining (ctx : Context , team : int , slot : int ) -> typing .List [int ]:
464
465
items = []
465
- for ( location , location_slot ) in ctx .locations :
466
- if location_slot == slot and location not in ctx .location_checks [team , slot ]:
467
- items .append (ctx .locations [location , slot ][0 ]) # item ID
466
+ for location_id in ctx .locations [ slot ] :
467
+ if location_id not in ctx .location_checks [team , slot ]:
468
+ items .append (ctx .locations [slot ][ location_id ][0 ]) # item ID
468
469
return sorted (items )
469
470
470
471
@@ -473,8 +474,8 @@ def register_location_checks(ctx: Context, team: int, slot: int, locations: typi
473
474
if new_locations :
474
475
ctx .client_activity_timers [team , slot ] = datetime .datetime .now (datetime .timezone .utc )
475
476
for location in new_locations :
476
- if ( location , slot ) in ctx .locations :
477
- item_id , target_player = ctx .locations [( location , slot ) ]
477
+ if location in ctx .locations [ slot ] :
478
+ item_id , target_player = ctx .locations [slot ][ location ]
478
479
new_item = NetworkItem (item_id , location , slot )
479
480
if target_player != slot or slot in ctx .remote_items :
480
481
get_received_items (ctx , team , target_player ).append (new_item )
@@ -504,29 +505,26 @@ def notify_team(ctx: Context, team: int, text: str):
504
505
def collect_hints (ctx : Context , team : int , slot : int , item : str ) -> typing .List [NetUtils .Hint ]:
505
506
hints = []
506
507
seeked_item_id = lookup_any_item_name_to_id [item ]
507
- for check , result in ctx .locations .items ():
508
- item_id , receiving_player = result
509
- if receiving_player == slot and item_id == seeked_item_id :
510
- location_id , finding_player = check
511
- found = location_id in ctx .location_checks [team , finding_player ]
512
- entrance = ctx .er_hint_data .get (finding_player , {}).get (location_id , "" )
513
- hints .append (NetUtils .Hint (receiving_player , finding_player , location_id , item_id , found , entrance ))
508
+ for finding_player , check_data in ctx .locations .items ():
509
+ for location_id , result in check_data . items ():
510
+ item_id , receiving_player = result
511
+ if receiving_player == slot and item_id == seeked_item_id :
512
+ found = location_id in ctx .location_checks [team , finding_player ]
513
+ entrance = ctx .er_hint_data .get (finding_player , {}).get (location_id , "" )
514
+ hints .append (NetUtils .Hint (receiving_player , finding_player , location_id , item_id , found , entrance ))
514
515
515
516
return hints
516
517
517
518
518
519
def collect_hints_location (ctx : Context , team : int , slot : int , location : str ) -> typing .List [NetUtils .Hint ]:
519
- hints = []
520
- seeked_location = Regions .lookup_name_to_id [location ]
521
- for check , result in ctx .locations .items ():
522
- location_id , finding_player = check
523
- if finding_player == slot and location_id == seeked_location :
524
- item_id , receiving_player = result
525
- found = location_id in ctx .location_checks [team , finding_player ]
526
- entrance = ctx .er_hint_data .get (finding_player , {}).get (location_id , "" )
527
- hints .append (NetUtils .Hint (receiving_player , finding_player , location_id , item_id , found , entrance ))
528
- break # each location has 1 item
529
- return hints
520
+
521
+ seeked_location : int = Regions .lookup_name_to_id [location ]
522
+ item_id , receiving_player = ctx .locations [slot ].get (seeked_location , (None , None ))
523
+ if item_id :
524
+ found = seeked_location in ctx .location_checks [team , slot ]
525
+ entrance = ctx .er_hint_data .get (slot , {}).get (seeked_location , "" )
526
+ return [NetUtils .Hint (receiving_player , slot , seeked_location , item_id , found , entrance )]
527
+ return []
530
528
531
529
532
530
def format_hint (ctx : Context , team : int , hint : NetUtils .Hint ) -> str :
@@ -864,7 +862,7 @@ def _cmd_hint(self, item_or_location: str = "") -> bool:
864
862
"""Use !hint {item_name/location_name}, for example !hint Lamp or !hint Link's House. """
865
863
points_available = get_client_points (self .ctx , self .client )
866
864
if not item_or_location :
867
- self .output (f"A hint costs { self .ctx .hint_cost } points. "
865
+ self .output (f"A hint costs { self .ctx .get_hint_cost ( self . client . slot ) } points. "
868
866
f"You have { points_available } points." )
869
867
hints = {hint .re_check (self .ctx , self .client .team ) for hint in
870
868
self .ctx .hints [self .client .team , self .client .slot ]}
@@ -885,7 +883,7 @@ def _cmd_hint(self, item_or_location: str = "") -> bool:
885
883
hints = collect_hints (self .ctx , self .client .team , self .client .slot , item_name )
886
884
else : # location name
887
885
hints = collect_hints_location (self .ctx , self .client .team , self .client .slot , item_name )
888
-
886
+ cost = self . ctx . get_hint_cost ( self . client . slot )
889
887
if hints :
890
888
new_hints = set (hints ) - self .ctx .hints [self .client .team , self .client .slot ]
891
889
old_hints = set (hints ) - new_hints
@@ -899,8 +897,8 @@ def _cmd_hint(self, item_or_location: str = "") -> bool:
899
897
900
898
if not not_found_hints : # everything's been found, no need to pay
901
899
can_pay = 1000
902
- elif self . ctx . hint_cost :
903
- can_pay = points_available // self . ctx . hint_cost
900
+ elif cost :
901
+ can_pay = points_available // cost
904
902
else :
905
903
can_pay = 1000
906
904
@@ -926,7 +924,7 @@ def _cmd_hint(self, item_or_location: str = "") -> bool:
926
924
else :
927
925
self .output (f"You can't afford the hint. "
928
926
f"You have { points_available } points and need at least "
929
- f"{ self .ctx .hint_cost } " )
927
+ f"{ self .ctx .get_hint_cost ( self . client . slot ) } " )
930
928
notify_hints (self .ctx , self .client .team , hints )
931
929
self .ctx .save ()
932
930
return True
@@ -941,21 +939,19 @@ def _cmd_hint(self, item_or_location: str = "") -> bool:
941
939
942
940
def get_checked_checks (ctx : Context , client : Client ) -> typing .List [int ]:
943
941
return [location_id for
944
- location_id , slot in ctx .locations if
945
- slot == client .slot and
942
+ location_id in ctx .locations [client .slot ] if
946
943
location_id in ctx .location_checks [client .team , client .slot ]]
947
944
948
945
949
946
def get_missing_checks (ctx : Context , client : Client ) -> typing .List [int ]:
950
947
return [location_id for
951
- location_id , slot in ctx .locations if
952
- slot == client .slot and
948
+ location_id in ctx .locations [client .slot ] if
953
949
location_id not in ctx .location_checks [client .team , client .slot ]]
954
950
955
951
956
952
def get_client_points (ctx : Context , client : Client ) -> int :
957
953
return (ctx .location_check_points * len (ctx .location_checks [client .team , client .slot ]) -
958
- ctx .hint_cost * ctx .hints_used [client .team , client .slot ])
954
+ ctx .get_hint_cost ( client . slot ) * ctx .hints_used [client .team , client .slot ])
959
955
960
956
961
957
async def process_client_cmd (ctx : Context , client : Client , args : dict ):
@@ -1032,7 +1028,7 @@ async def process_client_cmd(ctx: Context, client: Client, args: dict):
1032
1028
}]
1033
1029
items = get_received_items (ctx , client .team , client .slot )
1034
1030
if items :
1035
- reply .append ({"cmd" : 'ReceivedItems' , "index" : 0 , "items" : tuplize_received_items ( items ) })
1031
+ reply .append ({"cmd" : 'ReceivedItems' , "index" : 0 , "items" : items })
1036
1032
client .send_index = len (items )
1037
1033
1038
1034
await ctx .send_msgs (client , reply )
@@ -1047,7 +1043,7 @@ async def process_client_cmd(ctx: Context, client: Client, args: dict):
1047
1043
if items :
1048
1044
client .send_index = len (items )
1049
1045
await ctx .send_msgs (client , [{"cmd" : "ReceivedItems" ,"index" : 0 ,
1050
- "items" : tuplize_received_items ( items ) }])
1046
+ "items" : items }])
1051
1047
1052
1048
elif cmd == 'LocationChecks' :
1053
1049
register_location_checks (ctx , client .team , client .slot , args ["locations" ])
@@ -1058,7 +1054,7 @@ async def process_client_cmd(ctx: Context, client: Client, args: dict):
1058
1054
if type (location ) is not int or location not in lookup_any_location_id_to_name :
1059
1055
await ctx .send_msgs (client , [{"cmd" : "InvalidArguments" , "text" : 'LocationScouts' }])
1060
1056
return
1061
- target_item , target_player = ctx .locations [location , client .slot ]
1057
+ target_item , target_player = ctx .locations [client .slot ][ location ]
1062
1058
locs .append (NetworkItem (target_item , location , target_player ))
1063
1059
1064
1060
await ctx .send_msgs (client , [{'cmd' : 'LocationInfo' , 'locations' : locs }])
@@ -1206,7 +1202,7 @@ def _cmd_send(self, player_name: str, *item_name: str) -> bool:
1206
1202
if usable :
1207
1203
for client in self .ctx .endpoints :
1208
1204
if client .name == seeked_player :
1209
- new_item = NetworkItem (lookup_any_item_name_to_id [item ], - 1 , client . slot )
1205
+ new_item = NetworkItem (lookup_any_item_name_to_id [item ], - 1 , 0 )
1210
1206
get_received_items (self .ctx , client .team , client .slot ).append (new_item )
1211
1207
self .ctx .notify_all ('Cheat console: sending "' + item + '" to ' +
1212
1208
self .ctx .get_aliased_name (client .team , client .slot ))
0 commit comments