NOTE: This is not a guide on how to use the tool, just the draft made before actually making the tool. Instructions to use the tool are actually on the main README.
Field | Convert as | Example |
---|---|---|
Name | same | { "name": "warlock" } |
Article | same | { "article": "a" } |
Experience | the experienceYield field |
{ "experienceYield": 4000 } |
Corpse | same | { "corpse": "4240" } |
Blood | one of enum_bloodTypes values |
{ "blood": "blood" } |
This means the following:
Name = "warlock"
Article = "a"
Corpse = 4240
Blood = Blood
Experience = 4000
gets converted to:
{
"name": "warlock",
"article": "a",
"blood": "blood",
"experienceYield": 4000,
"corpse": "4240"
}
The following fields do not need to be converted:
RaceNumber = 10
...
SummonCost = 0
...
Poison = 0
The Outfit
field we'll convert into one of the following schemas:
Format | Convert as |
---|---|
(130, 0-52-128-95) | { "type": "outfit", "id": 130, "head": 0, "body": 52, "legs": 128, "feet": 95 } |
(36, 0-0-0-0) | { "type": "race", "id": 130 } |
(0, 0) | { "type": "invisible" } |
(0, 4240) | { "type": "item", "id": 4240 } |
Field | Convert to |
---|---|
Attack | combat.baseAttackPower |
Defend | combat.baseDefensePower |
Armor | combat.baseArmor |
For example:
"combat": {
...
"baseAttackPower": 40,
"baseDefensePower": 50,
"baseArmor": 32,
...
}
Strategy
is broken into 4 values under combat
(which must add to 100):
Strategy value | Converts as |
---|---|
Strategy = (x , x, x, x) |
combat.strategy.changeTarget.closest |
Strategy = ( x, x , x, x) |
combat.strategy.changeTarget.weakest |
Strategy = ( x, x, x , x) |
combat.strategy.changeTarget.strongest |
Strategy = ( x, x, x, x ) |
combat.strategy.changeTarget.random |
FleeThreshold
is converted as combat.strategy.flee.hitpointThreshold
, such as:
LoseTarget
is converted as combat.strategy.changeTarget.chance
, such as:
"combat": {
...
"strategy": {
"flee": {
"hitpointThreshold": 6
},
"changeTarget": {
"closest": 100,
"weakest": 0,
"strongest": 0,
"random": 0,
"chance": 0.5
}
}
...
}
Note that the
LoseTarget
value is converted from theinteger
range[0, 100]
todecimal
probability range[0.00, 1.00]
.
Flag | Converts as |
---|---|
Unpushable | CannotBePushed |
KickBoxes | CanPushItems |
KickCreatures | CanPushCreatures |
SeeInvisible | CanSeeInvisible |
These specific flags go into the flags
property (which are values of enum_flags
):
{
...
"flags": [
"CannotBePushed",
"CanPushItems",
"CanPushCreatures",
"CanSeeInvisible"
],
...
}
However these other flags:
Flag | Converts as |
---|---|
DistanceFighting | combat.distance = 4 |
NoBurning | combat.immunities[]: { type: "poison", modifier: 1.0 } |
NoPoison | combat.immunities[]: { type: fire", modifier: 1.0 } |
NoEnergy | combat.immunities[]: { type: energy", modifier: 1.0 } |
NoParalyze | combat.immunities[]: { type: paralysis", modifier: 1.0 } |
NoLifeDrain | combat.immunities[]: { type: lifeDrain", modifier: 1.0 } |
end up being like this:
"combat": {
...
"distance": 4,
...
"immunities": [
{
"type": "poison",
"modifier": 1.0
},
{
"type": "fire",
"modifier": 1.0
},
{
"type": "energy",
"modifier": 1.0
},
{
"type": "lifedrain",
"modifier": 1.0
},
{
"type": "paralysis",
"modifier": 1.0
}
],
...
},
These 3 skills convert one to one (using the first number):
Skill | Converts as |
---|---|
HitPoints | stats.hitpoints |
GoStrength | stats.baseSpeed |
CarryStrength | stats.carryStrength |
But FistFighting
becomes combat.skills.Fist
, and is split into:
Element | Converts as | Remarks |
---|---|---|
(FistFighting, 50 , 50, 50, 100, 1100, 2) |
combat.skills.Fist.level | |
(FistFighting, 50, 50, 50, 100 , 1100, 2) |
combat.skills.Fist.targetCount | |
(FistFighting, 50, 50, 50, 100, 1100 , 2) |
combat.skills.Fist.factor | normalized by dividing by 1000 |
(FistFighting, 50, 50, 50, 100, 1100, 2 ) |
combat.skills.Fist.increase |
For this one it's easier if you convert from the XML files in Nostalrius format. For simplicity here are only 2 of the items in the inventory/loot element for the warlock:
<item id="3031" countmax="80" chance="300" /> <!-- a gold coin -->
<item id="3360" countmax="1" chance="3" /> <!-- a golden armor -->
We'll:
-
Carry over names from Nostalrius files into the NAME property, stripping
'a'
/'an'
prefixes. -
Convert chance by dividing by 1000. e.g:
<item id="3360" countmax="1" chance="3" /> <!-- a golden armor -->
becomes
{ "id": "3360", "name": "golden armor", "maximumCount": 1, "chance": 0.003 }
Also note that
countmax
converts tomaximumCount
, and thatid
is a string.
You may just copy as-is from the .mon file. Alternatively, on the XML format, any text tagged YELL
will need to be prefixed with #Y
.
Here's an example:
Talk = {"Learn the secret of our magic! YOUR death!",
"Even a rat is a better mage than you.",
"We don't like intruders!"}
becomes
{
...
"speech": [
"Learn the secret of our magic! YOUR death!",
"Even a rat is a better mage than you.",
"We don't like intruders!"
]
...
}
... because you actually have to think.
Spells all become an entry under combat.abilities
, and they are broken down for each different type.
Here's what a Warlock has:
Spells = {Actor (13) -> Healing (80, 20) : 4,
Actor (13) -> Outfit ((0, 0), 20) : 10,
Victim (7, 5, 0) -> Damage (1, 75, 30) : 2,
Victim (7, 0, 0) -> Damage (512, 55, 20) : 6,
Victim (7, 0, 14) -> Speed (-80, 20, 40) : 9,
Origin (0, 13) -> Summon (67, 1) : 10,
Destination (7, 4, 2, 7) -> Damage (4, 130, 40) : 3,
Destination (7, 4, 0, 0) -> Field (1) : 7,
Destination (7, 4, 1, 0) -> Field (1) : 5,
Angle (0, 8, 12) -> Damage (8, 175, 30) : 8}
We'll dissect them all in the general form:
CastType
(params
) -> Action
(params
) : CHANCE
Then, assume we can mix and match, any Action
(params
) that we want, so forget about that part.
We're only left with CastType
(params
) and CHANCE
to worry about:
For CHANCE
there is a simple conversion rule: do 1/CHANCE
and round to 3 decimals:
(back to the warlock example)
Spell | Chance | Converted Chance |
---|---|---|
Actor (13) -> Healing (80, 20) : 4 |
4 | 1/4 = 0.25 |
Victim (7, 5, 0) -> Damage (1, 75, 30) : 2 |
2 | 1/2 = 0.5 |
Destination (7, 4, 2, 7) -> Damage (4, 130, 40) : 3 |
3 | 1/3 = 0.333 |
Victim (7, 0, 14) -> Speed (-80, 20, 40) : 9 |
9 | 1/9 = 0.111 |
Angle (0, 8, 12) -> Damage (8, 175, 30) : 8 |
8 | 1/8 = 0.125 |
Now, let's focus on the CastType
(params
) part:
converts to the form:
{
"type": "self",
"casterEffect": "SparklesBlue",
"actions": [
...
],
"chance": 0.1
},
where
Param | Type | Remarks |
---|---|---|
type | string | always "self" |
castEffect | enum_animatedEffect |
|
actions | array | |
chance | number | bounded in the range [0.000, 1.000] (with precision 3 ). |
{
"type": "selfArea",
"radius": 0,
"areaEffect": "SparklesBlue",
"actions": [
...
],
"chance": 0.1
},
where
Param | Type | Remarks |
---|---|---|
type | string | always "selfArea" |
radius | integer | |
areaEffect | enum_animatedEffect |
|
actions | array | |
chance | number | bounded in the range [0.000, 1.000] (with precision 3 ). |
{
"type": "target",
"range": 7,
"projectileEffect": "None",
"targetEffect": "SparklesRed",
"actions": [
...
],
"chance": 0.111
},
where
Param | Type | Remarks |
---|---|---|
type | string | always "target" |
range | integer | |
projectileEffect | enum_projectileEffects |
|
targetEffect | enum_animatedEffect |
|
actions | array | |
chance | number | bounded in the range [0.000, 1.000] (with precision 3 ). |
{
"type": "targetArea",
"range": 7,
"casterEffect": "None",
"projectileEffect": "Fire",
"areaEffect": "AreaFlame",
"radius": 2,
"actions": [
...
],
"chance": 0.333
},
where
Param | Type | Remarks |
---|---|---|
type | string | always "targetArea" |
range | integer | |
casterEffect | enum_animatedEffect |
|
projectileEffect | enum_projectileEffects |
|
areaEffect | enum_animatedEffect |
|
radius | integer | |
actions | array | |
chance | number | bounded in the range [0.000, 1.000] (with precision 3 ). |
{
"type": "targetDirection",
"length": 8,
"spread": 0,
"areaEffect": "DamageEnergy",
"actions": [
...
],
"chance": 0.125
}
where
Param | Type | Remarks |
---|---|---|
type | string | always "targetDirection" |
spread | integer | |
length | integer | |
areaEffect | enum_animatedEffect |
|
actions | array | |
chance | number | bounded in the range [0.000, 1.000] (with precision 3 ). |
Finally, let's get back to the general form:
CastType
(params
) -> Action
(params
) : CHANCE
And focus on the Action
(params
) part.
The spells/abilities can have any of the following actions:
Which is converted to:
{
"type": "heal",
"base": 80,
"variation": 20
}
{
"type": "damage",
"kind": "Physical",
"base": 75,
"variation": 30
}
where kind
is a enum_damageKinds
.
{
"type": "summon",
"monsterFile": "stonegolem",
"maximumCount": 1
}
where monsterFile
is the actual name (without extension) of the monster file (which you'll be converting too).
{
"type": "magicField",
"kind": "Fire"
}
where kind
is a enum_magicFieldKinds
.
{
"type": "speedChange",
"base": -70
"variation": 20,
"duration": 30000
}
where duration
is in milliseconds instead of seconds, so multiply by 1000.
{
"type": "makeDrunk",
"strength": 6,
"duration": 60000
}
where duration
is in milliseconds instead of seconds, so multiply by 1000.
If I ever think this is wrong, there's a reference here
{
"type": "changeSkill",
"base": -70
"variation": 20,
"kind": "1", // this is the chance parameter...
"duration": 20000
}
where duration
is in milliseconds instead of seconds, so multiply by 1000.
{
"type": "lookChange",
"targetLook": {
"type": "invisible"
},
"duration": 20000
}
where duration
is in milliseconds instead of seconds, so multiply by 1000.
{
"type": "lookChange",
"targetLook": {
"type": "item"
"id": "4240"
},
"duration": 20000
}
where duration
is in milliseconds instead of seconds, so multiply by 1000.
{
"type": "lookChange",
"targetLook": {
"type": "race",
"id": 122
},
"duration": 6000
}
where duration
is in milliseconds instead of seconds, so multiply by 1000.
{
"type": "lookChange",
"targetLook": {
"type": "outfit",
"id": 129,
"head": 95,
"body": 116,
"legs": 120,
"feet": 115
},
"duration": 6000
}
where duration
is in milliseconds instead of seconds, so multiply by 1000.