Skip to content
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

Merged
merged 13 commits into from
Sep 19, 2024
Merged

Conversation

ranisalt
Copy link
Member

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 😆

@ghost ghost requested review from EvilHero90 and MillhioreBT June 15, 2024 18:49
@ghost
Copy link

ghost commented Jun 15, 2024

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

@ranisalt
Copy link
Member Author

nice, can we keep tab for indentation just to keep aligned with the other files?

It was formatted with luaformatter, I don't know why it used spaces but maybe we're missing a config file?

some spells were deleted accidentally? for example magic shield and cancel magic shield

oops

@ranisalt ranisalt force-pushed the revscriptsys-spells branch 2 times, most recently from 7a6d543 to 4efe7e7 Compare June 15, 2024 21:19
@ranisalt ranisalt force-pushed the revscriptsys-spells branch from 4efe7e7 to 8d52558 Compare June 15, 2024 21:21
@ranisalt ranisalt changed the title Move player spells to scripts folder Move spells to scripts folder Jun 15, 2024
@ranisalt
Copy link
Member Author

nice, can we keep tab for indentation just to keep aligned with the other files?

All files use spaces rather than tabs, are you sure about that? 🤔

@ranisalt
Copy link
Member Author

We can make loading not fail if XML is not present and drop the file altogether

@ArturKnopik
Copy link
Contributor

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)

@ranisalt
Copy link
Member Author

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

@ArturKnopik
Copy link
Contributor

Droping XML support will break backward compatibility.
As far as i know TFS want to be backward compat.
PS:
There is no automated script to convert all xml spells to revscript format.

@ranisalt
Copy link
Member Author

ranisalt commented Jun 17, 2024

Droping XML support will break backward compatibility.
As far as i know TFS want to be backward compat.

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++

There is no automated script to convert all xml spells to revscript format.

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']}")

@ArturKnopik
Copy link
Contributor

will be nice to add this script to repo for speedup migration from older version to latest

@ranisalt ranisalt merged commit 25df9cf into otland:master Sep 19, 2024
5 checks passed
@ranisalt ranisalt deleted the revscriptsys-spells branch September 19, 2024 22:14
@xmish xmish mentioned this pull request Sep 22, 2024
3 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants