349 lines
9.7 KiB
Markdown
349 lines
9.7 KiB
Markdown
# 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.)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|