PastebinnerMKII

Unify Hair, Makeup and/or Tattoos

Dec 8th, 2020
125
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 11.76 KB | None | 0 0
  1. """
  2. Sims 4 Unify Hair Makeup Tattoos
  3. by Lynire @ modthesims.info
  4. Much of this is from Sims 4 Outfit Tools by Scumbumbo @ ModTheSims
  5. This copies hair, makeup and/or tattoos from everyday outfit 1 to all the other outfits.
  6. Much thanks to rekees @ ModTheSims for figuring out how to fix the issue of it duplicating outfit clothes
  7. to other slots in the same category on some sims.
  8. """
  9. import sims4.commands
  10. import services
  11. import sims.sim_info
  12. import enum
  13. from sims.outfits.outfit_enums import OutfitCategory
  14. from protocolbuffers import Outfits_pb2, S4Common_pb2
  15.  
  16. def unifyhmt_usage(output):
  17. output("This copies the hair, makeup and/or tattoos from everyday outfit 1 to all the other outfits.")
  18. output("This only applies to outfits that already exist. Those that don't exist can't be used and are skipped.")
  19. output("usage: unifyhmt [SimFirstName SimLastName] [h|hair] [m|makeup] [t|tattoos]")
  20. output("If the sim name is omitted, then the current sim is used.")
  21.  
  22. def outfit_get_category(outfit_type):
  23. if outfit_type=="e" or outfit_type=="everyday":
  24. return OutfitCategory.EVERYDAY
  25. elif outfit_type=="f" or outfit_type=="formal":
  26. return OutfitCategory.FORMAL
  27. elif outfit_type=="a" or outfit_type=="athletic":
  28. return OutfitCategory.ATHLETIC
  29. elif outfit_type=="sl" or outfit_type=="sleep":
  30. return OutfitCategory.SLEEP
  31. elif outfit_type=="p" or outfit_type=="party":
  32. return OutfitCategory.PARTY
  33. elif outfit_type=="c" or outfit_type=="career":
  34. return OutfitCategory.CAREER
  35. elif outfit_type=="b" or outfit_type=="bathing":
  36. return OutfitCategory.BATHING
  37. elif outfit_type=="sw" or outfit_type=="swimwear":
  38. return OutfitCategory.SWIMWEAR
  39. elif outfit_type=="si" or outfit_type=="situation":
  40. return OutfitCategory.SITUATION
  41. elif outfit_type=="sp" or outfit_type=="special":
  42. return OutfitCategory.SPECIAL
  43. elif outfit_type=="ho" or outfit_type=="Hot Weather":
  44. return OutfitCategory.HOTWEATHER
  45. elif outfit_type=="co" or outfit_type=="Cold Weather":
  46. return OutfitCategory.COLDWEATHER
  47. else:
  48. return None
  49.  
  50. def outfit_get_name(outfit_category):
  51. if outfit_category == OutfitCategory.EVERYDAY:
  52. return 'Everyday'
  53. elif outfit_category == OutfitCategory.FORMAL:
  54. return 'Formal'
  55. elif outfit_category == OutfitCategory.ATHLETIC:
  56. return 'Athletic'
  57. elif outfit_category == OutfitCategory.SLEEP:
  58. return 'Sleep'
  59. elif outfit_category == OutfitCategory.PARTY:
  60. return 'Party'
  61. elif outfit_category == OutfitCategory.BATHING:
  62. return 'Bathing'
  63. elif outfit_category == OutfitCategory.CAREER:
  64. return 'Career'
  65. elif outfit_category == OutfitCategory.SITUATION:
  66. return 'Situation'
  67. elif outfit_category == OutfitCategory.SPECIAL:
  68. return 'Special'
  69. elif outfit_category == OutfitCategory.SWIMWEAR:
  70. return 'Swimwear'
  71. elif outfit_category == OutfitCategory.HOTWEATHER:
  72. return 'Hot Weather'
  73. elif outfit_category == OutfitCategory.COLDWEATHER:
  74. return 'Cold Weather'
  75. return "unknown category"
  76.  
  77. def outfit_copy_parts(src_outfit,dest_outfit_body_types,dest_outfit_part_ids,body_types):
  78. # Look at each body type in the body_types list and see if it needs to be copied,added or removed
  79. for body_type in body_types:
  80. src_idx=-1
  81. dest_idx=-1
  82. for idx in range(len(src_outfit.body_types)):
  83. if src_outfit.body_types[idx]==body_type:
  84. src_idx=idx
  85. break
  86. for idx in range(len(dest_outfit_body_types)):
  87. if dest_outfit_body_types[idx]==body_type:
  88. dest_idx=idx
  89. break
  90. if src_idx==-1:
  91. if dest_idx!=-1:
  92. # Part is in destination but not source outfit, remove it
  93. del dest_outfit_body_types[dest_idx]
  94. del dest_outfit_part_ids[dest_idx]
  95. elif dest_idx!=-1:
  96. # Part is in both source and destination, copy it
  97. dest_outfit_part_ids[dest_idx]=src_outfit.part_ids[src_idx]
  98. else:
  99. # Part is in source but not destination outfit, add it
  100. dest_outfit_body_types.append(body_type)
  101. dest_outfit_part_ids.append(src_outfit.part_ids[src_idx])
  102.  
  103. def DoCopy(SimInfo,src_category,src_slot,dest_category,dest_slot,include_hair,include_makeup,include_tattoos,output):
  104. if not SimInfo.has_outfit((src_category,src_slot)):
  105. output('Error: {} {} does not have an outfit in {} slot {}.'.format(SimInfo.first_name,SimInfo.last_name,outfit_get_name(src_category),src_num+1))
  106. return False
  107. if not SimInfo.has_outfit((dest_category,dest_slot)):
  108. return False
  109.  
  110. # List of body_type locations (see list at end for all locations)
  111. hair_items=[2,28,34]
  112. makeup_items=[29,30,31,32,33,37]
  113. tattoo_items=[45,46,47,48,49,50,51,52,53,54]
  114.  
  115. src_outfit=SimInfo.get_outfit(src_category,src_slot)
  116. dest_outfit=SimInfo.get_outfit(dest_category,dest_slot)
  117. copy_items=[]
  118. items_label=""
  119. if include_hair:
  120. copy_items+=hair_items
  121. items_label+="hair"
  122. if include_makeup:
  123. copy_items+=makeup_items
  124. if items_label:
  125. items_label+=", "
  126. items_label+="makeup"
  127. if include_tattoos:
  128. copy_items+=tattoo_items
  129. if items_label:
  130. items_label+=", "
  131. items_label+="tattoos"
  132. 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))
  133.  
  134. # Method for writing outfits back to sim_info based upon the work of Deaderpool
  135. outfits_msg=Outfits_pb2.OutfitList()
  136. outfits_msg.ParseFromString(SimInfo._base.outfits)
  137. for outfit in outfits_msg.outfits:
  138. if outfit.outfit_id==dest_outfit.outfit_id:
  139. dest_outfit_part_ids=list(outfit.parts.ids)
  140. dest_outfit_body_types=list(outfit.body_types_list.body_types)
  141. outfit_copy_parts(src_outfit,dest_outfit_body_types,dest_outfit_part_ids,copy_items)
  142. outfit.parts=S4Common_pb2.IdList()
  143. outfit.parts.ids.extend(dest_outfit_part_ids)
  144. outfit.body_types_list=Outfits_pb2.BodyTypesList()
  145. outfit.body_types_list.body_types.extend(dest_outfit_body_types)
  146. SimInfo._base.outfits=outfits_msg.SerializeToString()
  147.  
  148. # Resend the outfit info to the game
  149. SimInfo.resend_outfits()
  150.  
  151. return True
  152.  
  153. @sims4.commands.Command('unifyhmt', command_type=sims4.commands.CommandType.Live)
  154. def unifyhmt(*args,_connection=None):
  155. output=sims4.commands.CheatOutput(_connection)
  156. argc=len(args)
  157. if argc<1 or argc>5:
  158. unifyhmt_usage(output)
  159. return false
  160. include_hair=False
  161. include_makeup=False
  162. include_tattoos=False
  163. SimFirstName=""
  164. SimLastName=""
  165. if argc>3:
  166. for i in range(2,argc):
  167. if args[i]=="hair" or args[i]=="h":
  168. include_hair=True
  169. elif args[i]=="makeup" or args[i]=="m":
  170. include_makeup=True
  171. elif args[i]=="tattoos" or args[i]=="t":
  172. include_tattoos=True
  173. else:
  174. unifyhmt_usage(output)
  175. return False
  176. SimFirstName=args[0]
  177. SimLastName=args[1]
  178. elif argc==3:
  179. if args[2]=="hair" or args[2]=="h":
  180. include_hair=True
  181. elif args[2]=="makeup" or args[2]=="m":
  182. include_makeup=True
  183. elif args[2]=="tattoos" or args[2]=="t":
  184. include_tattoos=True
  185. else:
  186. unifyhmt_usage(output)
  187. return False
  188. if include_hair or include_makeup or include_tattoos:
  189. TrueCount=1
  190. else:
  191. TrueCount=0
  192. for i in range(2):
  193. if args[i]=="hair" or args[i]=="h":
  194. include_hair=True
  195. TrueCount+=1
  196. elif args[i]=="makeup" or args[i]=="m":
  197. include_makeup=True
  198. TrueCount+=1
  199. elif args[i]=="tattoos" or args[i]=="t":
  200. include_tattoos=True
  201. TrueCount+=1
  202. if TrueCount==1:
  203. SimFirstName=args[0]
  204. SimLastName=args[1]
  205. elif TrueCount==2 or TrueCount==0:
  206. unifyhmt_usage(output)
  207. return False
  208. else:
  209. for i in range(argc):
  210. if args[i]=="hair" or args[i]=="h":
  211. include_hair=True
  212. elif args[i]=="makeup" or args[i]=="m":
  213. include_makeup=True
  214. elif args[i]=="tattoos" or args[i]=="t":
  215. include_tattoos=True
  216. else:
  217. unifyhmt_usage(output)
  218. return False
  219.  
  220. # Get the sim info.
  221. if SimFirstName and SimLastName:
  222. SimInfo=services.sim_info_manager().get_sim_info_by_name(SimFirstName,SimLastName)
  223. if SimInfo is None:
  224. output('Error: No sim named {} {} was found.'.format(SimFirstName,SimLastName))
  225. return False
  226. else:
  227. tgt_client=services.client_manager().get(_connection)
  228. if tgt_client is None:
  229. output("Error: No sim is selected.")
  230. return False
  231. SimInfo=tgt_client.active_sim.sim_info
  232.  
  233. src_category=outfit_get_category('e')
  234. CurrentOutfitCategory=SimInfo._current_outfit[0]
  235. CurrentOutfitSlot=SimInfo._current_outfit[1]
  236. for outfit_type in ['e','f','a','sl','p','c','b','sw','si','sp']:
  237. for slot in range(5):
  238. dest_category=outfit_get_category(outfit_type)
  239. if outfit_type=='e' and slot==0: continue
  240. DoCopy(SimInfo,src_category,0,dest_category,slot,include_hair,include_makeup,include_tattoos,output)
  241. if CurrentOutfitSlot<0:
  242. output("Unable to determine the current outfit.")
  243. else:
  244. if CurrentOutfitCategory==OutfitCategory.BATHING:
  245. SimInfo.set_current_outfit((OutfitCategory.EVERYDAY,0))
  246. else:
  247. SimInfo.set_current_outfit((OutfitCategory.BATHING,0))
  248. SimInfo.set_current_outfit((CurrentOutfitCategory,CurrentOutfitSlot))
  249. output("{} {}'s currently wearing {} outfit {}.".format(SimInfo.first_name,SimInfo.last_name,outfit_get_name(CurrentOutfitCategory),CurrentOutfitSlot+1))
  250.  
  251. return True
  252.  
  253. """
  254. This is a list of all body type locations from outfit_enums.py:
  255. NONE=0
  256. HAT=1
  257. HAIR=2
  258. HEAD=3
  259. TEETH=4
  260. FULL_BODY=5
  261. UPPER_BODY=6
  262. LOWER_BODY=7
  263. SHOES=8
  264. CUMMERBUND=9
  265. EARRINGS=10
  266. GLASSES=11
  267. NECKLACE=12
  268. GLOVES=13
  269. WRIST_LEFT=14
  270. WRIST_RIGHT=15
  271. LIP_RING_LEFT=16
  272. LIP_RING_RIGHT=17
  273. NOSE_RING_LEFT=18
  274. NOSE_RING_RIGHT=19
  275. BROW_RING_LEFT=20
  276. BROW_RING_RIGHT=21
  277. INDEX_FINGER_LEFT=22
  278. INDEX_FINGER_RIGHT=23
  279. RING_FINGER_LEFT=24
  280. RING_FINGER_RIGHT=25
  281. MIDDLE_FINGER_LEFT=26
  282. MIDDLE_FINGER_RIGHT=27
  283. FACIAL_HAIR=28
  284. LIPS_TICK=29
  285. EYE_SHADOW=30
  286. EYE_LINER=31
  287. BLUSH=32
  288. FACEPAINT=33
  289. EYEBROWS=34
  290. EYECOLOR=35
  291. SOCKS=36
  292. MASCARA=37
  293. SKINDETAIL_CREASE_FOREHEAD=38
  294. SKINDETAIL_FRECKLES=39
  295. SKINDETAIL_DIMPLE_LEFT=40
  296. SKINDETAIL_DIMPLE_RIGHT=41
  297. TIGHTS=42
  298. SKINDETAIL_MOLE_LIP_LEFT=43
  299. SKINDETAIL_MOLE_LIP_RIGHT=44
  300. TATTOO_ARM_LOWER_LEFT=45
  301. TATTOO_ARM_UPPER_LEFT=46
  302. TATTOO_ARM_LOWER_RIGHT=47
  303. TATTOO_ARM_UPPER_RIGHT=48
  304. TATTOO_LEG_LEFT=49
  305. TATTOO_LEG_RIGHT=50
  306. TATTOO_TORSO_BACK_LOWER=51
  307. TATTOO_TORSO_BACK_UPPER=52
  308. TATTOO_TORSO_FRONT_LOWER=53
  309. TATTOO_TORSO_FRONT_UPPER=54
  310. SKINDETAIL_MOLE_CHEEK_LEFT=55
  311. SKINDETAIL_MOLE_CHEEK_RIGHT=56
  312. SKINDETAIL_CREASE_MOUTH=57
  313. SKIN_OVERLAY=58
  314. FUR_BODY=59
  315. EARS=60
  316. TAIL=61
  317. SKINDETAIL_NOSE_COLOR=62
  318. EYECOLOR_SECONDARY=63
  319. OCCULT_BROW=64
  320. OCCULT_EYE_SOCKET=65
  321. OCCULT_EYE_LID=66
  322. OCCULT_MOUTH=67
  323. OCCULT_LEFT_CHEEK=68
  324. OCCULT_RIGHT_CHEEK=69
  325. OCCULT_NECK_SCAR=70
  326. FOREARM_SCAR=71
  327. ACNE=72
  328. """
Add Comment
Please, Sign In to add comment