import encode, decode, shared import tables import os conf={} confp=os.path.expanduser('~/.config/swat.cfg') # This won't work on Windows. You'll need to tweak this to run it on Windows. Not my problem. defaults={'classes':[(1,3),(1,3),(1,3),(1,3),(1,3),(1,3),(1,3),(0,0),(0,0),(1,3),(1,3),(1,3)],'guns':[(1,3),(1,3),(1,3),(1,3),(1,3),(0,0),(0,0),(1,3)],'armour':[(1,3),(1,3),(1,3),(1,3)],'traits':[(1,3),(1,3),(1,3),(1,3),(1,3),(1,3),(1,3),(1,3),(1,3),(1,3),(1,3),(1,3),(1,3),(1,3),(1,3),(1,3)],'specs':[(1,3),(1,3),(1,3),(1,3),(1,3),(1,3),(1,3),(1,3),(1,3)],'talents':[(12,12),(1,3),(1,3),(1,3),(1,3),(1,3),(1,3)],'medals':{},'saves':{}} def add_user(name): namehash=encode.hash_name(name) # Store the hash so that if they request a different name that happens to have the same hash, it can just be stored together. if namehash in conf: conf[namehash]['names'].add(name) else: conf[namehash]=defaults.copy()|{'names':{name}} save_conf() global active_profile active_profile=namehash def parse_conf_line(line): a=line.split(' ') out=[] for n in a: b=n.split('/') out.append((int(b[0]),int(b[1]))) return out def load_conf(): if not os.path.exists(confp): return a=open(confp).read() for n in a.split('\n\n'): lines=n.split('\n') lines=list(filter(lambda x:x,lines)) if not lines: continue header=lines[0].split(' ') nhash=int(header[0]); names=set(header[1:]) # Makes deduping way easier medals={} if ':' in lines[-1]: # Since this isn't used in any other line, it's safe medals={int(n.split(':')[0]):int(n.split(':')[1]) for n in lines.pop(-1).split(' ')} stuff={k:parse_conf_line(v) for k,v in zip(tables.displays_str[:-1],lines[1:])} conf[nhash]={'names':names}|stuff|{'medals':medals} update_all_talents() global active_profile active_profile=nhash def unparse_conf_line(line): return ' '.join([str(n[0])+'/'+str(n[1]) for n in line]) def save_conf(): write='' for k,v in conf.items(): write+=' '.join([str(k)]+list(v['names']))+'\n' for n in map(lambda x:unparse_conf_line(v[x]),tables.displays_str[:-1]): write+=n+'\n' write+=' '.join(f'{h}:{m}' for h,m in v['medals'].items())+'\n' write+='\n' write=write[:-2] open(confp,'w').write(write) def update_all_talents(): for profile in conf: cl=dict(enumerate(conf[profile]['classes'])) t=defaults['talents'].copy() conf[profile]['talents']=t for n in range(1,7): t[n]=update_talent(n,cl) def update_talents(clas,profile=None): if profile is None: profile=active_profile cl=dict(enumerate(conf[profile]['classes'])) for talent in tables.clas[clas][1:]: # Don't care about courage conf[profile]['talents'][talent]=update_talent(talent,cl) def update_talent(talent,classes): a=enumerate(tables.clas); b=filter(lambda x:talent in x[1],a); c=list(map(lambda x:x[0],b)); d=filter(lambda x:x[0] in c,classes.items()); rel_classes=list(map(lambda x:x[1],d)) ranks,caps=[],[] for n in rel_classes: ranks.append(n[0]); caps.append(n[1]) ranks,caps=sorted(ranks),sorted(caps) lon=len(ranks)//2+len(ranks)%2 return (ranks[-lon],caps[-lon]) def read_code(code,name=None,save=None): if name is None: name=active_profile; save2=True else: save2=False # Don't save spoofed codes unless explicitly told if save is None: save=save2 data=list(decode.decode(code,name)) check,validator=data.pop(-1),data.pop(-1) talent=data.pop(5) hero=data[0:6] show=list(map(lambda x:x[0][x[1]],zip(tables.displays,hero))) rank,cap=data[6:8] cap=tables.cap[cap] if rank==12: cap=12 data=data[8:] if rank<9: show[-1]='Hidden' # Don't spoil the talent print(show) print(str(rank)+'/'+str(cap)) print(data) # Extract medals and save them medals=data[1:-1] if not check: print('No name given, code validation not performed') else: if check!=validator: print('code did not validate:',validator,check); return else: # Do not save medals unless validation passed if any(medals): conf[active_profile]['medals'][shared.muxhero(hero[0],hero[3],hero[4])]=shared.muxmedals(*medals) print('code validated') for thing in zip(tables.displays_str[:-1],hero): saved=conf[active_profile][thing[0]][thing[1]] saved=(max(saved[0],rank),max(saved[1],cap)) conf[active_profile][thing[0]][thing[1]]=saved update_talents(hero[0]) if not save: return save_conf() def mass_add(): a=input('>') while a: try: read_code(a,false) except: pass a=input('>') save_conf() def generate(officer=None,name=None): pro=conf[active_profile] if name is None: name=active_profile if officer is None: officer=input('> ') pieces=officer.split('/') c=pieces[0].lower() if 'mav' in c: gun=c[0] pieces[0]='mav' elif 'wm' in c: gun=c[0:2] pieces[0]='wm' else: gun='' out=[] if len(pieces)==6: rank=cap=int(pieces.pop(-1)) else: rank,cap=12,12 try: for n in zip(pieces,tables.displays_nogun,tables.displays_nogun_str): ind=lookup_piece(n[0],n[1],n[2]) rank,cap=min(rank,pro[n[2]][ind][0]),min(cap,pro[n[2]][ind][1]) if 0 in [rank,cap]: print(f"{n[0]} is locked, go unlock it first.") out.append(ind) if gun: out.insert(1,lookup_piece(gun,tables.guns,'guns',True)) else: out.insert(1,tables.gunmaps_wrapped[out[0]]) except LookupException as ex: print(ex); return rank,cap=min(rank,pro['guns'][out[1]][0]),min(cap,pro['guns'][out[1]][1]) # Derp2, forgot to actually cap on gun if 0 in [rank,cap]: return # Already warned about locks earlier. cap=(cap-(cap<10)+(cap>10))//3 # Derp try: out[-1]=tables.clas[out[0]].index(out[-1]) except ValueError: print(f"{tables.classes[out[0]]} can't get talent {tables.talent[out[-1]]}, options are {list(map(lambda x:tables.talent[x],tables.clas[out[0]]))}"); return muxed=shared.muxhero(out[0],out[3],out[4]) meds=[] if muxed in pro['medals']: meds=shared.muxmedals(pro['medals'][muxed]) return encode.encode(name,*out,rank,cap,0,*meds) def lookup_piece(piece,table,name,partial=False): if len(piece)<3: p=piece.upper() else: p=piece.capitalize() # Bloody Americans if not partial: try: return table.index(p) except ValueError: raise LookupException(f"Couldn't resolve {piece} from {name}") res=list(filter(lambda x:x.startswith(p),table)) if len(res)!=1: raise LookupException(f"Couldn't resolve {piece} with partial match from {name} (found {len(res)} possibilities)") # Ambiguous lookups not allowed return table.index(res[0]) class LookupException(Exception): pass def ranks(): for n,m in zip(tables.displays_str,tables.displays): a=zip(m,conf[active_profile][n]) for o in a: print(f'{o[0]}: {o[1][0]}/{o[1][1]}',end=', ') print() def savebuild(code,name): pass def builds(): pass def medals(): pass load_conf() if __name__=="__main__": print("Please open an interpreter and use 'import codegen', this script doesn't serve as an entrypoint on its own yet.")