EOSERV Forum > EOSERV > Tutorial: Automatic NPC Experience System
Page: << 1 >>
Tutorial: Automatic NPC Experience System
Author Message
Post #202717 Tutorial: Automatic NPC Experience System

I have been brainstorming ways to balance out our private server, in regards to the monster/npc experience.

I decided to roll out an automatic experience system with a configurable formula, and also includes a very simple npc level system. I'll share it with the community.

Note: If anyone can help me come up with a better formula, that would be very appreciated!

I don't have time for a proper tutorial, this is the best I can do:

http://pastebin.com/v8EsPGFS

The experience system can work without the level system. So you can choose to not add the level system code. I just added the level system so that formulas can give out bonus experienced based on the level range.


Sample of the INI file:

## NPCNameSearchLevelPrefix / NPCNameSearchLevelSuffix (string)
# Searches for the NPC level in the NPC name between NPCNameSearchLevelPrefix and NPCNameSearchLevelSuffix strings.
# If NPCNameSearchLevelPrefix is empty. It will search from the beginning of the NPC name.
# If NPCNameSearchLevelSuffix is empty. It will search until the end of the NPC name.
# If both NPCNameSearchLevelPrefix and NPCNameSearchLevelSuffix are empty. It will not search for a level.
# The level is stored as "npc->level" which can be referenced by code or via NPCExperienceAutoFormula "level" variable.
# Example NPC Names: "Goat [Lvl 0]", "Piglet [Lvl 1]"
# Note: If no level is found or searched in the name text, level 0 will be set.
NPCNameSearchLevelPrefix = [Lvl
NPCNameSearchLevelSuffix = ]

## NPCExperienceType (number)
# Sets how NPC experience is calculated.
# 0 = Manual experience, defined in pub enf file. This is the default behavior.
# 1 = Automatic experience, defined by NPCExperienceAutoFormula.
# 2 = Manual with fallback to automatic experience. If manual experience (in the pub enf file) is set to 0, it will fall back to automatic experience (defined by NPCExperienceAutoFormula).
NPCExperienceType = 1

## NPCExperienceAutoFormula (number)
# Formula for automatic experience calculation (when NPCExperienceType is set to 1 or 2).
# Written in Reverse Polish notation: http://en.wikipedia.org/wiki/Reverse_Polish_notation
# Infix / RPN online converter: http://www.mathblog.dk/tools/infix-postfix-converter/
#
# Example (experience specified by ENF pub file, with a bonus between -50% and 50% when character is between 10 levels of the NPC level):
#   char_level level - 10 min 10- max 0.05 * experience * experience +   0 max
# Example (flat experience based on NPC stats):
#   10 hp / mindam maxdam + + 2 accuracy evade + armor + / + 5 *
# Example (scaling experience based on NPC stats, with a bonus between -50% and 50% when between 10 levels of the NPC level):
#   char_level level - 10 min 10- max 0.05 *   10 hp / mindam maxdam + + 2 accuracy evade + armor + / + 5 *   *   10 hp / mindam maxdam + + 2 accuracy evade + armor + / + 5 *   +   0 max
NPCExperienceAutoFormula = char_level level - 10 min 10- max 0.05 *   10 hp / mindam maxdam + + 2 accuracy evade + armor + / + 5 *   *   10 hp / mindam maxdam + + 2 accuracy evade + armor + / + 5 *   +   0 max
---
Just your friendly neighborhood Programmer-Man!
7 years, 7 weeks ago
Post #202727 Re: Tutorial: Automatic NPC Experience System

Just a heads up the system also does 50% increases and decreases in exp rate based on your level as a player when killing certain mobs.

The system does not DISPLAY the mob level for you but it will detect a level on its own (mentally in a sense)

I suggest using google spreadsheet if you are curious exactly what level the mob is (through this formula)

We are thinking about displaying the level of the mobs through the pub file name (example: Crow Lv1)

but, haven't fully decided yet.

---
Graphics Designer.
"I'll keep believing in the future, not caring if anyone laughs at me"
Hi : D I am me!
7 years, 7 weeks ago
Post #202729 Re: Tutorial: Automatic NPC Experience System

I extended the system to allow optional configurable variables inside of  NPCExperienceAutoFormula, to make it easier to create complex formulas. As well as an added "char_party" variable so that you can create bonus exp when in a party.

Here's another tutorial (requires finishing the first tutorial here http://pastebin.com/v8EsPGFS ):


(Optional) Inside config\npc_experience.ini, add the following:
## NPCExperienceAutoFormula_[Variable_Name] (number)
# Optional variables to reference in NPCExperienceAutoFormula.
# Each variable is also a written in Reverse Polish notation: http://en.wikipedia.org/wiki/Reverse_Polish_notation
# Variables can be named anything, as long as it's prefixed with "NPCExperienceAutoFormula_". (Number characters not tested)
# Variables can reference other variables, in order of line numbers. You can only reference a variable above the current variable.
# Variables are referenced as a lowercase string without the "NPCExperienceAutoFormula_" prefix.
# Example (experience specified by ENF pub file, with a bonus of 50% when in a party, and with a bonus between -50% and 50% when between 10 levels of the NPC level):
# (NPCExperienceAutoFormula_XP = xp; NPCExperienceAutoFormula_XP_Level = xp_level; NPCExperienceAutoFormula_XP_Party = xp_party)
#   NPCExperienceAutoFormula = xp xp_level + xp_party + 0 max
#   NPCExperienceAutoFormula_XP = experience
#   NPCExperienceAutoFormula_XP_Level = char_level level - 10 min 10- max 0.05 * xp *
#   NPCExperienceAutoFormula_XP_Party = char_party 0.5 * xp *
NPCExperienceAutoFormula_XP_HP = 10 hp /
NPCExperienceAutoFormula_XP_DMG = mindam maxdam +
NPCExperienceAutoFormula_XP_Stats = 2 accuracy evade + armor + /
NPCExperienceAutoFormula_XP_Multiplier = 5
NPCExperienceAutoFormula_XP = xp_hp xp_dmg + xp_stats + xp_multiplier *
NPCExperienceAutoFormula_XP_Level = char_level level - 10 min 10- max 0.05 * xp *
NPCExperienceAutoFormula_XP_Party = char_party 0.5 * xp *

If you want to use the above variables, you can change NPCExperienceAutoFormula to the following:

 NPCExperienceAutoFormula = xp xp_level + xp_party + 0 max


In scr\character.cpp, inside the  "void Character::FormulaVars(std::unordered_map<std::string, double> &vars, std::string prefix)" method. Add the following code:

vv((this->party ? true : false), "party")


In src\config.hpp, add the following public variable:
std::vector<std::string> keys;

In src\config.cpp, below line #125:
            this->operator[](key) = static_cast<util::variant>(val);

Add the following line:

            this->keys.push_back(key);

In src\world.hpp, add the following public declarations:
        std::unordered_map<std::string, std::string> npc_experience_vars;
        std::vector<std::string> npc_experience_vars_keys;
        void setup_npc_experience_vars();

In src\world.cpp, add the following method:
void World::setup_npc_experience_vars() {
    this->npc_experience_vars = {};
    this->npc_experience_vars_keys = {};

    std::string variablePrefix = "NPCExperienceAutoFormula_";
    for(auto const& key: this->config.keys) {
        auto res = std::mismatch(variablePrefix.begin(), variablePrefix.end(), key.begin());
        if (res.first == variablePrefix.end())
        {
            std::string autoKey = util::lowercase(key.substr(variablePrefix.length()));
            if (autoKey.length()) {
                std::string autoValue = static_cast<std::string>(this->config[key]);
                npc_experience_vars.insert({ autoKey, autoValue });
                npc_experience_vars_keys.push_back(autoKey);
            }
        }
    }
}

Inside the following method:

World::World(std::array<std::string, 6> dbinfo, const Config &eoserv_config, const Config &admin_config)

Anywhere below this line:

this->config = eoserv_config;

Add the following line:

setup_npc_experience_vars();


In src\npc.cpp, replace the following method:

unsigned short NPC::Experience(Character *character) {
    unsigned short experience = 0;
    int experienceType = this->map->world->config["NPCExperienceType"];
    // 0 = Manual experience, defined in pub enf file. This is the default behavior.
    // 1 = Automatic experience, defined by NPCExperienceAutoFormula.
    // 2 = Manual with fallback to automatic experience. If manual experience (in the pub enf file) is set to 0, it will fall back to automatic experience (defined by NPCExperienceAutoFormula).

    if (experienceType == 1 || experienceType == 2) { //Automatic experience || Manual with fallback to automatic experience
        if (experienceType == 2 && this->ENF().exp > 0) { //Manual experience
            experience = this->ENF().exp;
        } else { //Automatic experience
            std::unordered_map<std::string, double> formula_vars;
            this->FormulaVars(formula_vars);
            character->FormulaVars(formula_vars, "char_");
            formula_vars["hp"] = formula_vars["maxhp"];

            for(auto const& key: this->map->world->npc_experience_vars_keys) {
                formula_vars[key] = util::rpn_eval(util::rpn_parse(this->map->world->npc_experience_vars[key]), formula_vars);
            }

            experience = std::round(rpn_eval(rpn_parse(this->map->world->config["NPCExperienceAutoFormula"]), formula_vars));
        }
    } else { //Manual experience
        experience = this->ENF().exp;
    }
    return experience;
}

That's all.

Now you should be able to use optional variables like the following:

NPCExperienceAutoFormula = xp xp_level + xp_party + 0 max
NPCExperienceAutoFormula_XP_HP = 10 hp /
NPCExperienceAutoFormula_XP_DMG = mindam maxdam +
NPCExperienceAutoFormula_XP_Stats = 2 accuracy evade + armor + /
NPCExperienceAutoFormula_XP_Multiplier = 5
NPCExperienceAutoFormula_XP = xp_hp xp_dmg + xp_stats + xp_multiplier *
NPCExperienceAutoFormula_XP_Level = char_level level - 10 min 10- max 0.05 * xp *
NPCExperienceAutoFormula_XP_Party = char_party 0.5 * xp *
---
Just your friendly neighborhood Programmer-Man!
7 years, 7 weeks ago
Post #202734 Re: Tutorial: Automatic NPC Experience System

Very cool idea. Nice to see things like this being messed with.
Especially this specifically since server balance is pretty important.

---
EO Resources/Guides: â—„ eobud.boards.net â–º
7 years, 7 weeks ago
Post #202738 Re: Tutorial: Automatic NPC Experience System

Aren't there unused / unk values in the enf that can be used to set npc level and other various things as an option if someone doesnt like putting the level in the npc name?

(good to keep both options because custom servers might already be using unk values in the pub)

---
I not hacker

“Everybody is a genius. But if you judge a fish by its ability to climb a tree, it will live its
whole life believing that it is stupid.” - Albert Einstein : Really Great Quote Ramy!
7 years, 7 weeks ago
Post #202740 Re: Tutorial: Automatic NPC Experience System
Hacker_Alex posted: (8th Mar 2017, 12:46 am)

Aren't there unused / unk values in the enf that can be used to set npc level and other various things as an option if someone doesnt like putting the level in the npc name?

(good to keep both options because custom servers might already be using unk values in the pub)


That is a great question. I thought of this approach, but I think it's a bit tacky, and i'd rather assume the unknown values are used for other things instead of assume they are never used. Then again, if I could find out for certain if an unknown value is never used, id be happy to implement with that value in mind.

Then again, as you said, options are always great, I might implement support for that kind of option too.

Edit:

I added support for setting the NPC level via any ENF value (including unknown values), let me know if you would like a tutorial for it.

Example:

## NPCLevelENFVariable (string)
# The ENF pub variable to read for the level on npcs. (Not case sensitive)
# See eodata.hpp for a list of variables: template <class ENF> struct ENF_Data_Base
# Note: If not empty, it will override NPCNameSearchLevelPrefix and NPCNameSearchLevelSuffix. If empty, NPCNameSearchLevelPrefix and NPCNameSearchLevelSuffix will be used.
# Note: If no level is found via the specified variable, level 0 will be set.
# Default: (empty)
# [OVERRIDES NPCNameSearchLevelPrefix and NPCNameSearchLevelSuffix]
NPCLevelENFVariable = unkA
---
Just your friendly neighborhood Programmer-Man!
7 years, 7 weeks ago
Page: << 1 >>

EOSERV Forum > EOSERV > Tutorial: Automatic NPC Experience System