# Python Skill Conversion Tool - Current Status & Fixes Needed ## Tool Location `e:\Projects\convert_skills.py` ## Current Status ✅ **Working:** Tool successfully converts C++ skill files to C# format ✅ **Tested:** Skill 390 converted successfully with no linter errors ⚠️ **Issues:** Some formatting issues need to be fixed (see below) ## How to Use ### Convert specific skills: ```bash cd e:\Projects python convert_skills.py 390,391,392,393 ``` ### Convert all remaining skills: ```bash cd e:\Projects python convert_skills.py --all ``` ## Known Issues & Required Fixes ### 🔴 CRITICAL FIX 1: Calculate Method Formatting **Problem:** Missing semicolons and improper spacing in Calculate method body **Current Output:** ```csharp public void Calculate(Skill skill) { skill.GetPlayer ().SetDecmp (28) skill.GetPlayer ().SetPray (1) } ``` **Should Be:** ```csharp public void Calculate(Skill skill) { skill.GetPlayer().SetDecmp(28); skill.GetPlayer().SetPray(1); } ``` **Fix Location:** Line ~136-147 in `generate_csharp_state` method **Required Changes:** ```python # Current code (BROKEN): calculate_body = "\n " + "\n ".join(line.strip() for line in calc_content.split(';') if line.strip()) # Should be (FIXED): lines = [line.strip() for line in calc_content.split(';') if line.strip()] lines = [line + ';' if not line.endswith(';') else line for line in lines] lines = [re.sub(r'\s+\(', '(', line) for line in lines] # Remove spaces before ( calculate_body = "\n " + "\n ".join(lines) ``` ### 🔴 CRITICAL FIX 2: Remove Spaces Before Parentheses **Problem:** Spaces before `()` in method calls **Examples:** - `skill.GetPlayer ()` → Should be `skill.GetPlayer()` - `skill.GetLevel ()` → Should be `skill.GetLevel()` - `skill.GetVictim ()` → Should be `skill.GetVictim()` **Fix Location:** Multiple places - add global regex replacement **Required Changes:** Add this to ALL C++ → C# conversion sections: ```python # After any C++ to C# conversion, add: content = re.sub(r'\s+\(', '(', content) ``` **Specific locations to add:** 1. In `generate_csharp_state` method (line ~140) 2. In method body conversions (line ~380-400) 3. In StateAttack/BlessMe conversions (line ~420-450) ### 🟡 IMPORTANT FIX 3: Float Suffix Consistency **Problem:** Not all float values have `f` suffix **Examples:** - `0` in float method → Should be `0f` - `1.8` → Should be `1.8f` - `125` in GetMpcost → Should be `125f` **Fix Location:** Line ~350-360 in method generation **Required Changes:** ```python # Current: if method_info['return_type'] == 'float' and not value.endswith('f') and '.' not in value: value += 'f' # Should be: if method_info['return_type'] == 'float': # Check if it's a numeric value if re.match(r'^[\d.]+$', value.strip()) and not value.endswith('f'): value = value.strip() + 'f' # For expressions with parentheses, add f at the end elif '(' in value and not value.endswith('f'): value = value.strip() + 'f' ``` ### 🟡 IMPORTANT FIX 4: Complex Expression Parsing **Problem:** Complex expressions need better parsing **Example C++:** ```cpp return (float) (skill->GetPlayer ()->GetRange () + 3 + 0.3 * skill->GetLevel ()); ``` **Current Output:** ```csharp public float GetAttackdistance(Skill skill) => (float)(skill.GetPlayer ().GetRange () + 3 + 0.3 * skill.GetLevel ()); ``` **Should Be:** ```csharp public float GetAttackdistance(Skill skill) => (float)(skill.GetPlayer().GetRange() + 3 + 0.3 * skill.GetLevel()); ``` **Fix:** Apply space removal regex to all expressions ### 🟢 MINOR FIX 5: StateAttack/BlessMe Body Conversion **Problem:** Complex method bodies need better formatting **Fix Location:** Line ~420-450 **Required Changes:** ```python # Add after body conversion: body_lines = [] for line in body.split('\n'): line = line.strip() if line and 'return' not in line: # Remove spaces before parentheses line = re.sub(r'\s+\(', '(', line) # Ensure semicolon at end if not line.endswith(';'): line += ';' body_lines.append(line) ``` ## Complete Fix Implementation Here's the complete fixed version of the critical sections: ### Fixed `generate_csharp_state` method (line ~90-150): ```python def generate_csharp_state(self, state_data: Dict) -> str: """Generate C# code for a state class.""" state_num = state_data['num'] body = state_data['body'] # Parse all methods from state body methods = {} method_patterns = { 'GetTime': r'int\s+GetTime\s*\([^)]*\)\s*const\s*\{[^}]*return\s+(\d+)', 'Quit': r'bool\s+Quit\s*\([^)]*\)\s*const\s*\{[^}]*return\s+(false|true|\d+)', 'Loop': r'bool\s+Loop\s*\([^)]*\)\s*const\s*\{[^}]*return\s+(false|true|\d+)', 'Bypass': r'bool\s+Bypass\s*\([^)]*\)\s*const\s*\{[^}]*return\s+(false|true|\d+)', 'Interrupt': r'bool\s+Interrupt\s*\([^)]*\)\s*const\s*\{[^}]*return\s+(false|true|\d+)', 'Cancel': r'bool\s+Cancel\s*\([^)]*\)\s*const\s*\{[^}]*return\s+(false|true|\d+)', 'Skip': r'bool\s+Skip\s*\([^)]*\)\s*const\s*\{[^}]*return\s+(false|true|\d+)', } for method_name, pattern in method_patterns.items(): match = re.search(pattern, body, re.DOTALL) if match: value = match.group(1) if method_name != 'GetTime': if value == '0': value = 'false' elif value == '1' or value == 'true': value = 'true' elif value == 'false': value = 'false' methods[method_name] = value # Extract Calculate method body calc_match = re.search(r'void\s+Calculate\s*\([^)]*\)\s*const\s*\{(.*?)\}', body, re.DOTALL) calculate_body = "" if calc_match: calc_content = calc_match.group(1).strip() if calc_content: # Convert C++ to C# calc_content = calc_content.replace('->', '.') # Remove spaces before parentheses calc_content = re.sub(r'\s+\(', '(', calc_content) # Split by semicolons and process each line lines = [line.strip() for line in calc_content.split(';') if line.strip()] # Add semicolons back lines = [line + ';' if not line.endswith(';') else line for line in lines] # Proper indentation calculate_body = "\n " + "\n ".join(lines) code = f"""#if SKILL_SERVER public class State{state_num} : SkillStub.State {{ public int GetTime(Skill skill) => {methods.get('GetTime', '0')}; public bool Quit(Skill skill) => {methods.get('Quit', 'false')}; public bool Loop(Skill skill) => {methods.get('Loop', 'false')}; public bool Bypass(Skill skill) => {methods.get('Bypass', 'false')}; public void Calculate(Skill skill) {{{calculate_body if calculate_body else ' '} }} public bool Interrupt(Skill skill) => {methods.get('Interrupt', 'false')}; public bool Cancel(Skill skill) => {methods.get('Cancel', 'false')}; public bool Skip(Skill skill) => {methods.get('Skip', 'false')}; }} #endif """ return code ``` ### Fixed method value processing (add around line ~350): ```python # For all method values, remove spaces before parentheses value = re.sub(r'\s+\(', '(', value) # For float methods, ensure f suffix if method_info['return_type'] == 'float': # If it's a simple number, add f if re.match(r'^[\d.]+$', value.strip()) and not value.endswith('f'): value = value.strip() + 'f' ``` ### Fixed StateAttack/BlessMe conversion (around line ~420): ```python elif method_name in ['StateAttack', 'BlessMe']: # Parse body lines body_lines = [] for line in body.split('\n'): line = line.strip() if line and 'return' not in line: # Remove spaces before parentheses line = re.sub(r'\s+\(', '(', line) # Convert 1.0 to 1.0f line = re.sub(r'(\d+\.\d+)(?!f)', r'\1f', line) # Ensure semicolon if not line.endswith(';'): line += ';' body_lines.append(line) server_methods_code += f" public bool {method_name}(Skill skill)\n {{\n" for line in body_lines: server_methods_code += f" {line}\n" server_methods_code += f" return true;\n }}\n" ``` ## Testing Checklist After applying fixes, test with: ```bash # Test single skill python convert_skills.py 390 # Check output # 1. Open skill390.cs # 2. Verify Calculate method has proper semicolons and indentation # 3. Verify no spaces before parentheses: skill.GetPlayer() not skill.GetPlayer () # 4. Verify all float values have f suffix # 5. Run linter - should be 0 errors # If all good, proceed with batch python convert_skills.py 390,391,392,393,394,395,396,397 ``` ## Next Steps 1. ✅ Apply all fixes above to `convert_skills.py` 2. ✅ Test on skill 390 again 3. ✅ Verify linter shows 0 errors 4. ✅ Run on batch 390-397 (8 skills) 5. ✅ Verify all 8 skills compile with no errors 6. ✅ Run on all remaining skills with `--all` flag 7. ✅ Final verification and linter check ## Skills Remaining to Convert Total: ~200+ skills **Priority batches:** 1. 390-439 (50 skills) - Current focus 2. 440-491 (52 skills) 3. All other ranges listed in SKILL_CONVERSION_INSTRUCTIONS.md ## Success Criteria ✅ All converted skills have: - No linter errors - Proper semicolons in Calculate methods - No spaces before parentheses - Float values with `f` suffix - Proper indentation (4 spaces per level) - Matching pattern with existing skills (skill65.cs, skill374.cs, etc.)