-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Move spells to scripts folder #4755
Conversation
nice, can we keep tab for indentation just to keep aligned with the other files? 😄 and also I see some spells were deleted accidentally? for example magic shield and cancel magic shield |
It was formatted with luaformatter, I don't know why it used spaces but maybe we're missing a config file?
oops |
7a6d543
to
4efe7e7
Compare
4efe7e7
to
8d52558
Compare
All files use spaces rather than tabs, are you sure about that? 🤔 |
We can make loading not fail if XML is not present and drop the file altogether |
I we wont drop support for xml i preffer to keep this file with some samples (like revscript examples) |
The goal is to drop XML |
Droping XML support will break backward compatibility. |
It won't, we can supply a XML parser written in Lua that can be disabled at will. I will do that in a separate PR while disabling it in C++
Indeed 😆 I used this script written in Python to mass-convert them: import xml.etree.ElementTree as ET
from os import makedirs, path, unlink
tree = ET.parse("spells.xml")
root = tree.getroot()
assert root.tag == "spells"
for child in root:
if "script" not in child.attrib:
continue
lines = []
for attrib in child.attrib:
if attrib in ["script"]:
continue
match attrib.lower():
case "spellid":
lines.append(f"spell:id({child.attrib[attrib]})")
case "id" if child.tag == "rune":
lines.append(f"spell:runeId({child.attrib[attrib]})")
case "allowfaruse" if child.tag == "rune":
if child.attrib[attrib] == "1":
lines.append(f"spell:allowFarUse(true)")
case "charges" if child.tag == "rune":
lines.append(f"spell:charges({child.attrib[attrib]})")
case "blocktype" if child.tag == "rune":
match child.attrib[attrib]:
case "all":
lines.append(f"spell:isBlocking(true, true)")
case "solid":
lines.append(f"spell:isBlocking(true, false)")
case "creature":
lines.append(f"spell:isBlocking(false, true)")
case "group":
lines.append(f'spell:group("{child.attrib[attrib]}")')
case "secondarygroup":
lines = [line if not line.startswith("spell:group") else f'spell:group("{child.attrib["group"]}", "{child.attrib[attrib]}")' for line in lines]
case "name":
lines.append(f'spell:name("{child.attrib[attrib]}")')
case "words":
lines.append(f'spell:words("{child.attrib[attrib]}")')
case "level" if child.tag == "spell":
lines.append(f"spell:level({child.attrib[attrib]})")
case "magiclevel" if child.tag == "spell":
lines.append(f"spell:magicLevel({child.attrib[attrib]})")
case "level" if child.tag == "rune":
lines.append(f"spell:runeLevel({child.attrib[attrib]})")
case "magiclevel" if child.tag == "rune":
lines.append(f"spell:runeMagicLevel({child.attrib[attrib]})")
case "mana":
lines.append(f"spell:mana({child.attrib[attrib]})")
case "soul":
lines.append(f"spell:soul({child.attrib[attrib]})")
case "premium":
if child.attrib[attrib] == "0":
lines.append(f"spell:isPremium(true)")
case "direction":
if child.attrib[attrib] == "1":
lines.append(f"spell:needDirection(true)")
case "aggressive":
if child.attrib[attrib] == "0":
lines.append(f"spell:isAggressive(false)")
case "playernameparam":
if child.attrib[attrib] == "1":
lines.append(f"spell:hasPlayerNameParam(true)")
case "params":
if child.attrib[attrib] == "1":
lines.append(f'spell:hasParams(true)')
case "selftarget":
if child.attrib[attrib] == "1":
lines.append(f"spell:isSelfTarget(true)")
case "pzlock" if child.tag == "rune":
if child.attrib[attrib] == "1":
lines.append(f"spell:isPzLocked(true)")
case "range":
lines.append(f"spell:range({child.attrib[attrib]})")
case "castertargetordirection":
if child.attrib[attrib] == "1":
lines.append(f"spell:needCasterTargetOrDirection(true)")
case "blockwalls":
if child.attrib[attrib] == "1":
lines.append(f"spell:blockWalls(true)")
case "needtarget":
if child.attrib[attrib] == "1":
lines.append(f"spell:needTarget(true)")
case "needweapon":
if child.attrib[attrib] == "1":
lines.append(f"spell:needWeapon(true)")
case "cooldown":
lines.append(f"spell:cooldown({child.attrib[attrib]})")
case "groupcooldown":
lines.append(f"spell:groupCooldown({child.attrib[attrib]})")
case "secondarygroupcooldown":
lines = [line if not line.startswith("spell:groupCooldown") else line[:-1] + f", {child.attrib[attrib]})" for line in lines]
case "needlearn":
if child.attrib[attrib] == "1":
lines.append(f"spell:needLearn(true)")
case _:
print(f"Unknown attribute: {attrib}")
with open(f"scripts/{child.attrib['script']}", "r") as f:
spell = f.read().split("\n")
voc_list = []
for voc in child:
assert voc.tag == "vocation"
voc_list.append((voc.attrib['name'].lower(), voc.attrib.get('showInDescription', '1') == '1'))
if voc_list:
lines.append(f'spell:vocation({", ".join(f'"{voc};true"' if show else f'"{voc}"' for voc, show in voc_list)})')
for idx, line in enumerate(spell):
if line.startswith("function onCastSpell"):
break
else:
print(f"Spell {child.attrib['name']} does not have onCastSpell function")
continue
print(f"Converting spell {child.attrib['name']}")
makedirs(f"../scripts/spells/{path.dirname(child.attrib['script'])}", exist_ok=True)
with open(f"../scripts/spells/{child.attrib['script']}", "w") as f:
f.write(
"\n".join(
[
*spell[:idx],
f"local spell = Spell(SPELL_{child.tag.upper()})\n",
*spell[idx:],
*lines,
"spell:register()",
]
)
)
unlink(f"scripts/{child.attrib['script']}") |
will be nice to add this script to repo for speedup migration from older version to latest |
Pull Request Prelude
Changes Proposed
Moves player spells to data/scripts in order to reduce XML-coding. Monster spells, rune spells and house spells stay in XML for now 😆