aslain.dev
0%
01 Hizmetler 02 Hakkımda 03 Projeler 04 Stack 05 Blog 06 İletişim
← Tüm makaleler Metin2

Metin2 Bonus Editing: Attr Tables and Apply Types

Those green lines a player sees when they hover over an item — "Max HP +500", "Attack speed +8" — are the soul of a server. Metin2 bonus editing is the craft of deciding which bonus can roll on which item, with what probability and at what value. All of it lives in two tables inside the player database and in the apply types of the game core. In this guide I'll walk through the table logic, the probability system and how to add a brand-new bonus from scratch, using the same setup as my own server, Runa2.

Two tables: item_attr and item_attr_rare

The bonus pool lives in two tables in the player database:

  • item_attr — the pool the normal (1st–4th) bonus lines roll from.
  • item_attr_rare — a separate pool for the 5th/6th (rare) line, usually added by a special item.

Each row holds an apply type, a prob (probability weight), value tiers lv1lv5, and on/off columns that say which item types it can roll on:

SELECT apply, prob, lv1, lv2, lv3, lv4, lv5
FROM item_attr
WHERE weapon = 1
ORDER BY prob DESC;

The slot columns are typically weapon, body, wrist, foots, neck, head, shield and ear. A 1 means the bonus can appear on that item type; a 0 means it can't.

How prob works: weight, not percentage

A common misconception: prob is not a percentage. When the core gives a bonus to an item, it sums the prob values of every row flagged for that slot (e.g. weapon=1) and rolls within that total. So a row's chance is its own prob / the sum of all probs for that slot. Consequently:

  • To see a bonus more often, raise its prob.
  • Scaling every value proportionally does not change the relative odds — only the total grows.
  • To remove a bonus from a slot entirely, setting its slot column to 0 is safer than deleting the row.

lv1–lv5: the value tiers

When a bonus is added to an item, the rolled value comes from the lv1lv5 columns, with lv1 being the weakest tier and lv5 the strongest. For example, to strengthen the HP-steal bonus on weapons:

UPDATE item_attr
SET lv1 = 1, lv2 = 2, lv3 = 3, lv4 = 4, lv5 = 6
WHERE apply = 'STEAL_HP';

Note: the apply column stores the apply type without the "APPLY_" prefix — i.e. MAX_HP, ATT_SPEED, STEAL_HP. These names must match the table in the game core.

Apply types: where do the names come from?

Every apply type is bound to a number and a point (stat) type in the game core. That mapping lives in the aApplyInfo array in srcs/game/src/constants.cpp:

const TValueName aApplyInfo[MAX_APPLY_NUM] =
{
    { "NONE",       APPLY_NONE,       POINT_NONE },
    { "MAX_HP",     APPLY_MAX_HP,     POINT_MAX_HP },
    { "STR",        APPLY_STR,        POINT_ST },
    { "ATT_SPEED",  APPLY_ATT_SPEED,  POINT_ATT_SPEED },
    { "STEAL_HP",   APPLY_STEAL_HP,   POINT_STEAL_HP },
    // ...
};

The first column ("MAX_HP") is exactly the apply value in the DB. The second is the APPLY_ enum from length.h, and the third is the POINT_ type that says which stat the value is written to. To add an existing bonus you only need a DB row — its name is already defined in this table.

Opening an existing bonus to a new item type

Say you want the HP-steal bonus to also roll on bracelets. All you do is update the slot column on that row:

UPDATE item_attr
SET wrist = 1
WHERE apply = 'STEAL_HP';

Adding a new bonus to the pool is just an INSERT:

INSERT INTO item_attr
  (apply, prob, lv1, lv2, lv3, lv4, lv5,
   weapon, body, wrist, foots, neck, head, shield, ear)
VALUES
  ('CRITICAL_PCT', 250, 1, 2, 3, 4, 5,
   1, 0, 0, 0, 0, 0, 0, 0);

Adding a genuinely NEW bonus (apply)

If you want to define a brand-new effect that doesn't exist in the pool, the DB isn't enough; you have to touch both the server and client source. The order is:

  • length.h — add the new type to the APPLY_ enum and update MAX_APPLY_NUM.
  • constants.cpp — add the { "NAME", APPLY_NAME, POINT_NAME } row to aApplyInfo.
  • char.cpp / char_battle.cpp — implement the PointChange / effect-application logic for the new POINT_ type (if it's a new point type).
  • Client — the apply numbers in item_length.h must be identical to the server; otherwise the tooltip shows the wrong bonus. Then add the new text to the apply-name dictionary in root/uiToolTip.py and to the locale files.

If the numbers drift between server and client, a bonus the server calls "+5 STR" shows up in-game as "+5 something else" — which is why keeping the two sides in sync is critical.

Deploying the change

The item_attr tables are read by the DB core at startup and pushed to the game core, so changing the SQL alone has no immediate effect. The typical flow: apply the change, then restart the db and game cores. If you touched the source (a new apply type), you also need to recompile and deploy the new binary. Before going live, always refresh a couple of items on a test server and confirm the bonuses roll correctly.

Frequently asked questions

Does raising prob guarantee the bonus rolls?

No. prob is a weight; the chance is your row's prob over the sum of all probs for that slot. For a guarantee you'd have to lower the other rows' probs or reduce the options on that slot.

I changed the SQL but nothing changed in-game — why?

Because the attr tables aren't re-read while running. You need to restart the db and game cores; only after that do newly granted bonuses use the updated pool.

What's the difference between item_attr and item_attr_rare?

item_attr is for the normal 1st–4th bonus lines, while item_attr_rare is a separate pool for the rare 5th/6th line. They're triggered by different items/actions.

Want a balanced bonus system for your server? From attr tables to new apply types, I can design and balance your bonus system from scratch — get in touch.

Bu kategorideki tüm yazılar →

Devamı için