The most compatible way to script this would be to make it a story script. I wrote a tutorial for that recently: Your First Story Script.

Essentially, your story script could look like this:
So as I was writing up some sample code, the idea was interesting to me, so I went ahead and wrote it like I probably would, using databases, procedures, and queries (which to me, are the fundamentals of reusable, extensible story script code). Here's what I came up with:

INIT:
Code
//DB_MyMod_BuffLevels(_Target, _BuffLevel)
//DB_MyMod_Buffs(_BuffLevel, _Status, _Turns, _Force)
DB_MyMod_Buffs(1, "BUFF1", 2.0, 0);
DB_MyMod_Buffs(2, "BUFF2", 2.0, 0);
DB_MyMod_Buffs(3, "BUFF3", 2.0, 0);
DB_MyMod_Buffs(4, "BUFF4", 2.0, 0);


KB:

//REGION HELPERS
QRY
QRY_MaxBuffLevelReached((INTEGER)_Level)
AND
SysCount("DB_MyMod_Buffs", 4, _Max)
AND
_Level >= _Max
THEN
DB_NOOP(1); // Dummy database to make query evaluate as true

QRY
QRY_BuffActive((CHARACTERGUID)_Target)
AND
DB_MyMod_Buffs(_BuffLevel, _Status, _Turns, _Force)
AND
HasActiveStatus(_Target, _Status, 1)
THEN
DB_NOOP(1);
//END_REGION

//REGION CHARACTER_EVENTS
IF
CharacterUsedSkillOnTarget(_Caster, (CHARACTERGUID)_Target, "Target_MySkillName", _)
THEN
IncrementBuff(_Target);

IF
CharacterStatusRemoved(_Character, _Status, _)
AND
DB_MyMod_BuffLevels(_Character, _BuffLevel)
AND
DB_MyMod_Buffs(_BuffLevel, _Status, _Turns, _Force)
AND
NOT QRY_BuffActive(_Character)
THEN
//Clear character from database since all the buffs are gone.
NOT DB_MyMod_BuffLevels(_Character, _BuffLevel);

//END_REGION

//REGION BUFF_APPLYING
PROC
IncrementBuff((CHARACTERGUID)_Target)
AND
NOT DB_MyMod_BuffLevels(_Target, _)
THEN
DB_MyMod_BuffLevels(_Target, 1);
ApplyBuffStatus(_Target, 1);

PROC
IncrementBuff((CHARACTERGUID)_Target)
AND
DB_MyMod_BuffLevels(_Target, _BuffLevel)
AND
NOT QRY_MaxBuffLevelReached(_BuffLevel)
AND
IntegerSum(_BuffLevel, 1, _NextBuffLevel)
THEN
NOT DB_MyMod_BuffLevels(_Target, _BuffLevel); // Remove previous entry
DB_MyMod_BuffLevels(_Target, _NextBuffLevel);
ApplyBuffStatus(_Target, _NextBuffLevel);

PROC
ApplyBuffStatus((CHARACTERGUID)_Target, (INTEGER)_BuffLevel)
AND
DB_MyMod_Buffs(_BuffLevel, _Status, _Turns, _Force)
THEN
ApplyStatus(_Target, _Status, _Turns, _Force);
//END_REGION

This will probably look pretty complicated as you're just learning how it all works, what the syntax means, and so on, but essentially what I did here was:

Quote
º Create a database that contains all the status information we need: the buff level of the status, the actual status name, the turn duration, and whether or not to force it. We do this so we can reduce the actual code to apply the status to one rule. Makes it way easier to extend, if we decide we want more buffs.

º Create a database to store the target character's current buff level. We use this to cross-reference into our buffs database. Where the previous buffs database is more of our buff "settings", this database is a basically a way for us to temporarily store a variable for a target character, until their buffs are gone.

º Create rules for when that specific skill is cast on a target, and when all of the buff statuses are removed.

º Create some queries/procs to make things easier in the long run.


Now this could be extended, depending on what you want. If you want the buff level to go in reverse (if, say, buff 4 runs out, you want the level to go back a step to level 3), then that would be possible with another rule like this:

Code
IF
CharacterStatusRemoved(_Character, _Status, _)
AND
DB_MyMod_Buffs(_BuffLevel, _Status, _Turns, _Force)
AND
DB_MyMod_BuffLevels(_Character, _BuffLevel)
AND
QRY_BuffActive(_Character)
AND
IntegerSubtract(_BuffLevel, 1, _NextBuffLevel)
THEN
NOT DB_MyMod_BuffLevels(_Character, _BuffLevel);
DB_MyMod_BuffLevels(_Character, _NextBuffLevel);
// No triggering the status applying, since we just want it to apply from the skill being cast.


Looking at it now, this is probably way more information than you wanted, haha. opa

To get a basic idea working, the main methods you'll need are:

Quote
event CharacterUsedSkillOnTarget((CHARACTERGUID)_Character, (GUIDSTRING)_Target, (STRING)_Skill, (STRING)_SkillType)
event CharacterStatusApplied((CHARACTERGUID)_Character, (STRING)_Status, (GUIDSTRING)_Causee)
event CharacterStatusRemoved((CHARACTERGUID)_Character, (STRING)_Status, (GUIDSTRING)_Causee)

query HasActiveStatus([in](GUIDSTRING)_Target, [in](STRING)_Status, [out](INTEGER)_Bool)
call ApplyStatus((GUIDSTRING)_Object, (STRING)_Status, (REAL)_Duration, (INTEGER)_Force, (GUIDSTRING)_Source)