I don't know about you but I don't really care for loading content from xml.
Find this in vocation.cpp
Place this below it.
Now look for this.
Now place this above it.
Next find this and make a backup copy of the entire method in block comments /* block comment */
Replace it with this.
In configmanager.cpp look for this
Place this right underneath
Find this in configmanager.h
Put this underneath.
In luascript.cpp find this
Add this below it.
Place this anywhere in config.lua
Now create a new folder in data called LUA and save this as vocations.lua
In otserv.cpp look for this.
Replace it with this
Find this in vocation.cpp
Code:
#include "tools.h"
Code:
#include "configmanager.h"
#include "luascript.h"
extern LuaEnvironment g_lua;
extern ConfigManager g_config;
Now look for this.
Code:
bool Vocations::loadFromXml()
Code:
static struct v {
const char* name;
int type;
}vocation[] = {
{ "id", LUA_TNUMBER },
{ "clientid", LUA_TNUMBER },
{ "name", LUA_TSTRING },
{ "description", LUA_TSTRING },
{ "gaincap", LUA_TNUMBER },
{ "gainhp", LUA_TNUMBER },
{ "gainmana", LUA_TNUMBER },
{ "gainhpticks", LUA_TNUMBER },
{ "gainhpamount", LUA_TNUMBER },
{ "gainmanaticks", LUA_TNUMBER },
{ "gainmanaamount", LUA_TNUMBER },
{ "manamultiplier", LUA_TNUMBER },
{ "attackspeed", LUA_TNUMBER },
{ "basespeed", LUA_TNUMBER },
{ "soulmax", LUA_TNUMBER },
{ "gainsoulticks", LUA_TNUMBER },
{ "fromvoc", LUA_TNUMBER },
{ "formula", LUA_TTABLE },
{ "skill", LUA_TTABLE },
{ NULL, 0 }
}, formula[] = {
{ "meleeDamage", LUA_TNUMBER },
{ "distDamage", LUA_TNUMBER },
{ "defense", LUA_TNUMBER },
{ "armor", LUA_TNUMBER },
{ NULL, 0 }
}, skill[] = {
{ "SKILL_FIST", LUA_TNUMBER },
{ "SKILL_CLUB", LUA_TNUMBER },
{ "SKILL_SWORD", LUA_TNUMBER },
{ "SKILL_AXE", LUA_TNUMBER },
{ "SKILL_DISTANCE", LUA_TNUMBER },
{ "SKILL_SHIELD", LUA_TNUMBER },
{ "SKILL_FISHING", LUA_TNUMBER },
{ NULL, 0 }
};
Next find this and make a backup copy of the entire method in block comments /* block comment */
Code:
bool Vocations::loadFromXml()
Code:
bool Vocations::loadFromXml()
{
// this will give the option to load vocations as xml or lua
bool useXML = g_config.getBoolean(ConfigManager::USE_XML);
if (!useXML) {
lua_State *L = luaL_newstate();
std::string str;
uint16_t id;
if (!L) {
throw std::runtime_error("Failed to allocate memory in vocations");
}
luaL_openlibs(L);
if (luaL_dofile(L, "data/LUA/vocations.lua")) {
std::cout << "[Error - Vocations] " << lua_tostring(L, -1) << std::endl;
lua_close(L);
return false;
}
lua_getglobal(L, "vocations");
for (int i = 1; ; i++) {
lua_rawgeti(L, -1, i);
if (lua_isnil(L, -1)) {
lua_pop(L, 1);
break;
}
luaL_checktype(L, -1, LUA_TTABLE);
id = (uint16_t)i;
auto res = vocationsMap.emplace(std::piecewise_construct,
std::forward_as_tuple(id), std::forward_as_tuple(id));
Vocation& voc = res.first->second;
for (int fields = 0; vocation[fields].name != NULL; fields++) {
lua_getfield(L, -1, vocation[fields].name);
luaL_checktype(L, -1, vocation[fields].type);
str = vocation[fields].name;
if (lua_isnumber(L, -1)) {
if (str == "id") {
//id = g_lua.getNumber<uint16_t>(L, -1);
}
else if (str == "clientid") {
voc.clientId = g_lua.getNumber<uint16_t>(L, -1);
}
else if (str == "gaincap") {
voc.gainCap = g_lua.getNumber<uint32_t>(L, -1);
}
else if (str == "gainhp") {
voc.gainHP = g_lua.getNumber<uint32_t>(L, -1);
}
else if (str == "gainmana") {
voc.gainMana = g_lua.getNumber<uint32_t>(L, -1);
}
else if (str == "gainhpticks") {
voc.gainHealthTicks = g_lua.getNumber<uint32_t>(L, -1);
}
else if (str == "gainhpamount") {
voc.gainHealthAmount = g_lua.getNumber<uint32_t>(L, -1);
}
else if (str == "gainmanaticks") {
voc.gainManaTicks = g_lua.getNumber<uint32_t>(L, -1);
}
else if (str == "gainmanaamount") {
voc.gainManaAmount = g_lua.getNumber<uint32_t>(L, -1);
}
else if (str == "manamultiplier") {
voc.manaMultiplier = g_lua.getNumber<float>(L, -1);
}
else if (str == "attackspeed") {
voc.attackSpeed = g_lua.getNumber<uint32_t>(L, -1);
}
else if (str == "basespeed") {
voc.baseSpeed = g_lua.getNumber<uint32_t>(L, -1);
}
else if (str == "soulmax") {
voc.soulMax = g_lua.getNumber<uint32_t>(L, -1);
}
else if (str == "gainsoulticks") {
voc.gainSoulTicks = g_lua.getNumber<uint32_t>(L, -1);
}
else if (str == "fromvoc") {
voc.fromVocation = g_lua.getNumber<uint32_t>(L, -1);
}
}
if (lua_isstring(L, -1)) {
if (str == "name") {
voc.name = lua_tostring(L, -1);
}
else if (str == "description") {
voc.description = lua_tostring(L, -1);
}
}
if (lua_istable(L, -1)) {
if (str == "formula") {
std::string formstr;
for (int n = 0; formula[n].name != NULL; n++) {
lua_getfield(L, -1, formula[n].name);
luaL_checktype(L, -1, formula[n].type);
formstr = formula[n].name;
switch (lua_type(L, -1)) {
case LUA_TNUMBER:
if (formstr == "meleeDamage") {
voc.meleeDamageMultiplier = g_lua.getNumber<float>(L, -1);
}
else if (formstr == "distDamage") {
voc.distDamageMultiplier = g_lua.getNumber<float>(L, -1);
}
else if (formstr == "defense") {
voc.defenseMultiplier = g_lua.getNumber<float>(L, -1);
}
else if (formstr == "armor") {
voc.armorMultiplier = g_lua.getNumber<float>(L, -1);
}
break;
}
lua_pop(L, 1);
}
}
else if (str == "skill") {
std::string skillstr;
for (int x = 0; skill[x].name != NULL; x++) {
lua_getfield(L, -1, skill[x].name);
luaL_checktype(L, -1, skill[x].type);
skillstr = skill[x].name;
switch (lua_type(L, -1)) {
case LUA_TNUMBER:
if (skillstr == "SKILL_FIST") {
voc.skillMultipliers[SKILL_FIST] = g_lua.getNumber<float>(L, -1);
}
else if (skillstr == "SKILL_CLUB") {
voc.skillMultipliers[SKILL_CLUB] = g_lua.getNumber<float>(L, -1);
}
else if (skillstr == "SKILL_SWORD") {
voc.skillMultipliers[SKILL_SWORD] = g_lua.getNumber<float>(L, -1);
}
else if (skillstr == "SKILL_AXE") {
voc.skillMultipliers[SKILL_AXE] = g_lua.getNumber<float>(L, -1);
}
else if (skillstr == "SKILL_DISTANCE") {
voc.skillMultipliers[SKILL_DISTANCE] = g_lua.getNumber<float>(L, -1);
}
else if (skillstr == "SKILL_SHIELD") {
voc.skillMultipliers[SKILL_SHIELD] = g_lua.getNumber<float>(L, -1);
}
else if (skillstr == "SKILL_FISHING") {
voc.skillMultipliers[SKILL_FISHING] = g_lua.getNumber<float>(L, -1);
}
break;
}
lua_pop(L, 1);
}
}
}
lua_pop(L, 1);
}
lua_pop(L, 1);
}
lua_close(L);
return true;
}
else {
pugi::xml_document doc;
pugi::xml_parse_result result = doc.load_file("data/XML/vocations.xml");
if (!result) {
printXMLError("Error - Vocations::loadFromXml", "data/XML/vocations.xml", result);
return false;
}
for (auto vocationNode : doc.child("vocations").children()) {
pugi::xml_attribute attr;
if (!(attr = vocationNode.attribute("id"))) {
std::cout << "[Warning - Vocations::loadFromXml] Missing vocation id" << std::endl;
continue;
}
uint16_t id = pugi::cast<uint16_t>(attr.value());
auto res = vocationsMap.emplace(std::piecewise_construct,
std::forward_as_tuple(id), std::forward_as_tuple(id));
Vocation& voc = res.first->second;
if ((attr = vocationNode.attribute("name"))) {
voc.name = attr.as_string();
}
if ((attr = vocationNode.attribute("clientid"))) {
voc.clientId = pugi::cast<uint16_t>(attr.value());
}
if ((attr = vocationNode.attribute("description"))) {
voc.description = attr.as_string();
}
if ((attr = vocationNode.attribute("gaincap"))) {
voc.gainCap = pugi::cast<uint32_t>(attr.value()) * 100;
}
if ((attr = vocationNode.attribute("gainhp"))) {
voc.gainHP = pugi::cast<uint32_t>(attr.value());
}
if ((attr = vocationNode.attribute("gainmana"))) {
voc.gainMana = pugi::cast<uint32_t>(attr.value());
}
if ((attr = vocationNode.attribute("gainhpticks"))) {
voc.gainHealthTicks = pugi::cast<uint32_t>(attr.value());
}
if ((attr = vocationNode.attribute("gainhpamount"))) {
voc.gainHealthAmount = pugi::cast<uint32_t>(attr.value());
}
if ((attr = vocationNode.attribute("gainmanaticks"))) {
voc.gainManaTicks = pugi::cast<uint32_t>(attr.value());
}
if ((attr = vocationNode.attribute("gainmanaamount"))) {
voc.gainManaAmount = pugi::cast<uint32_t>(attr.value());
}
if ((attr = vocationNode.attribute("manamultiplier"))) {
voc.manaMultiplier = pugi::cast<float>(attr.value());
}
if ((attr = vocationNode.attribute("attackspeed"))) {
voc.attackSpeed = pugi::cast<uint32_t>(attr.value());
}
if ((attr = vocationNode.attribute("basespeed"))) {
voc.baseSpeed = pugi::cast<uint32_t>(attr.value());
}
if ((attr = vocationNode.attribute("soulmax"))) {
voc.soulMax = pugi::cast<uint16_t>(attr.value());
}
if ((attr = vocationNode.attribute("gainsoulticks"))) {
voc.gainSoulTicks = pugi::cast<uint16_t>(attr.value());
}
if ((attr = vocationNode.attribute("fromvoc"))) {
voc.fromVocation = pugi::cast<uint32_t>(attr.value());
}
for (auto childNode : vocationNode.children()) {
if (strcasecmp(childNode.name(), "skill") == 0) {
pugi::xml_attribute skillIdAttribute = childNode.attribute("id");
if (skillIdAttribute) {
uint16_t skill_id = pugi::cast<uint16_t>(skillIdAttribute.value());
if (skill_id <= SKILL_LAST) {
voc.skillMultipliers[skill_id] = pugi::cast<float>(childNode.attribute("multiplier").value());
}
else {
std::cout << "[Notice - Vocations::loadFromXml] No valid skill id: " << skill_id << " for vocation: " << voc.id << std::endl;
}
}
else {
std::cout << "[Notice - Vocations::loadFromXml] Missing skill id for vocation: " << voc.id << std::endl;
}
}
else if (strcasecmp(childNode.name(), "formula") == 0) {
pugi::xml_attribute meleeDamageAttribute = childNode.attribute("meleeDamage");
if (meleeDamageAttribute) {
voc.meleeDamageMultiplier = pugi::cast<float>(meleeDamageAttribute.value());
}
pugi::xml_attribute distDamageAttribute = childNode.attribute("distDamage");
if (distDamageAttribute) {
voc.distDamageMultiplier = pugi::cast<float>(distDamageAttribute.value());
}
pugi::xml_attribute defenseAttribute = childNode.attribute("defense");
if (defenseAttribute) {
voc.defenseMultiplier = pugi::cast<float>(defenseAttribute.value());
}
pugi::xml_attribute armorAttribute = childNode.attribute("armor");
if (armorAttribute) {
voc.armorMultiplier = pugi::cast<float>(armorAttribute.value());
}
}
}
}
return true;
}
}
In configmanager.cpp look for this
Code:
boolean[CLASSIC_EQUIPMENT_SLOTS] = getGlobalBoolean(L, "classicEquipmentSlots", false);
Code:
boolean[USE_XML] = getGlobalBoolean(L, "useXML", false);
Find this in configmanager.h
Code:
CLASSIC_EQUIPMENT_SLOTS,
Code:
USE_XML,
In luascript.cpp find this
Code:
registerEnumIn("configKeys", ConfigManager::CLASSIC_EQUIPMENT_SLOTS)
Code:
registerEnumIn("configKeys", ConfigManager::USE_XML)
Place this anywhere in config.lua
Code:
useXML = false
Now create a new folder in data called LUA and save this as vocations.lua
Code:
local classes = {
['None'] = {
hp = 5, mana = 0, desc = "none.",
clientid = 0,
gaincap = 0,
gainhpticks = 5,
gainhpamount = 5,
gainmanaticks = 5,
gainmanaamount = 5,
manamultiplier = 5,
attackspeed = 2000,
basespeed = 220,
soulmax = 100,
gainsoulticks = 5,
fromvoc = 0,
formula = {
meleeDamage = 1.0,
distDamage = 1.0,
defense = 1.0,
armor = 1.0
},
skill = {
SKILL_FIST = 1.1,
SKILL_CLUB = 1.1,
SKILL_SWORD = 1.1,
SKILL_AXE = 1.1,
SKILL_DISTANCE = 1.1,
SKILL_SHIELD = 1.1,
SKILL_FISHING = 1.1,
}
}
}
vocationsTable = {}
local i = 1
for vocationName, attributes in pairs(classes) do
vocationsTable[i] = {
id = i,
name = vocationName,
clientid = attributes.clientid,
description = attributes.desc,
gaincap = attributes.gaincap,
gainhp = attributes.hp,
gainmana = attributes.mana,
gainhpticks = attributes.gainhpticks,
gainhpamount = attributes.gainhpamount,
gainmanaticks = attributes.gainmanaticks,
gainmanaamount = attributes.gainmanaamount,
manamultiplier = attributes.manamultiplier,
attackspeed = attributes.attackspeed,
basespeed = attributes.basespeed,
soulmax = attributes.soulmax,
gainsoulticks = attributes.gainsoulticks,
fromvoc = attributes.fromvoc,
formula = {
meleeDamage = attributes.formula.meleeDamage,
distDamage = attributes.formula.distDamage,
defense = attributes.formula.defense,
armor = attributes.formula.armor
},
skill = {
SKILL_FIST = attributes.skill.SKILL_FIST,
SKILL_CLUB = attributes.skill.SKILL_CLUB,
SKILL_SWORD = attributes.skill.SKILL_SWORD,
SKILL_AXE = attributes.skill.SKILL_AXE,
SKILL_DISTANCE = attributes.skill.SKILL_DISTANCE,
SKILL_SHIELD = attributes.skill.SKILL_SHIELD,
SKILL_FISHING = attributes.skill.SKILL_FISHING,
}
}
i = i + 1
end
vocations = vocationsTable
In otserv.cpp look for this.
Code:
//load vocations
std::cout << ">> Loading vocations" << std::endl;
if (!g_vocations.loadFromXml()) {
startupErrorMessage("Unable to load vocations!");
return;
}
Code:
//load vocations
bool useXML = g_config.getBoolean(ConfigManager::USE_XML);
std::string from = (useXML ? "from xml" : "from lua");
std::cout << ">> Loading vocations " << from << std::endl;
if (!g_vocations.loadFromXml()) {
if (useXML) {
startupErrorMessage("Unable to load vocations.xml!");
}
else {
startupErrorMessage("Unable to load vocations.lua!");
}
return;
}
Last edited: