Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- """
- Sims 4 Unify Hair Makeup Tattoos
- by Lynire @ modthesims.info
- Much of this is from Sims 4 Outfit Tools by Scumbumbo @ ModTheSims
- This copies hair, makeup and/or tattoos from everyday outfit 1 to all the other outfits.
- Much thanks to rekees @ ModTheSims for figuring out how to fix the issue of it duplicating outfit clothes
- to other slots in the same category on some sims.
- """
- import sims4.commands
- import services
- import sims.sim_info
- import enum
- from sims.outfits.outfit_enums import OutfitCategory
- from protocolbuffers import Outfits_pb2, S4Common_pb2
- def unifyhmt_usage(output):
- output("This copies the hair, makeup and/or tattoos from everyday outfit 1 to all the other outfits.")
- output("This only applies to outfits that already exist. Those that don't exist can't be used and are skipped.")
- output("usage: unifyhmt [SimFirstName SimLastName] [h|hair] [m|makeup] [t|tattoos]")
- output("If the sim name is omitted, then the current sim is used.")
- def outfit_get_category(outfit_type):
- if outfit_type=="e" or outfit_type=="everyday":
- return OutfitCategory.EVERYDAY
- elif outfit_type=="f" or outfit_type=="formal":
- return OutfitCategory.FORMAL
- elif outfit_type=="a" or outfit_type=="athletic":
- return OutfitCategory.ATHLETIC
- elif outfit_type=="sl" or outfit_type=="sleep":
- return OutfitCategory.SLEEP
- elif outfit_type=="p" or outfit_type=="party":
- return OutfitCategory.PARTY
- elif outfit_type=="c" or outfit_type=="career":
- return OutfitCategory.CAREER
- elif outfit_type=="b" or outfit_type=="bathing":
- return OutfitCategory.BATHING
- elif outfit_type=="sw" or outfit_type=="swimwear":
- return OutfitCategory.SWIMWEAR
- elif outfit_type=="si" or outfit_type=="situation":
- return OutfitCategory.SITUATION
- elif outfit_type=="sp" or outfit_type=="special":
- return OutfitCategory.SPECIAL
- elif outfit_type=="ho" or outfit_type=="Hot Weather":
- return OutfitCategory.HOTWEATHER
- elif outfit_type=="co" or outfit_type=="Cold Weather":
- return OutfitCategory.COLDWEATHER
- else:
- return None
- def outfit_get_name(outfit_category):
- if outfit_category == OutfitCategory.EVERYDAY:
- return 'Everyday'
- elif outfit_category == OutfitCategory.FORMAL:
- return 'Formal'
- elif outfit_category == OutfitCategory.ATHLETIC:
- return 'Athletic'
- elif outfit_category == OutfitCategory.SLEEP:
- return 'Sleep'
- elif outfit_category == OutfitCategory.PARTY:
- return 'Party'
- elif outfit_category == OutfitCategory.BATHING:
- return 'Bathing'
- elif outfit_category == OutfitCategory.CAREER:
- return 'Career'
- elif outfit_category == OutfitCategory.SITUATION:
- return 'Situation'
- elif outfit_category == OutfitCategory.SPECIAL:
- return 'Special'
- elif outfit_category == OutfitCategory.SWIMWEAR:
- return 'Swimwear'
- elif outfit_category == OutfitCategory.HOTWEATHER:
- return 'Hot Weather'
- elif outfit_category == OutfitCategory.COLDWEATHER:
- return 'Cold Weather'
- return "unknown category"
- def outfit_copy_parts(src_outfit,dest_outfit_body_types,dest_outfit_part_ids,body_types):
- # Look at each body type in the body_types list and see if it needs to be copied,added or removed
- for body_type in body_types:
- src_idx=-1
- dest_idx=-1
- for idx in range(len(src_outfit.body_types)):
- if src_outfit.body_types[idx]==body_type:
- src_idx=idx
- break
- for idx in range(len(dest_outfit_body_types)):
- if dest_outfit_body_types[idx]==body_type:
- dest_idx=idx
- break
- if src_idx==-1:
- if dest_idx!=-1:
- # Part is in destination but not source outfit, remove it
- del dest_outfit_body_types[dest_idx]
- del dest_outfit_part_ids[dest_idx]
- elif dest_idx!=-1:
- # Part is in both source and destination, copy it
- dest_outfit_part_ids[dest_idx]=src_outfit.part_ids[src_idx]
- else:
- # Part is in source but not destination outfit, add it
- dest_outfit_body_types.append(body_type)
- dest_outfit_part_ids.append(src_outfit.part_ids[src_idx])
- def DoCopy(SimInfo,src_category,src_slot,dest_category,dest_slot,include_hair,include_makeup,include_tattoos,output):
- if not SimInfo.has_outfit((src_category,src_slot)):
- output('Error: {} {} does not have an outfit in {} slot {}.'.format(SimInfo.first_name,SimInfo.last_name,outfit_get_name(src_category),src_num+1))
- return False
- if not SimInfo.has_outfit((dest_category,dest_slot)):
- return False
- # List of body_type locations (see list at end for all locations)
- hair_items=[2,28,34]
- makeup_items=[29,30,31,32,33,37]
- tattoo_items=[45,46,47,48,49,50,51,52,53,54]
- src_outfit=SimInfo.get_outfit(src_category,src_slot)
- dest_outfit=SimInfo.get_outfit(dest_category,dest_slot)
- copy_items=[]
- items_label=""
- if include_hair:
- copy_items+=hair_items
- items_label+="hair"
- if include_makeup:
- copy_items+=makeup_items
- if items_label:
- items_label+=", "
- items_label+="makeup"
- if include_tattoos:
- copy_items+=tattoo_items
- if items_label:
- items_label+=", "
- items_label+="tattoos"
- output("Copying {} {}'s {} outfit {} {} to {} outfit {}.".format(SimInfo.first_name,SimInfo.last_name,outfit_get_name(src_category),src_slot+1,items_label,outfit_get_name(dest_category),dest_slot+1))
- # Method for writing outfits back to sim_info based upon the work of Deaderpool
- outfits_msg=Outfits_pb2.OutfitList()
- outfits_msg.ParseFromString(SimInfo._base.outfits)
- for outfit in outfits_msg.outfits:
- if outfit.outfit_id==dest_outfit.outfit_id:
- dest_outfit_part_ids=list(outfit.parts.ids)
- dest_outfit_body_types=list(outfit.body_types_list.body_types)
- outfit_copy_parts(src_outfit,dest_outfit_body_types,dest_outfit_part_ids,copy_items)
- outfit.parts=S4Common_pb2.IdList()
- outfit.parts.ids.extend(dest_outfit_part_ids)
- outfit.body_types_list=Outfits_pb2.BodyTypesList()
- outfit.body_types_list.body_types.extend(dest_outfit_body_types)
- SimInfo._base.outfits=outfits_msg.SerializeToString()
- # Resend the outfit info to the game
- SimInfo.resend_outfits()
- return True
- @sims4.commands.Command('unifyhmt', command_type=sims4.commands.CommandType.Live)
- def unifyhmt(*args,_connection=None):
- output=sims4.commands.CheatOutput(_connection)
- argc=len(args)
- if argc<1 or argc>5:
- unifyhmt_usage(output)
- return false
- include_hair=False
- include_makeup=False
- include_tattoos=False
- SimFirstName=""
- SimLastName=""
- if argc>3:
- for i in range(2,argc):
- if args[i]=="hair" or args[i]=="h":
- include_hair=True
- elif args[i]=="makeup" or args[i]=="m":
- include_makeup=True
- elif args[i]=="tattoos" or args[i]=="t":
- include_tattoos=True
- else:
- unifyhmt_usage(output)
- return False
- SimFirstName=args[0]
- SimLastName=args[1]
- elif argc==3:
- if args[2]=="hair" or args[2]=="h":
- include_hair=True
- elif args[2]=="makeup" or args[2]=="m":
- include_makeup=True
- elif args[2]=="tattoos" or args[2]=="t":
- include_tattoos=True
- else:
- unifyhmt_usage(output)
- return False
- if include_hair or include_makeup or include_tattoos:
- TrueCount=1
- else:
- TrueCount=0
- for i in range(2):
- if args[i]=="hair" or args[i]=="h":
- include_hair=True
- TrueCount+=1
- elif args[i]=="makeup" or args[i]=="m":
- include_makeup=True
- TrueCount+=1
- elif args[i]=="tattoos" or args[i]=="t":
- include_tattoos=True
- TrueCount+=1
- if TrueCount==1:
- SimFirstName=args[0]
- SimLastName=args[1]
- elif TrueCount==2 or TrueCount==0:
- unifyhmt_usage(output)
- return False
- else:
- for i in range(argc):
- if args[i]=="hair" or args[i]=="h":
- include_hair=True
- elif args[i]=="makeup" or args[i]=="m":
- include_makeup=True
- elif args[i]=="tattoos" or args[i]=="t":
- include_tattoos=True
- else:
- unifyhmt_usage(output)
- return False
- # Get the sim info.
- if SimFirstName and SimLastName:
- SimInfo=services.sim_info_manager().get_sim_info_by_name(SimFirstName,SimLastName)
- if SimInfo is None:
- output('Error: No sim named {} {} was found.'.format(SimFirstName,SimLastName))
- return False
- else:
- tgt_client=services.client_manager().get(_connection)
- if tgt_client is None:
- output("Error: No sim is selected.")
- return False
- SimInfo=tgt_client.active_sim.sim_info
- src_category=outfit_get_category('e')
- CurrentOutfitCategory=SimInfo._current_outfit[0]
- CurrentOutfitSlot=SimInfo._current_outfit[1]
- for outfit_type in ['e','f','a','sl','p','c','b','sw','si','sp']:
- for slot in range(5):
- dest_category=outfit_get_category(outfit_type)
- if outfit_type=='e' and slot==0: continue
- DoCopy(SimInfo,src_category,0,dest_category,slot,include_hair,include_makeup,include_tattoos,output)
- if CurrentOutfitSlot<0:
- output("Unable to determine the current outfit.")
- else:
- if CurrentOutfitCategory==OutfitCategory.BATHING:
- SimInfo.set_current_outfit((OutfitCategory.EVERYDAY,0))
- else:
- SimInfo.set_current_outfit((OutfitCategory.BATHING,0))
- SimInfo.set_current_outfit((CurrentOutfitCategory,CurrentOutfitSlot))
- output("{} {}'s currently wearing {} outfit {}.".format(SimInfo.first_name,SimInfo.last_name,outfit_get_name(CurrentOutfitCategory),CurrentOutfitSlot+1))
- return True
- """
- This is a list of all body type locations from outfit_enums.py:
- NONE=0
- HAT=1
- HAIR=2
- HEAD=3
- TEETH=4
- FULL_BODY=5
- UPPER_BODY=6
- LOWER_BODY=7
- SHOES=8
- CUMMERBUND=9
- EARRINGS=10
- GLASSES=11
- NECKLACE=12
- GLOVES=13
- WRIST_LEFT=14
- WRIST_RIGHT=15
- LIP_RING_LEFT=16
- LIP_RING_RIGHT=17
- NOSE_RING_LEFT=18
- NOSE_RING_RIGHT=19
- BROW_RING_LEFT=20
- BROW_RING_RIGHT=21
- INDEX_FINGER_LEFT=22
- INDEX_FINGER_RIGHT=23
- RING_FINGER_LEFT=24
- RING_FINGER_RIGHT=25
- MIDDLE_FINGER_LEFT=26
- MIDDLE_FINGER_RIGHT=27
- FACIAL_HAIR=28
- LIPS_TICK=29
- EYE_SHADOW=30
- EYE_LINER=31
- BLUSH=32
- FACEPAINT=33
- EYEBROWS=34
- EYECOLOR=35
- SOCKS=36
- MASCARA=37
- SKINDETAIL_CREASE_FOREHEAD=38
- SKINDETAIL_FRECKLES=39
- SKINDETAIL_DIMPLE_LEFT=40
- SKINDETAIL_DIMPLE_RIGHT=41
- TIGHTS=42
- SKINDETAIL_MOLE_LIP_LEFT=43
- SKINDETAIL_MOLE_LIP_RIGHT=44
- TATTOO_ARM_LOWER_LEFT=45
- TATTOO_ARM_UPPER_LEFT=46
- TATTOO_ARM_LOWER_RIGHT=47
- TATTOO_ARM_UPPER_RIGHT=48
- TATTOO_LEG_LEFT=49
- TATTOO_LEG_RIGHT=50
- TATTOO_TORSO_BACK_LOWER=51
- TATTOO_TORSO_BACK_UPPER=52
- TATTOO_TORSO_FRONT_LOWER=53
- TATTOO_TORSO_FRONT_UPPER=54
- SKINDETAIL_MOLE_CHEEK_LEFT=55
- SKINDETAIL_MOLE_CHEEK_RIGHT=56
- SKINDETAIL_CREASE_MOUTH=57
- SKIN_OVERLAY=58
- FUR_BODY=59
- EARS=60
- TAIL=61
- SKINDETAIL_NOSE_COLOR=62
- EYECOLOR_SECONDARY=63
- OCCULT_BROW=64
- OCCULT_EYE_SOCKET=65
- OCCULT_EYE_LID=66
- OCCULT_MOUTH=67
- OCCULT_LEFT_CHEEK=68
- OCCULT_RIGHT_CHEEK=69
- OCCULT_NECK_SCAR=70
- FOREARM_SCAR=71
- ACNE=72
- """
Add Comment
Please, Sign In to add comment