|
@@ -1,41 +1,42 @@
|
|
|
import os
|
|
|
import re
|
|
|
+from collections import defaultdict
|
|
|
|
|
|
-#made by Awesome :peeposhrug:
|
|
|
+# made by Awesome
|
|
|
|
|
|
-script_directory = os.path.dirname(os.path.realpath(__file__))
|
|
|
-text_path = os.path.dirname(script_directory)
|
|
|
-qsrc_directory = os.path.join(text_path, 'locations')
|
|
|
+# Get the main directory path where the tools folder is located
|
|
|
+main_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
|
|
|
+qsrc_dir = os.path.join(main_dir, "locations")
|
|
|
+# Set the text_path to the main directory
|
|
|
+text_path = main_dir
|
|
|
+
|
|
|
+# Get the game directory from the user
|
|
|
image_directory = input('Enter the game directory: ')
|
|
|
-keywords = input('Enter keywords to exclude (comma-separated, press Enter to skip): ')
|
|
|
|
|
|
-keywords_to_exclude = keywords.split(',')
|
|
|
+# Ensure image_directory ends with a '/'
|
|
|
+if not image_directory.endswith('/'):
|
|
|
+ image_directory += '/'
|
|
|
|
|
|
-# Create a list to store missing images
|
|
|
-missing_images = []
|
|
|
-color_values = ['black', 'brown', 'red', 'blonde', 'light red', 'dark blue', 'blue', 'light blue', 'dark green', 'green', 'light green', 'dark pink', 'pink', 'light pink', 'dark purple', 'purple', 'light purple', 'light orange', 'dark red', 'medium red', 'turquoise', 'medium orange', 'dark orange']
|
|
|
+# Check if the user entered the images folder path instead of the game directory
|
|
|
+if image_directory.lower().endswith('images/'):
|
|
|
+ image_directory = os.path.dirname(os.path.dirname(image_directory))
|
|
|
|
|
|
-def exclude_keywords(image_path, keywords):
|
|
|
- for keyword in keywords:
|
|
|
- if keyword and keyword.lower() in image_path.lower():
|
|
|
- return True
|
|
|
- return False
|
|
|
+# Remove the 'images' subfolder from image_directory only if it's there
|
|
|
+if os.path.basename(image_directory.rstrip('/')).lower() == 'images':
|
|
|
+ image_directory = os.path.dirname(image_directory.rstrip('/'))
|
|
|
|
|
|
-keywords_to_exclude.append('$pcs_haircol')
|
|
|
-keywords_to_exclude.append('set_<<')
|
|
|
-keywords_to_exclude.append('+iif')
|
|
|
-keywords_to_exclude.append('<<FUNC')
|
|
|
+# Define keywords to exclude from media paths
|
|
|
+keywords_to_exclude = ['$pcs_haircol', 'pharma_picrand', 'mitkapicrand', '<<sex_ev[', '$epayments', '<<npc_apt_number', 'lover_picture[lover_number]', '<<lover_picrand[$boy]>>', '$_color', '<<masseuse', 'dress_', 'FUNC(', 'pants_', '<<pirs', '<<$phonetheme_name[pcs_phonetheme]>>', '$ARGS', '+iif', '<<BDSMmeet>>', 'kamasutra_page', '<<$']
|
|
|
|
|
|
-# Function to construct the absolute path from a relative image reference
|
|
|
-def construct_absolute_path(image_reference, image_directory):
|
|
|
- return os.path.join(image_directory, image_reference.replace("images\\", ""))
|
|
|
+# Create a list to store missing media (images and videos)
|
|
|
+missing_media = []
|
|
|
|
|
|
-# Function to evaluate and replace random expressions within a string
|
|
|
+# Function to evaluate and replace random expressions while preserving existing single quotes or '+' operators
|
|
|
def evaluate_and_replace_random(expression):
|
|
|
- image_paths = []
|
|
|
+ media_paths = []
|
|
|
|
|
|
- # Define a regular expression pattern to find '+rand(...)' or '<<rand(...)>>' expressions
|
|
|
- rand_pattern = r'(\+\s*rand\(([^)]*)\)\s*\+|\s*<<rand\(([^)]*)\)>>)'
|
|
|
+ # Define a regular expression pattern to find expressions like ' + rand(...) + ' or "'+rand(...)+'" or '<<rand(...)>>'
|
|
|
+ rand_pattern = r'(["\']?)\s*([\+\-]?)\s*(<<)?rand\s*\(\s*(\d+)\s*,\s*(\d+)\s*\)(>>)?\s*([\+\-]?)\s*(["\']?)'
|
|
|
|
|
|
# Find all matching expressions in the input string
|
|
|
matches = re.finditer(rand_pattern, expression)
|
|
@@ -45,113 +46,164 @@ def evaluate_and_replace_random(expression):
|
|
|
|
|
|
# Iterate through the matches and replace them
|
|
|
for match in matches:
|
|
|
- rand_expression = match.group(2) or match.group(3)
|
|
|
- if rand_expression:
|
|
|
- # Check if there are numeric values within the parentheses
|
|
|
- numeric_values = re.findall(r'\d+', rand_expression)
|
|
|
- if numeric_values:
|
|
|
- min_value = int(numeric_values[0])
|
|
|
- max_value = int(numeric_values[1]) if len(numeric_values) > 1 else min_value
|
|
|
- if min_value <= max_value:
|
|
|
- # Generate image paths for each number in the range
|
|
|
- image_paths.extend([str(num) for num in range(min_value, max_value + 1)])
|
|
|
+ start_quote, start_operator, _, min_value, max_value, _, end_operator, end_quote = match.groups()
|
|
|
+ min_value = int(min_value)
|
|
|
+ max_value = int(max_value)
|
|
|
+
|
|
|
+ if min_value <= max_value:
|
|
|
+ # Generate media paths for each number in the range
|
|
|
+ for num in range(min_value, max_value + 1):
|
|
|
+ # Create a copy of the modified expression
|
|
|
+ temp_expression = modified_expression
|
|
|
|
|
|
- # Replace the match in the expression with a placeholder
|
|
|
- modified_expression = modified_expression.replace(match.group(0), '<REPLACED>')
|
|
|
+ # Replace the 'rand' expression with the current number
|
|
|
+ replacement = (start_operator if start_operator else '') + str(num) + (end_operator if end_operator else '')
|
|
|
+ if start_quote and start_quote == end_quote:
|
|
|
+ replacement = replacement.strip("'")
|
|
|
+ replacement = replacement.strip("+")
|
|
|
|
|
|
- # Remove single quotes and extra spaces
|
|
|
- modified_expression = modified_expression.replace("'", "").strip()
|
|
|
- modified_expression = modified_expression.replace(" ", "")
|
|
|
+ temp_expression = temp_expression[:match.start()] + replacement + temp_expression[match.end():]
|
|
|
+ media_paths.append(temp_expression)
|
|
|
|
|
|
- # Add the generated image paths to the result
|
|
|
- image_paths = [modified_expression.replace('<REPLACED>', str(num)) for num in image_paths]
|
|
|
+ # If no random evaluations were found, return the original expression
|
|
|
+ if not media_paths:
|
|
|
+ media_paths = [modified_expression]
|
|
|
+
|
|
|
+ return media_paths
|
|
|
|
|
|
- return image_paths
|
|
|
|
|
|
# Function to evaluate and replace variables within a string
|
|
|
def evaluate_and_replace_variables(expression, variables):
|
|
|
variable_matches = re.findall(r'<<(\$?[a-zA-Z_][a-zAZ0-9_]*)>>', expression)
|
|
|
for variable_name in variable_matches:
|
|
|
if variable_name.startswith("$"):
|
|
|
- variable_value = variables.get(variable_name[1:], "")
|
|
|
+ variable_value = variables.get(variable_name[1:], None)
|
|
|
else:
|
|
|
- variable_value = variables.get(variable_name, "")
|
|
|
+ variable_value = variables.get(variable_name, None)
|
|
|
+ # Check if the variable value is a 'rand' function
|
|
|
+ if isinstance(variable_value, str) and 'rand(' in variable_value:
|
|
|
+ # Evaluate the 'rand' function
|
|
|
+ variable_value = evaluate_and_replace_random(variable_value)[0]
|
|
|
+ if variable_value is None:
|
|
|
+ return None
|
|
|
expression = expression.replace(f"<<{variable_name}>>", str(variable_value))
|
|
|
return [expression]
|
|
|
|
|
|
+# Initialize an empty dictionary to store variable values
|
|
|
+variables = {}
|
|
|
+
|
|
|
# Iterate through .qsrc files in the specified directory and its subdirectories
|
|
|
-for root, dirs, files in os.walk(qsrc_directory):
|
|
|
- for file in files:
|
|
|
- if file.endswith(".qsrc"):
|
|
|
- qsrc_file = os.path.join(root, file)
|
|
|
-
|
|
|
- # Read the .qsrc file
|
|
|
- with open(qsrc_file, "r", encoding="utf-8") as script_file:
|
|
|
- script_content = script_file.readlines()
|
|
|
-
|
|
|
- # Find and extract variable assignments within the same code block
|
|
|
- variable_matches = re.findall(r'<<(\$?[a-zA-Z_][a-zAZ0-9_]*)>>\s*=\s*([\'"]?[^\'"]+[\'"]?)', ''.join(script_content))
|
|
|
-
|
|
|
- # Store variable values for this code block
|
|
|
- code_block_variables = {}
|
|
|
- for variable_name, variable_value in variable_matches:
|
|
|
- code_block_variables[variable_name] = variable_value.strip("'\"")
|
|
|
-
|
|
|
- # Use regular expressions to find image references in the script
|
|
|
- for line_number, line in enumerate(script_content, start=1):
|
|
|
- if line.strip().startswith('!') or '+iif' in line or '<<FUNC' in line:
|
|
|
+for file in os.listdir(qsrc_dir):
|
|
|
+ if file.endswith(".qsrc"):
|
|
|
+ qsrc_file = os.path.join(qsrc_dir, file)
|
|
|
+
|
|
|
+ # Read the .qsrc file
|
|
|
+ with open(qsrc_file, "r", encoding="utf-8", errors="ignore") as script_file:
|
|
|
+ script_content = script_file.readlines()
|
|
|
+
|
|
|
+ # Initialize a dictionary to store the 'rand' variables and their expressions
|
|
|
+ rand_variables = {}
|
|
|
+
|
|
|
+ # Define a regular expression pattern to find 'rand' variable assignments
|
|
|
+ rand_assignment_pattern = r'<<(\$?[a-zA-Z_][a-zAZ0-9_]*)>>\s*=\s*(rand\(\d+,\s*\d+\))'
|
|
|
+
|
|
|
+ # Iterate through the script content to find and store 'rand' variable assignments
|
|
|
+ for line_number, line in enumerate(script_content, start=1):
|
|
|
+ matches = re.findall(rand_assignment_pattern, line)
|
|
|
+ for match in matches:
|
|
|
+ variable_name, rand_expression = match
|
|
|
+ rand_variables[variable_name.strip()] = rand_expression.strip()
|
|
|
+
|
|
|
+ # Iterate through each line in the .qsrc file
|
|
|
+ for line_number, line in enumerate(script_content, start=1):
|
|
|
+ # Check if the line contains a variable assignment
|
|
|
+ if "=" in line and "<<" in line and ">>" in line:
|
|
|
+ # Find all matches of the regular expression in the line
|
|
|
+ matches = re.findall(r'<<(\$?[a-zA-Z_][a-zAZ0-9_]*)>>\s*=\s*([\'"]?[^\'"]+[\'"]?)', line)
|
|
|
+ # Check if there are any matches
|
|
|
+ if matches:
|
|
|
+ # Split the line into a variable name and value
|
|
|
+ variable_name, variable_value = matches[0]
|
|
|
+ # Check if the variable value contains a 'rand' function
|
|
|
+ if "rand(" in variable_value:
|
|
|
+ # Evaluate the 'rand' function
|
|
|
+ variable_value = evaluate_and_replace_random(variable_value)[0]
|
|
|
+ # Store the variable value in the dictionary with the filename and line number as the key
|
|
|
+ variables[(qsrc_file, line_number)] = {variable_name.strip(): variable_value.strip("'\"")}
|
|
|
+
|
|
|
+ # Use regular expressions to find media references in the script
|
|
|
+ if line.strip().startswith('!') or '<<FUNC' in line:
|
|
|
+ continue
|
|
|
+ media_references = re.findall(r'<(?:img.*?|video.*?)src="([^"]+)"', line)
|
|
|
+
|
|
|
+ for media_reference in media_references:
|
|
|
+ if any(keyword in media_reference for keyword in keywords_to_exclude):
|
|
|
continue
|
|
|
- image_references = re.findall(r'<(?:img <<\$set_imgh>>|video autoplay loop) src="([^"]+)"', line)
|
|
|
|
|
|
- for image_reference in image_references:
|
|
|
- if exclude_keywords(image_reference, keywords_to_exclude):
|
|
|
+ # Special rules
|
|
|
+ media_reference = media_reference.replace("lover_picrand", 'rand(1, 30)')
|
|
|
+ media_reference = media_reference.replace("modelfoto[''debut_image'']+1", 'rand(1, 9)')
|
|
|
+ media_reference = media_reference.replace("modelfoto[''debut_image'']+2", 'rand(1, 9)')
|
|
|
+ media_reference = media_reference.replace("modelfoto[''debut_image'']", 'rand(1, 9)')
|
|
|
+ media_reference = media_reference.replace("zz_stage", 'rand(0, 7)')
|
|
|
+ media_reference = media_reference.replace("VKWoods", 'rand(0, 8)')
|
|
|
+ media_reference = media_reference.replace("metrorand['rand']", 'rand(1, 2)')
|
|
|
+ media_reference = media_reference.replace("picpRand", 'rand(1, 20)')
|
|
|
+ media_reference = media_reference.replace("Doublerand", 'rand(14, 15)')
|
|
|
+
|
|
|
+ # Find the variable assignment that is closest to (but above) the media reference
|
|
|
+ relevant_variables = max(((k, v) for k, v in variables.items() if k[0] == qsrc_file and k[1] < line_number), key=lambda item: item[0][1], default=({}, {}))[1]
|
|
|
+
|
|
|
+ # Evaluate variables first
|
|
|
+ media_reference = evaluate_and_replace_variables(media_reference, relevant_variables)
|
|
|
+ if media_reference is None:
|
|
|
+ continue
|
|
|
+ media_reference = media_reference[0]
|
|
|
+
|
|
|
+ # Use regular expression to identify and replace variables set with rand in the image path
|
|
|
+ variable_references = re.findall(r'<<(\$?[a-zA-Z_][a-zAZ0-9_]*)>>', media_reference)
|
|
|
+ for variable_reference in variable_references:
|
|
|
+ if variable_reference in rand_variables:
|
|
|
+ rand_expression = rand_variables[variable_reference]
|
|
|
+ media_reference = media_reference.replace(f"<<{variable_reference}>>", str(eval(rand_expression)))
|
|
|
+
|
|
|
+ media_paths = evaluate_and_replace_random(media_reference)
|
|
|
+
|
|
|
+ for path in media_paths:
|
|
|
+ if any(keyword in path for keyword in keywords_to_exclude):
|
|
|
continue
|
|
|
- # If the image reference contains '<<$pcs_haircol>>', replace it with each color value
|
|
|
- if '<<$pcs_haircol>>' in image_reference:
|
|
|
- for color in color_values:
|
|
|
- # Replace spaces with underscores in color names
|
|
|
- image_reference_color = image_reference.replace('<<$pcs_haircol>>', color)
|
|
|
- # Handle the '+rand(1,19)+' part
|
|
|
- if '+rand(1,19)+' in image_reference_color:
|
|
|
- for i in range(1, 20): # 20 is exclusive, so this will give numbers from 1 to 19
|
|
|
- image_reference_color_i = image_reference_color.replace('+rand(1,19)+', str(i))
|
|
|
- # Remove single quotes around the number
|
|
|
- image_reference_color_i = image_reference_color_i.replace("'"+str(i)+"'", str(i))
|
|
|
- absolute_path = construct_absolute_path(image_reference_color_i, image_directory)
|
|
|
-
|
|
|
- if not os.path.exists(absolute_path):
|
|
|
-
|
|
|
- missing_images.append((os.path.basename(qsrc_file), image_reference_color_i, line_number)) # Store the .qsrc filename, image path, and line number
|
|
|
- else:
|
|
|
- absolute_path = construct_absolute_path(image_reference_color, image_directory)
|
|
|
-
|
|
|
- if not os.path.exists(absolute_path):
|
|
|
-
|
|
|
- missing_images.append((os.path.basename(qsrc_file), image_reference_color, line_number)) # Store the .qsrc filename, image path, and line number
|
|
|
- else:
|
|
|
- # Evaluate variables first
|
|
|
- image_reference = evaluate_and_replace_variables(image_reference, code_block_variables)[0]
|
|
|
- image_paths = evaluate_and_replace_random(image_reference)
|
|
|
-
|
|
|
- for path in image_paths:
|
|
|
- if exclude_keywords(path, keywords_to_exclude):
|
|
|
- continue
|
|
|
- absolute_path = construct_absolute_path(path, image_directory)
|
|
|
-
|
|
|
- if not os.path.exists(absolute_path):
|
|
|
-
|
|
|
- missing_images.append((os.path.basename(qsrc_file), path, line_number)) # Store the .qsrc filename, image path, and line number
|
|
|
-missing_media_count = len(missing_images)
|
|
|
+ absolute_path = os.path.join(image_directory, path)
|
|
|
+
|
|
|
+ # Check if the path is a directory
|
|
|
+ if os.path.isdir(absolute_path) and not os.listdir(absolute_path):
|
|
|
+ missing_media.append((os.path.basename(qsrc_file), path, line_number))
|
|
|
+
|
|
|
+ elif not os.path.exists(absolute_path):
|
|
|
+ missing_media.append((os.path.basename(qsrc_file), path, line_number))
|
|
|
|
|
|
# Specify the path to the "missing_media.txt" output file
|
|
|
missing_media_file = os.path.join(text_path, "missing_media.txt")
|
|
|
|
|
|
-# Write the list of missing images with full image paths to the "missing_media.txt" file
|
|
|
+# Convert the list to a set to remove duplicates, then convert it back to a list
|
|
|
+missing_media = [i for n, i in enumerate(missing_media) if i not in missing_media[n + 1:]]
|
|
|
+
|
|
|
+# Create a dictionary to store the file name, media path and line numbers
|
|
|
+missing_media_dict = defaultdict(list)
|
|
|
+
|
|
|
+for qsrc_file, media_path, line_number in missing_media:
|
|
|
+ # Use the file name and media path as the key, and append the line number to the list of values
|
|
|
+ missing_media_dict[(qsrc_file, media_path)].append(line_number)
|
|
|
+
|
|
|
+# Write the dictionary to the "missing_media.txt" file
|
|
|
with open(missing_media_file, "w", encoding="utf-8") as file:
|
|
|
- for qsrc_file, image_path, line_number in missing_images:
|
|
|
- file.write(f"From file: {qsrc_file}, line: {line_number}\n") # Write the .qsrc filename and line number
|
|
|
- file.write(f"images/{image_path.replace('images/', '')}\n\n") # Write the relative image path and start a new line
|
|
|
- file.write(f"\nTotal missing media files: {missing_media_count}\n") # Write the count of missing media files at the end of the file
|
|
|
- file.write(f"this amazing script was made by Awesome(with help from chatGPT)\n") #bragging
|
|
|
-print(f"{missing_media_count} Missing images have been saved to 'missing_media.txt'.")
|
|
|
-pause = input("Press Enter to exit.")
|
|
|
+ for (qsrc_file, media_path), line_numbers in missing_media_dict.items():
|
|
|
+ # Join the line numbers with commas
|
|
|
+ line_numbers_str = ", ".join(map(str, line_numbers))
|
|
|
+ file.write(f"From file: {qsrc_file}, lines: {line_numbers_str}\n") # Write the .qsrc filename and line numbers
|
|
|
+ file.write(f"{media_path}\n\n") # Write the full media path and start a new line
|
|
|
+ file.write(f"\nTotal missing media files: {len(missing_media_dict)}\n") # Write the count of missing media files at the end of the file
|
|
|
+ file.write(f"this amazing script was made by Awesome (with help from chatGPT)\n") # Bragging
|
|
|
+
|
|
|
+print(f"{len(missing_media_dict)} Missing media files have been saved to 'missing_media.txt'.")
|
|
|
+pause = input("Press Enter to exit.")
|
|
|
+
|