Levels and skills
XP, the level curve formula, the skill tree, and writing skills as addons.
Players have a level, from 1 up to rpgx_level_max (100), and XP towards the next one. The
bottom left of the HUD shows them: the level, with an XP bar next to it. Health and suit sit on top
of those, with stamina, mana and buffs above them. XP comes from:
- killing a spawn point's enemy: by its level, from the kill XP formula (default
10 * level: a level 3 enemy is 30 XP). Whoever kills it gets it. - turning in a quest with an XP reward (see Interactable NPCs).
- addons:
GAMEMODE:PlayerAddXP( ply, amount )(server).
"+30 XP" shows next to the bar as it comes in. A level up shows LEVEL UP in the middle of the
screen, refills stamina and mana (which grow by their per_level each level, see Stamina and mana)
and gives rpgx_skill_points_per_level (1) skill point to spend on skills. At the highest
level XP stops counting. Quests' minimum player level goes by it.
The level curve #
How much XP each level takes is a formula, set with a command in the console: by an owner in the game, or from the server console / RCON. It's saved in the database, so it survives restarts (and is the same on every server sharing a MySQL database, from their next restart).
rpgx_level_formula "100 * level ^ 1.5"
level is the level the player is at, and the result is the XP it takes to get from it to the next
one: here 100 for level 1 to 2, 283 for 2 to 3, 3,162 for 10 to 11. It's rounded to whole XP, at
least 1. With nothing after it, the command prints the current formula, what it comes out to for a
few levels, and the total XP from level 1 to the highest. rpgx_level_formula default puts the
default back. A formula that doesn't work is refused with the reason, and the old one stays.
Changing it never takes levels away, and a cheaper curve levels players up right away if they
already have the XP.
rpgx_kill_xp_formula "10 * level" works the same way for XP per kill, where level is the
enemy's level (0 or less = no XP).
Put the formula in quotes. What a formula can have:
| Write | Means | Example |
|---|---|---|
+ - * / |
add, subtract, multiply, divide | 50 * level + 100 |
^ |
to the power of | level ^ 2 (level squared), 1.1 ^ level (10% more every level) |
( ) |
work this part out first | (level + 1) * 50 |
sqrt(x) |
square root | 100 * sqrt(level) |
cbrt(x) |
cube root | 100 * cbrt(level) |
root(x, n) |
nth root | 100 * root(level, 4) |
% |
remainder after dividing | level % 5 (0 every 5th level) |
min(a, b, ...), max(a, b, ...) |
the smallest / biggest of them | max(100, 25 * level) (never under 100) |
floor(x), ceil(x), round(x), abs(x) |
round down / up / to nearest, without the minus | floor(level / 10) |
ln(x), log(x), log(x, b), exp(x) |
natural log, log base 10, log base b, e to the power of x | 100 * ln(level) + 50 |
pi, e, numbers like 1.5, .5, 2e3 |
constants (2e3 = 2000) |
pi * level |
The order things are worked out in, and the mistakes it saves you from:
- Parentheses first, then
^, then*/%, then+-. Solevel + 1 * 50islevel + 50; write(level + 1) * 50for 50 times level plus one.2 * 3 ^ 2is 18, not 36. - Always write the
*:2 * level, not2level;2 * (level + 1), not2(level + 1);(level + 1) * (level + 2), not(level + 1)(level + 2). The command tells you where it's missing. - Powers go right to left:
2 ^ 3 ^ 2is2 ^ 9(512). Write(2 ^ 3) ^ 2for 64. - A minus in front comes after the power:
-2 ^ 2is -4,(-2) ^ 2is 4. A negative power works:2 ^ -1is 0.5. - Roots as powers need parentheses around the fraction:
level ^ (1/2)is the square root (same assqrt(level)),level ^ (1/3)the cube root.level ^ 1/2is(level ^ 1) / 2, half the level. - Every level has to come out as a number. A root of something negative (
sqrt(level - 5)below level 5) or dividing by zero (100 / (level - 3)at level 3) doesn't, so the formula is refused and the command says at which level. - Spaces don't matter, and neither do capitals (
LEVEL). Only numbers,level,pi,e, the functions above and+ - * / % ^ ( ) ,are allowed; a formula is worked out, never run as code.
Some curves, as XP for level 1, 2, 5 and 10:
| Formula | 1 | 2 | 5 | 10 | |
|---|---|---|---|---|---|
100 * level ^ 1.5 |
100 | 283 | 1,118 | 3,162 | The default: steeper every level |
50 * level ^ 2 + 100 |
150 | 300 | 1,350 | 5,100 | Steeper still |
1000 * 1.1 ^ level |
1,100 | 1,210 | 1,611 | 2,594 | 10% more each level: gentle at first, very steep much later |
100 * sqrt(level) |
100 | 141 | 224 | 316 | Flattens out |
(level + 1) * 50 |
100 | 150 | 300 | 550 | The same step every level |
max(100, 25 * level) |
100 | 100 | 125 | 250 | Flat 100 until level 4, then rising |
Skills #
The inventory's Skills tab is the skill tree. It builds itself from whatever skills are installed: skills that need nothing are the top row, and every other skill sits below the skills it needs, with a line from each one labelled with the level it needs (green once you have it). Rows wider than the window wrap. Each box shows the skill's icon and its level out of its cap. The edge is gold at the cap, green if you can raise it now, blue if you have some of it, and grey otherwise. Hovering shows what it does, what the next level costs and what it needs (✔ / ✘), or why it can't be raised. Click to put points into it. The top of the tab shows your level, XP and unspent skill points.
- Every skill has its own level cap and skill points per level (usually 1). A skill with 0 points per level can't be bought at all: only quest rewards raise it.
- A skill can need a player level, and other skills at a level ("Bonus stamina at level 3"). One that needs a skill that isn't installed stays in the tree but can't be learned.
- Quest rewards can give levels of a skill (see Interactable NPCs): for free, whatever it needs, up to its cap. Given levels are kept apart from bought ones.
- Built in: Bonus stamina and Bonus mana, each +
rpgx_skill_bonus_stamina/rpgx_skill_bonus_mana(10) max per level, up to level 10, 1 point per level. - Skills are saved as they change. A skill whose addon has been removed from the server is deleted
from players when they join, and its points come back. If a skill's cap goes down, bought levels
come off first and their points come back. If a player has spent more points than they have
(their level was lowered, or
rpgx_skill_points_per_levelwas), their bought levels are reset and they spend the points again. Given levels always stay.
Commands, for owners (permission levels) and the server console:
| Command | Does |
|---|---|
rpgx_level_formula ["formula" | default] |
Shows or sets the level curve (see The level curve) |
rpgx_kill_xp_formula ["formula" | default] |
Shows or sets the XP per kill |
rpgx_xp <player> <amount> |
Gives XP (level ups included) |
rpgx_setlevel <player> <level> |
Sets the level, XP towards the next at 0 |
rpgx_skill_give <player> <skill> [levels] |
Gives levels of a skill, like a quest reward |
rpgx_skills_reset <player> |
Gives back every point they spent; given levels stay |
<player> is part of an online player's name, or their SteamID.
Skills from addons #
Skills are scripted like SWEPs (but aren't SWEPs): one file per skill, and the file name is its id.
The gamemode's own are in gamemode/skills/. Any addon's go in lua/rpgx/skills/*.lua (loaded
on both sides) and show up in the tree by themselves. For example lua/rpgx/skills/iron_lungs.lua:
SKILL.Name = "Iron lungs"
SKILL.Icon = "icon16/heart.png" -- any icon16/... (https://wiki.facepunch.com/gmod/Silkicons) or your own material
SKILL.MaxLevel = 5 -- its level cap
SKILL.Cost = 2 -- skill points per level; 0 = only quest rewards raise it
SKILL.PlayerLevel = 5 -- player level needed first
SKILL.Requires = { bonus_stamina = 3 } -- Bonus stamina at level 3 first
SKILL.Resources = { stamina = 15 } -- +15 max stamina per level
function SKILL:GetDescription( ply, level ) return "+15 max stamina per level. Now +" .. 15 * level .. "." end
function SKILL:OnLevelChanged( ply, level, old ) end -- server
Whatever a skill leaves out comes from its base: SKILL.Base, "base" when not set
(gamemode/skills/base.lua lists every value with its default). Any skill can be a base, and
self.BaseClass is the base, like with SWEPs. SKILL.Abstract = true makes one that isn't in the
tree.
| Value | Default | |
|---|---|---|
Name, Icon, Description |
"Skill", icon16/star.png, none |
What the tree shows (tooltip: Description or GetDescription) |
MaxLevel |
1 | Its level cap |
Cost |
1 | Skill points per level. 0 = can't be bought, only given. Or function( self, ply, level ) returning what raising it to level costs |
PlayerLevel |
1 | Player level it needs |
Requires |
none | Other skills at a level: { bonus_stamina = 3, other_skill = 1 } |
Resources |
none | Added to resource pools per level: { stamina = 10, mana = 5 }, or function( self, ply, level ) returning that |
Functions: GetDescription( ply, level ) (both; level 0 = not learned yet),
OnLevelChanged( ply, level, old ) (server: learned, given, reset, and when the player joins with
old 0), PlayerSpawn( ply, level ) (server, every spawn while it's above 0).
Also, both sides: GAMEMODE:PlayerLevel( ply ), GAMEMODE:PlayerXP( ply ) (XP, XP needed),
GAMEMODE:SkillLevel( ply, id ) or ply:GetSkillLevel( id ), GAMEMODE:SkillPoints( ply ),
GAMEMODE:SkillCanLearn( ply, id ), GAMEMODE:SkillList(), GAMEMODE:RegisterSkill( id, table ).
Server: GAMEMODE:PlayerAddXP( ply, amount ), GAMEMODE:SkillGrant( ply, id, levels ),
GAMEMODE:SkillLearn( ply, id ), GAMEMODE:SkillsReset( ply ), GAMEMODE:PlayerSetLevel( ply, level ),
and the hooks RPGXLevelUp( ply, level, old ), RPGXGainedXP( ply, amount, why ),
RPGXSkillChanged( ply, id, level, old ) and RPGXLevelsLoaded( ply ).