• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!

TFS 1.X+ Downgrading creatures

ralke

(҂ ͠❛ ෴ ͡❛)ᕤ
Joined
Dec 17, 2011
Messages
1,713
Solutions
31
Reaction score
965
Location
Santiago - Chile
GitHub
ralke23
Twitch
ralke23
Is there any tool, AI, idk which converts canary creatures into old xml 1.0 syntaxis?
I need to downgrade asuras, this one is an example from canary
LUA:
local mType = Game.createMonsterType("Dawnfire Asura")
local monster = {}

monster.description = "a dawnfire asura"
monster.experience = 4100
monster.outfit = {
    lookType = 150,
    lookHead = 114,
    lookBody = 94,
    lookLegs = 78,
    lookFeet = 79,
    lookAddons = 1,
    lookMount = 0,
}

monster.raceId = 1134
monster.Bestiary = {
    class = "Demon",
    race = BESTY_RACE_DEMON,
    toKill = 2500,
    FirstUnlock = 100,
    SecondUnlock = 1000,
    CharmsPoints = 50,
    Stars = 4,
    Occurrence = 0,
    Locations = "Asura Palace.",
}

monster.health = 2900
monster.maxHealth = 2900
monster.race = "blood"
monster.corpse = 21987
monster.speed = 140
monster.manaCost = 0

monster.changeTarget = {
    interval = 4000,
    chance = 10,
}

monster.strategiesTarget = {
    nearest = 70,
    health = 10,
    damage = 10,
    random = 10,
}

monster.flags = {
    summonable = false,
    attackable = true,
    hostile = true,
    convinceable = false,
    pushable = false,
    rewardBoss = false,
    illusionable = false,
    canPushItems = true,
    canPushCreatures = true,
    staticAttackChance = 80,
    targetDistance = 1,
    runHealth = 0,
    healthHidden = false,
    isBlockable = false,
    canWalkOnEnergy = true,
    canWalkOnFire = true,
    canWalkOnPoison = true,
}

monster.light = {
    level = 0,
    color = 0,
}

monster.voices = {
    interval = 5000,
    chance = 10,
    { text = "May the flames consume you!", yell = false },
    { text = "Encounter the flames of destiny!", yell = false },
    { text = "Fire and destruction!", yell = false },
}

monster.loot = {
    { id = 3031, chance = 69190, maxCount = 100 }, -- gold coin
    { id = 3035, chance = 84140, maxCount = 9 }, -- platinum coin
    { id = 6558, chance = 20910, maxCount = 2 }, -- flask of demonic blood
    { id = 238, chance = 8590, maxCount = 2 }, -- great mana potion
    { id = 3033, chance = 3140, maxCount = 1 }, -- small amethyst
    { id = 3028, chance = 2930, maxCount = 1 }, -- small diamond
    { id = 3032, chance = 3530, maxCount = 1 }, -- small emerald
    { id = 3030, chance = 5760, maxCount = 1 }, -- small ruby
    { id = 9057, chance = 2840, maxCount = 1 }, -- small topaz
    { id = 3041, chance = 220 }, -- blue gem
    { id = 6299, chance = 340 }, -- death ring
    { id = 6499, chance = 10660 }, -- demonic essence
    { id = 8043, chance = 870 }, -- focus cape
    { id = 21974, chance = 1230 }, -- golden lotus brooch
    { id = 826, chance = 570 }, -- magma coat
    { id = 3078, chance = 1160 }, -- mysterious fetish
    { id = 3574, chance = 2190 }, -- mystic turban
    { id = 21981, chance = 310 }, -- oriental shoes
    { id = 21975, chance = 11110 }, -- peacock feather fan
    { id = 5911, chance = 2340 }, -- red piece of cloth
    { id = 3016, chance = 800 }, -- ruby necklace
    { id = 5944, chance = 14560 }, -- soul orb
    { id = 8074, chance = 80 }, -- spellbook of mind control
    { id = 3071, chance = 910 }, -- wand of inferno
}

monster.attacks = {
    { name = "melee", interval = 2000, chance = 100, minDamage = 0, maxDamage = -269 },
    { name = "combat", interval = 3700, chance = 17, type = COMBAT_LIFEDRAIN, minDamage = -100, maxDamage = -300, length = 8, spread = 0, effect = CONST_ME_PURPLEENERGY, target = false },
    { name = "combat", interval = 3200, chance = 25, type = COMBAT_DEATHDAMAGE, minDamage = -100, maxDamage = -350, radius = 4, range = 5, target = true, effect = CONST_ME_MORTAREA },
    { name = "combat", interval = 2700, chance = 20, type = COMBAT_FIREDAMAGE, minDamage = -95, maxDamage = -180, range = 3, shootEffect = CONST_ANI_FIRE, target = true },
    { name = "speed", interval = 2000, chance = 20, speedChange = -800, radius = 1, shootEffect = CONST_ANI_EXPLOSION, effect = CONST_ME_SLEEP, target = true, duration = 15000 },
}

monster.defenses = {
    defense = 55,
    armor = 48,
    mitigation = 1.46,
    { name = "combat", interval = 2000, chance = 15, type = COMBAT_HEALING, minDamage = 50, maxDamage = 100, effect = CONST_ME_MAGIC_BLUE, target = false },
    { name = "speed", interval = 2000, chance = 15, speedChange = 320, effect = CONST_ME_MAGIC_RED, target = false, duration = 5000 },
}

monster.elements = {
    { type = COMBAT_PHYSICALDAMAGE, percent = -10 },
    { type = COMBAT_ENERGYDAMAGE, percent = -5 },
    { type = COMBAT_EARTHDAMAGE, percent = 0 },
    { type = COMBAT_FIREDAMAGE, percent = 100 },
    { type = COMBAT_LIFEDRAIN, percent = 0 },
    { type = COMBAT_MANADRAIN, percent = 0 },
    { type = COMBAT_DROWNDAMAGE, percent = 0 },
    { type = COMBAT_ICEDAMAGE, percent = -10 },
    { type = COMBAT_HOLYDAMAGE, percent = -10 },
    { type = COMBAT_DEATHDAMAGE, percent = 20 },
}

monster.immunities = {
    { type = "paralyze", condition = true },
    { type = "outfit", condition = false },
    { type = "invisible", condition = true },
    { type = "bleed", condition = false },
}

mType:register(monster)
And here's the theforgottenserver one (which doesn't match with canary attacks, inmunities, etc)
XML:
<?xml version="1.0" encoding="UTF-8"?>
<monster name="Dawnfire Asura" nameDescription="a dawnfire asura" race="blood" experience="4100" speed="280" raceId="1134">
    <health now="2900" max="2900" />
    <look type="150" head="114" body="94" legs="78" feet="79" addons="1" corpse="24643" />
    <targetchange interval="4000" chance="10" />
    <flags>
        <flag ignorespawnblock="1" />
        <flag pushable="0" />
        <flag canpushitems="1" />
        <flag canpushcreatures="1" />
        <flag staticattack="90" />
        <flag targetdistance="1" />
        <flag canwalkonenergy="1" />
        <flag canwalkonfire="1" />
        <flag canwalkonpoison="1" />
    </flags>
    <bestiary class="Demon" prowess="100" expertise="1000" mastery="2500" charmPoints="100" difficulty="hard" occurrence="common" locations="Dawnfire Asura Locations..." />
    <attacks>
        <attack name="melee" interval="2000" min="0" max="-269" />
        <attack name="manadrain" interval="2000" chance="10" range="7" min="0" max="-70" />
        <attack name="firefield" interval="2000" chance="10" range="7" radius="1" target="1">
            <attribute key="shootEffect" value="fire" />
        </attack>
        <attack name="lifedrain" interval="2000" chance="10" length="8" spread="0" min="-50" max="-200">
            <attribute key="areaEffect" value="purpleenergy" />
        </attack>
        <attack name="energy" interval="2000" chance="10" range="1" min="-10" max="-100">
            <attribute key="shootEffect" value="energy" />
            <attribute key="areaEffect" value="energy" />
        </attack>
        <attack name="speed" interval="2000" chance="15" radius="1" target="1" speedchange="-100" duration="30000">
            <attribute key="areaEffect" value="redshimmer" />
        </attack>
    </attacks>
    <defenses armor="55" defense="55">
        <defense name="healing" interval="2000" chance="15" min="50" max="100">
            <attribute key="areaEffect" value="blueshimmer" />
        </defense>
        <defense name="speed" interval="2000" chance="15" speedchange="320" duration="5000">
            <attribute key="areaEffect" value="redshimmer" />
        </defense>
    </defenses>
    <elements>
        <element physicalPercent="-10" />
        <element energyPercent="-5" />
        <element icePercent="-10" />
        <element holyPercent="-10" />
        <element deathPercent="20" />
    </elements>
    <immunities>
        <immunity fire="1" />
        <immunity paralyze="1" />
        <immunity invisible="1" />
    </immunities>
    <voices interval="2000" chance="7">
        <voice sentence="Encounter the flames of destiny!" />
        <voice sentence="Fire and destruction!" yell="1" />
        <voice sentence="I will end your torment. Do not run, little mortal." />
        <voice sentence="Join me, brothers, for a BLOODY FRENZY!" />
    </voices>
    <loot>
        <item id="2152" name="platinum coin" chance="84190" countmax="9" />
        <item id="2148" name="gold coin" chance="69612" countmax="100" />
        <item id="6558" name="flask of demonic blood" chance="20830" />
        <item id="5944" name="soul orb" chance="14157" />
        <item id="24630" name="golden lotus brooch" chance="12263" />
        <item id="24631" name="peacock feather fan" chance="11211" />
        <item id="6500" name="demonic essence" chance="10400" />
        <item id="7590" name="great mana potion" chance="9107" countmax="2" />
        <item id="2147" name="small ruby" chance="5981" countmax="3" />
        <item id="2149" name="small emerald" chance="3336" countmax="2" />
        <item id="2150" name="small amethyst" chance="3306" countmax="2" />
        <item id="9970" name="small topaz" chance="2825" countmax="2" />
        <item id="2145" name="small diamond" chance="2765" countmax="2" />
        <item id="5911" name="red piece of cloth" chance="2555" />
        <item id="2663" name="mystic turban" chance="2314" />
        <item id="2187" name="wand of inferno" chance="1172" />
        <item id="2194" name="mysterious fetish" chance="1022" />
        <item id="2156" name="red gem" chance="932" />
        <item id="8871" name="focus cape" chance="751" />
        <item id="2133" name="ruby necklace" chance="751" />
        <item id="7899" name="magma coat" chance="421" />
        <item id="2158" name="blue gem" chance="301" />
        <item id="6300" name="death ring" chance="271" />
        <item id="24637" name="oriental shoes" chance="180" />
        <item id="8902" name="spellbook of mind control" chance="60" />
    </loot>
</monster>

Thanks in advance!
 
you can ask chatgpt to create for you a python script that check your monster.xml and get every monster lua file from your canary and replace your canary monsters into the old xml but ofcours you should show chatgpt examples from canary and tfs
Post automatically merged:

 
Last edited:
I'm not sure if this works for you, but this is already converted to XML. This OTG Global base is fully based on version 13x and was converted to OTG with the full global map. So take a look — I believe it's similar to Canary in terms of attacks, defense, damage, and loot. Give it a try.

 
I'm not sure if this works for you, but this is already converted to XML. This OTG Global base is fully based on version 13x and was converted to OTG with the full global map. So take a look — I believe it's similar to Canary in terms of attacks, defense, damage, and loot. Give it a try.

he want a tool to convert all of his lua canary monsters files to xml
 
I'm not sure if this works for you, but this is already converted to XML. This OTG Global base is fully based on version 13x and was converted to OTG with the full global map. So take a look — I believe it's similar to Canary in terms of attacks, defense, damage, and loot. Give it a try.

Thanks but thse are not the correct values for the creature!
you can ask chatgpt to create for you a python script that check your monster.xml and get every monster lua file from your canary and replace your canary monsters into the old xml but ofcours you should show chatgpt examples from canary and tfs
Post automatically merged:

Did my attempt I got pretty good results. Here's the monsters attached.
It also did this script in python if works as base for something that does the job. Thanks for the replies!

Python:
import re
import os
from tkinter import Tk, filedialog


def parse_monster_lua(lua_content):
    monster = {}

    # Name
    name_match = re.search(r'Game\.createMonsterType\("(.+?)"\)', lua_content)
    if name_match:
        monster['name'] = name_match.group(1)

    # Description
    desc_match = re.search(r'monster\.description\s*=\s*"(.+?)"', lua_content)
    if desc_match:
        monster['description'] = desc_match.group(1)

    # Experience
    exp_match = re.search(r'monster\.experience\s*=\s*(\d+)', lua_content)
    if exp_match:
        monster['experience'] = exp_match.group(1)

    # Health
    hp_match = re.search(r'monster\.health\s*=\s*(\d+)', lua_content)
    if hp_match:
        monster['health'] = hp_match.group(1)
    max_hp_match = re.search(r'monster\.maxHealth\s*=\s*(\d+)', lua_content)
    if max_hp_match:
        monster['maxhealth'] = max_hp_match.group(1)

    # Speed
    speed_match = re.search(r'monster\.speed\s*=\s*(\d+)', lua_content)
    if speed_match:
        monster['speed'] = speed_match.group(1)

    # Race
    race_match = re.search(r'monster\.race\s*=\s*"(.+?)"', lua_content)
    if race_match:
        monster['race'] = race_match.group(1)

    # LookType
    looktype_match = re.search(r'lookType\s*=\s*(\d+)', lua_content)
    if looktype_match:
        monster['lookType'] = looktype_match.group(1)

    # Flags
    flags = re.findall(r'(\w+)\s*=\s*(true|false)', re.search(r'monster\.flags\s*=\s*{(.*?)}', lua_content, re.DOTALL).group(1))
    monster['flags'] = {flag: val for flag, val in flags}

    # Loot (simplified)
    loot = re.findall(r'{\s*name\s*=\s*"(.+?)".*?chance\s*=\s*(\d+).*?(?:maxCount\s*=\s*(\d+))?', lua_content)
    monster['loot'] = [{'name': item[0], 'chance': item[1], 'maxCount': item[2] or '1'} for item in loot]

    return monster


def generate_monster_xml(monster):
    lines = []
    lines.append(f'<monster name="{monster["name"]}" nameDescription="{monster.get("description", "a monster")}" race="{monster.get("race", "blood")}" experience="{monster.get("experience", "0")}" speed="{monster.get("speed", "0")}" manaCost="0">')
    lines.append(f'  <health now="{monster.get("health", "0")}" max="{monster.get("maxhealth", "0")}"/>')
    lines.append(f'  <look type="{monster.get("lookType", "0")}"/>')
    lines.append('  <flags>')
    for flag, val in monster['flags'].items():
        lines.append(f'    <flag {flag}="{val}"/>')
    lines.append('  </flags>')

    if monster['loot']:
        lines.append('  <loot>')
        for item in monster['loot']:
            line = f'    <item name="{item["name"]}" chance="{item["chance"]}"'
            if item['maxCount'] != '1':
                line += f' countmax="{item["maxCount"]}"'
            line += ' />'
            lines.append(line)
        lines.append('  </loot>')

    lines.append('</monster>')
    return '\n'.join(lines)


def convert_file():
    root = Tk()
    root.withdraw()
    file_path = filedialog.askopenfilename(title="Select a revscriptsys monster .lua file", filetypes=[("Lua Files", "*.lua")])
    if not file_path:
        print("No file selected.")
        return

    with open(file_path, 'r', encoding='utf-8') as file:
        lua_content = file.read()

    monster = parse_monster_lua(lua_content)
    xml_output = generate_monster_xml(monster)

    output_path = os.path.splitext(file_path)[0] + ".xml"
    with open(output_path, 'w', encoding='utf-8') as file:
        file.write(xml_output)

    print(f"Conversion completed: {output_path}")


if __name__ == '__main__':
    convert_file()
 

Attachments

Back
Top