Brazil's biggest MU Online portal — since 2003
Tutorial Intermediate Servidor

How to Add VIP and Bonus Systems to Your MU Online Server

Learn how to configure VIP ranks and bonus systems on your MU Online private server — from database setup to in-game rewards and automated expiration.

VI ViciadosMU Team · Updated on 4 jul 2026 · ⏱ 18 min read

Introduction: Why VIP and Bonus Systems Matter

A well-designed VIP and bonus system gives server administrators two powerful tools: a way to reward dedicated players and a mechanism to keep the economy balanced through controlled benefit tiers. Unlike direct stat boosts handed out arbitrarily, a structured VIP system is transparent, auditable, and easy to modify without touching core game logic.

This guide covers the full implementation pipeline — database schema, server-side configuration files, and the in-game command hooks that glue everything together. It assumes you are running a Season 6 or Season 9 server file on Windows Server with SQL Server 2014 or later.

Nota: This tutorial focuses on server files that expose configuration through .ini files and stored procedures. If your server file uses a different approach (XML configs, Lua scripts), the concepts are identical but the file paths and syntax will differ.

Setting Up the VIP Database Schema

Before touching any configuration file, lay the groundwork in SQL Server. Open SQL Server Management Studio and connect to your MuOnline database instance.

Run the following script to create the core tables:

-- VIP tier definitions
-- TierID → 1 = Bronze, 2 = Silver, 3 = Gold
CREATE TABLE [dbo].[VipTiers] (
    TierID          INT PRIMARY KEY,
    TierName        NVARCHAR(20)  NOT NULL,
    ExpMultiplier   FLOAT         NOT NULL DEFAULT 1.0,  -- e.g. 1.5 → +50% EXP
    DropMultiplier  FLOAT         NOT NULL DEFAULT 1.0,  -- e.g. 1.2 → +20% drops
    ZenMultiplier   FLOAT         NOT NULL DEFAULT 1.0,
    StorageSlots    INT           NOT NULL DEFAULT 0,    -- extra warehouse rows
    DailyBonusPts   INT           NOT NULL DEFAULT 0
);

-- Insert default tiers
INSERT INTO [dbo].[VipTiers] VALUES
(1, 'Bronze', 1.30, 1.10, 1.10, 0,  50),
(2, 'Silver', 1.60, 1.25, 1.20, 1, 120),
(3, 'Gold',   2.00, 1.50, 1.40, 2, 250);

-- Per-account VIP records
CREATE TABLE [dbo].[AccountVip] (
    AccountID       VARCHAR(10)   PRIMARY KEY,
    TierID          INT           NOT NULL DEFAULT 1,
    StartDate       DATETIME      NOT NULL DEFAULT GETDATE(),
    EndDate         DATETIME      NOT NULL,
    IsActive        BIT           NOT NULL DEFAULT 1,
    GrantedBy       VARCHAR(10)   NULL,       -- GM who granted it
    SuspendedByBan  BIT           NOT NULL DEFAULT 0,
    FOREIGN KEY (TierID) REFERENCES VipTiers(TierID)
);

-- Bonus points ledger
CREATE TABLE [dbo].[BonusPoints] (
    EntryID         INT IDENTITY(1,1) PRIMARY KEY,
    AccountID       VARCHAR(10)   NOT NULL,
    Points          INT           NOT NULL,
    Source          VARCHAR(50)   NOT NULL,   -- 'DailyVip', 'Event', 'GM'
    AwardedAt       DATETIME      NOT NULL DEFAULT GETDATE(),
    ExpiresAt       DATETIME      NULL        -- NULL → never expires
);

> [!WARNING] > Always back up your MuOnline database before running DDL statements. A failed migration that partially creates tables can leave foreign key constraints in a broken state, which will prevent GameServer from starting.

Once the tables exist, create the stored procedure that GameServer will call each time it needs to resolve a player's active benefits:

CREATE PROCEDURE [dbo].[usp_GetVipBenefits]
    @AccountID VARCHAR(10)
AS
BEGIN
    SET NOCOUNT ON;

    SELECT
        av.TierID,
        vt.TierName,
        vt.ExpMultiplier,
        vt.DropMultiplier,
        vt.ZenMultiplier,
        vt.StorageSlots,
        vt.DailyBonusPts,
        av.EndDate,
        -- Remaining days → useful for in-game display
        DATEDIFF(DAY, GETDATE(), av.EndDate) AS DaysRemaining
    FROM [dbo].[AccountVip] av
    INNER JOIN [dbo].[VipTiers] vt ON av.TierID = vt.TierID
    WHERE av.AccountID = @AccountID
      AND av.IsActive   = 1
      AND av.EndDate    > GETDATE()
      AND av.SuspendedByBan = 0;
END;

Configuring the Server Files

With the database ready, open your server directory and locate the main configuration folder. The path varies by server file edition, but it is typically:

GameServer\Config\

Inside you will find files such as GameServerInfo.ini and ExpRate.ini. Create or edit a file named VipSystem.ini:

; VipSystem.ini — loaded by GameServer on startup
; Lines beginning with ; are comments

[VIP_SYSTEM]
Enabled             = 1           ; 0 → disable entirely without removing tables
CheckIntervalMin    = 60          ; how often (minutes) expiry is re-checked
ExpiredTierFallback = 0           ; TierID to apply on expiry (0 → no VIP)

[BONUS_POINTS]
Enabled             = 1
DailyAwardHour      = 0           ; UTC hour when daily points are credited (0 → midnight)
MaxAccumulatedPts   = 99999       ; cap so the ledger does not grow unbounded
PointsExpiryDays    = 90          ; 0 → never expire organically awarded points

[GM_COMMANDS]
; Command format used in-game: /vipgrant <account> <tier> <days>
GrantVipCommand     = /vipgrant
RevokeVipCommand    = /viprevoke
AddPointsCommand    = /addpts
CheckVipCommand     = /vipinfo

> [!TIP] > Keep CheckIntervalMin at 60 or higher in production. Setting it too low (under 10 minutes) creates frequent SQL round-trips that can cause noticeable lag on servers with 200+ concurrent players. The expiry check is not time-critical — a player whose VIP lapses at 2:00 AM will not notice a delay until 3:00 AM.


Registering GM Commands

Open GameServer\Source\GMCommands.cpp (or the equivalent handler file for your server files). Locate the section where existing / commands are registered and add entries for the new VIP commands.

The pattern follows the existing command table format:

// VIP command handlers — add alongside existing GM command entries
{ "/vipgrant",  CMD_GM_LEVEL_3, CmdVipGrant,  "[account] [tier 1-3] [days]" },
{ "/viprevoke", CMD_GM_LEVEL_3, CmdVipRevoke, "[account]"                   },
{ "/addpts",    CMD_GM_LEVEL_2, CmdAddPoints, "[account] [points]"          },
{ "/vipinfo",   CMD_GM_LEVEL_1, CmdVipInfo,   "[account]"                   },

Each handler function calls the corresponding stored procedure via your server's existing ODBC or ADO connection wrapper, passing the parameters extracted from the command string.


Testing the System Before Going Live

Never push a new system directly to a live server. Use the following checklist on a staging instance:

  1. Grant a VIP tier to a test account: /vipgrant testaccount 2 30
  2. Log in with that account and verify the EXP multiplier is active by killing a monster and comparing the EXP gain against the base rate documented in ExpRate.ini.
  3. Wait for (or manually trigger) the daily bonus point credit and confirm an entry appears in the BonusPoints table.
  4. Set EndDate to a past timestamp in the database and wait one check interval to confirm the account loses VIP status cleanly.
  5. Verify the /vipinfo command returns accurate data for both VIP and non-VIP accounts.

Log all test results before promoting the configuration to production. If your server file supports hot-reload of .ini files via a console command, use it — restarting GameServer for every config tweak wastes time and drops active connections.


Maintaining the System Over Time

A VIP system generates ongoing database growth. Schedule a SQL Server Agent job (or a Windows Task Scheduler entry pointing to a .sql script) to run weekly maintenance:

-- Deactivate expired VIP records older than 30 days (keeps history)
UPDATE [dbo].[AccountVip]
SET    IsActive = 0
WHERE  EndDate < DATEADD(DAY, -30, GETDATE())
  AND  IsActive = 1;

-- Purge expired bonus point entries beyond the configured expiry window
DELETE FROM [dbo].[BonusPoints]
WHERE  ExpiresAt IS NOT NULL
  AND  ExpiresAt < GETDATE();

Keeping old AccountVip rows with IsActive = 0 rather than deleting them gives you an audit trail. If a player opens a support ticket claiming their VIP was lost, you can query the history directly without digging through backups.

Nota: Document every change you make to the VIP configuration in a server changelog file. When something breaks weeks later, that log is the first place to look. A simple dated text file in the server root is enough — it does not need to be a formal system.

Summary

You now have a complete, layered VIP and bonus system:

  • Tier definitions stored in SQL with individual multipliers per benefit category.
  • Per-account records with start/end dates, active flags, and ban-suspension support.
  • A separate bonus points ledger with source tracking and optional expiry.
  • Server-side .ini configuration that controls behavior without requiring recompilation.
  • GM commands at three privilege levels for granting, revoking, and inspecting VIP status.

The same pattern scales to additional tiers or new benefit types (for example, reduced cooldowns or access to exclusive maps) by adding columns to VipTiers and updating the stored procedure and .ini mappings accordingly.

Perguntas frequentes

What database tables are required for the VIP system?

At minimum you need a VIP account table (AccountID, VipType, StartDate, EndDate, IsActive) and a VIP benefits table that maps each VIP tier to its stat multipliers and drop-rate bonuses. Most Season 6+ server files already include stub tables — check your MuOnline database for existing entries before creating new ones.

How do I prevent VIP benefits from stacking with each other?

In your VIP benefit calculation function, apply a tier priority check before summing multipliers. Store the active tier in a session variable and only apply the highest matching tier. Using a CASE statement in SQL or an if-else chain in your GameServer source is the safest approach.

Can I grant time-limited bonus points without a VIP tier?

Yes. Create a separate BonusPoints table with AccountID, Points, ExpirationDate, and Source columns. Award points through a stored procedure called from GM commands or event scripts. Points are consumed independently of VIP status.

What happens to active VIP when a player is banned?

The VIP record stays in the database but the account is locked. When the ban is lifted, check whether EndDate is still in the future. If not, the tier has expired naturally. You may want to add a flag column (SuspendedByBan BIT) to pause the timer during the ban period.

VI

ViciadosMU Team

Equipe editorial do ViciadosMU — portal de MU Online no ar desde 2003.

Keep reading

Related articles