Procházet zdrojové kódy

Wave mode instances - walkthrough conversions (#3884)

* Wave mode instances - walkthrough conversions

* NPC_EMOTION and NPC_EMOTION_ON disrupted the walking system and have been restricted on the maps.
* Implemented AI_SPECIALs. AI and normal monsters can naturally fight each others. However monsters with AI_SPECIAL can't be hit by normal monsters.

* Implemented mob_setidleevent command.
`mob_setidleevent <GID>,<event>;`
This command will attach an event label to the monster with the given <GID> which will execute when the <GID> is idle.

* Added parameters to unitskilluseid and unitskillusepos
-- `<cancel>`: define if the skill can be interrupted when hit (by default the cancel value was 'castcancel' from skill_db.txt)
-- `<Line_ID>` : the monster will say the message from 'Line_ID' in mob_chat_db.yml when casting the skill

* Added `UMOB_IGNORE_CELL_STACK_LIMIT` for setunitdata/getunitdata script command.
When true, the monster will ignore the stack limit (max number of characters that can stack within a single cell) defined by 'official_cell_stack_limit' in misc.conf

* The script is disabled by default like on KRO

Thanks to @Lemongrass3110 @aleos89 @Badarosk0 @sigtus @Questune09 !
Atemo před 3 roky
rodič
revize
3abc86e02d

+ 3 - 1
db/mob_chat_db.yml

@@ -107,11 +107,13 @@ Body:
   - Id: 37
     Dialog: Is there anyone waiting for you outside of here?  Throw them all away, you are mine now...
   - Id: 38
-    Dialog: Discard your life and stay confined here.  You will yearn for freedom in captivity !!
+    Dialog: Discard your life and stay confined here. You will yearn for freedom in captivity !!
   - Id: 39
     Dialog: How much will the outside world change if you stay here in solitude for one thousand years?
   - Id: 40
     Dialog: Yes! Yearn for your freedom from this confined place, your captivity here will be permanent !!
+  - Id: 41
+    Dialog: Arrival!
 
 Footer:
   Imports:

+ 12 - 12
db/re/instance_db.yml

@@ -198,18 +198,18 @@ Body:
       Map: 1@glast
       X: 367
       Y: 304
-#  - Id: 22
-#    Name: Wave Mode - Forest
-#    Enter:
-#      Map: 1@def01
-#      X: 50
-#      Y: 21
-#  - Id: 23
-#    Name: Wave Mode - Sky
-#    Enter:
-#      Map: 1@def02
-#      X: 29
-#      Y: 35
+  - Id: 22
+    Name: Wave Mode - Forest
+    Enter:
+      Map: 1@def01
+      X: 50
+      Y: 21
+  - Id: 23
+    Name: Wave Mode - Sky
+    Enter:
+      Map: 1@def02
+      X: 29
+      Y: 35
   - Id: 24
     Name: Nightmarish Jitterbug
     Enter:

+ 43 - 42
db/re/item_noequip.txt

@@ -19,6 +19,7 @@
 // 1024 - restricted in zone 6
 // 2048 - restricted in zone 7
 // 4096 - restricted in zone 8
+// 8192 - restricted in zone 9
 //
 // Passing negative value as flag will unset the flag instead.
 //
@@ -240,45 +241,45 @@
 //----------------------------------------------------------------------------
 // WoE:TE Items - Only can be used in WoE:TE Castles (All except &16)
 //----------------------------------------------------------------------------
-1299,8175	// TE_Woe_Katar
-1319,8175	// TE_Woe_Axe
-1399,8175	// TE_Woe_Two_Handed_Axe
-1437,8175	// TE_Woe_Pike
-1495,8175	// TE_Woe_Lance
-1591,8175	// TE_Woe_Book
-1667,8175	// TE_Woe_Staff
-1834,8175	// TE_Woe_Fist
-1932,8175	// TE_Woe_Guitar
-1987,8175	// TE_Woe_Rope
-2019,8175	// TE_Woe_Two_Hand_Staff
-2178,8175	// TE_Woe_Buckler
-2179,8175	// TE_Woe_Shield
-2180,8175	// TE_Woe_Magic_Guard
-2496,8175	// TE_Woe_Shoes
-2497,8175	// TE_Woe_Boots
-2498,8175	// TE_Woe_Magic_Sandal
-2944,8175	// TE_Ring_Of_Protection
-2945,8175	// TE_Ring_Of_Rage
-2946,8175	// TE_Ring_Of_Defiance
-11557,8175	// TE_White_Potion
-11558,8175	// TE_White_Slim_Potion
-13083,8175	// TE_Woe_Knife
-13117,8175	// TE_Woe_Pistol
-13184,8175	// TE_Woe_Rifle
-13185,8175	// TE_Woe_Gatling
-13186,8175	// TE_Woe_Shotgun
-13187,8175	// TE_Woe_Grenade
-13317,8175	// TE_Woe_Huuma
-13439,8175	// TE_Woe_Sword
-15062,8175	// TE_Woe_Coat
-15063,8175	// TE_Woe_Chain_Mail
-15064,8175	// TE_Woe_Mage_Coat
-16025,8175	// TE_Woe_Mace
-18118,8175	// TE_Woe_Bow
-18732,8175	// TE_Woe_Cap
-18733,8175	// TE_Woe_Bone_Helm
-18734,8175	// TE_Woe_Magic_Eyes
-20702,8175	// TE_Woe_Muffler
-20703,8175	// TE_Woe_Manteau
-20704,8175	// TE_Woe_Magic_Manteau
-21006,8175	// TE_Woe_Two_Hand_Sword
+1299,16367	// TE_Woe_Katar
+1319,16367	// TE_Woe_Axe
+1399,16367	// TE_Woe_Two_Handed_Axe
+1437,16367	// TE_Woe_Pike
+1495,16367	// TE_Woe_Lance
+1591,16367	// TE_Woe_Book
+1667,16367	// TE_Woe_Staff
+1834,16367	// TE_Woe_Fist
+1932,16367	// TE_Woe_Guitar
+1987,16367	// TE_Woe_Rope
+2019,16367	// TE_Woe_Two_Hand_Staff
+2178,16367	// TE_Woe_Buckler
+2179,16367	// TE_Woe_Shield
+2180,16367	// TE_Woe_Magic_Guard
+2496,16367	// TE_Woe_Shoes
+2497,16367	// TE_Woe_Boots
+2498,16367	// TE_Woe_Magic_Sandal
+2944,16367	// TE_Ring_Of_Protection
+2945,16367	// TE_Ring_Of_Rage
+2946,16367	// TE_Ring_Of_Defiance
+11557,16367	// TE_White_Potion
+11558,16367	// TE_White_Slim_Potion
+13083,16367	// TE_Woe_Knife
+13117,16367	// TE_Woe_Pistol
+13184,16367	// TE_Woe_Rifle
+13185,16367	// TE_Woe_Gatling
+13186,16367	// TE_Woe_Shotgun
+13187,16367	// TE_Woe_Grenade
+13317,16367	// TE_Woe_Huuma
+13439,16367	// TE_Woe_Sword
+15062,16367	// TE_Woe_Coat
+15063,16367	// TE_Woe_Chain_Mail
+15064,16367	// TE_Woe_Mage_Coat
+16025,16367	// TE_Woe_Mace
+18118,16367	// TE_Woe_Bow
+18732,16367	// TE_Woe_Cap
+18733,16367	// TE_Woe_Bone_Helm
+18734,16367	// TE_Woe_Magic_Eyes
+20702,16367	// TE_Woe_Muffler
+20703,16367	// TE_Woe_Manteau
+20704,16367	// TE_Woe_Magic_Manteau
+21006,16367	// TE_Woe_Two_Hand_Sword

+ 1154 - 114
db/re/mob_db.yml

@@ -58564,74 +58564,911 @@ Body:
     Ai: 10
     Modes:
       CanMove: true
-#  - Id: 2569
-#    AegisName: G_ANOPHELES
-#  - Id: 2570
-#    AegisName: G_BREEZE
-#  - Id: 2571
-#    AegisName: G_BUTOIJO
-#  - Id: 2572
-#    AegisName: G_CARAMEL
-#  - Id: 2573
-#    AegisName: G_CHONCHON
-#  - Id: 2574
-#    AegisName: G_CIVIL_SERVANT
-#  - Id: 2575
-#    AegisName: G_COCO
-#  - Id: 2576
-#    AegisName: G_CREAMY
-#  - Id: 2577
-#    AegisName: G_FABRE
-#  - Id: 2578
-#    AegisName: G_HORN
-#  - Id: 2579
-#    AegisName: G_HYLOZOIST
-#  - Id: 2580
-#    AegisName: G_KAHO
-#  - Id: 2581
-#    AegisName: G_LUDE
-#  - Id: 2582
-#    AegisName: G_LUNATIC
-#  - Id: 2583
-#    AegisName: G_MARTIN
-#  - Id: 2584
-#    AegisName: G_MINERAL
-#  - Id: 2585
-#    AegisName: G_MOLE
-#  - Id: 2586
-#    AegisName: G_NERAID
-#  - Id: 2587
-#    AegisName: G_OBSIDIAN
-#  - Id: 2588
-#    AegisName: G_PITMAN
-#  - Id: 2589
-#    AegisName: G_POPORING
-#  - Id: 2590
-#    AegisName: G_ROCKER
-#  - Id: 2591
-#    AegisName: G_SAVAGE
-#  - Id: 2592
-#    AegisName: G_SIORAVA
-#  - Id: 2593
-#    AegisName: G_SIROMA
-#  - Id: 2594
-#    AegisName: G_SNOWIER
-#  - Id: 2595
-#    AegisName: G_STAINER
-#  - Id: 2596
-#    AegisName: G_STAPO
-#  - Id: 2597
-#    AegisName: G_STEEL_CHONCHON
-#  - Id: 2598
-#    AegisName: G_UNGOLIANT
-#  - Id: 2599
-#    AegisName: G_WILD_RIDER
-#  - Id: 2600
-#    AegisName: G_WOLF
-#  - Id: 2601
-#    AegisName: G_YOYO
-#  - Id: 2602
-#    AegisName: G_ZIPPER_BEAR
+  - Id: 2569
+    AegisName: G_ANOPHELES
+    Name: Anopheles
+    Level: 95
+    Hp: 7238
+    Attack: 315
+    Attack2: 18
+    Defense: 7
+    MagicDefense: 10
+    Str: 64
+    Agi: 60
+    Vit: 42
+    Int: 58
+    Dex: 106
+    Luk: 42
+    AttackRange: 1
+    SkillRange: 10
+    ChaseRange: 12
+    Size: Small
+    Race: Insect
+    Element: Wind
+    ElementLevel: 3
+    WalkSpeed: 170
+    AttackDelay: 1084
+    AttackMotion: 2304
+    DamageMotion: 576
+    Ai: 02
+  - Id: 2570
+    AegisName: G_BREEZE
+    Name: Breeze
+    Level: 92
+    Hp: 6755
+    Attack: 493
+    Attack2: 52
+    Defense: 83
+    MagicDefense: 32
+    Str: 75
+    Agi: 101
+    Vit: 46
+    Int: 35
+    Dex: 79
+    Luk: 55
+    AttackRange: 2
+    SkillRange: 10
+    ChaseRange: 12
+    Size: Medium
+    Race: Formless
+    Element: Wind
+    ElementLevel: 3
+    WalkSpeed: 100
+    AttackDelay: 140
+    AttackMotion: 384
+    DamageMotion: 504
+    Ai: 02
+  - Id: 2571
+    AegisName: G_BUTOIJO
+    Name: Butoijo
+    Level: 88
+    Hp: 7524
+    Attack: 358
+    Attack2: 102
+    Defense: 77
+    MagicDefense: 12
+    Str: 66
+    Agi: 65
+    Vit: 30
+    Int: 30
+    Dex: 106
+    Luk: 44
+    AttackRange: 1
+    SkillRange: 10
+    ChaseRange: 12
+    Size: Large
+    Race: Demon
+    Element: Fire
+    ElementLevel: 2
+    WalkSpeed: 170
+    AttackDelay: 576
+    AttackMotion: 768
+    DamageMotion: 432
+    Ai: 02
+  - Id: 2572
+    AegisName: G_CARAMEL
+    Name: Caramel
+    Level: 25
+    Hp: 518
+    Attack: 67
+    Attack2: 9
+    Defense: 39
+    Str: 19
+    Agi: 10
+    Vit: 15
+    Int: 10
+    Dex: 32
+    Luk: 5
+    AttackRange: 1
+    SkillRange: 10
+    ChaseRange: 12
+    Size: Small
+    Race: Brute
+    Element: Earth
+    ElementLevel: 1
+    WalkSpeed: 200
+    AttackDelay: 1604
+    AttackMotion: 840
+    DamageMotion: 756
+    Ai: 02
+  - Id: 2573
+    AegisName: G_CHONCHON
+    Name: Chonchon
+    Level: 5
+    Hp: 57
+    Attack: 11
+    Attack2: 3
+    Defense: 27
+    Str: 13
+    Agi: 4
+    Vit: 4
+    Dex: 8
+    Luk: 5
+    AttackRange: 1
+    SkillRange: 10
+    ChaseRange: 12
+    Size: Small
+    Race: Insect
+    Element: Wind
+    ElementLevel: 1
+    WalkSpeed: 200
+    AttackDelay: 1076
+    AttackMotion: 576
+    DamageMotion: 480
+    Ai: 02
+  - Id: 2574
+    AegisName: G_CIVIL_SERVANT
+    Name: Civil Servant
+    Level: 89
+    Hp: 5292
+    Attack: 304
+    Attack2: 61
+    Defense: 90
+    MagicDefense: 56
+    Str: 67
+    Agi: 76
+    Vit: 40
+    Int: 65
+    Dex: 74
+    Luk: 30
+    AttackRange: 2
+    SkillRange: 10
+    ChaseRange: 12
+    Size: Medium
+    Race: Brute
+    Element: Wind
+    ElementLevel: 2
+    WalkSpeed: 200
+    AttackDelay: 1257
+    AttackMotion: 528
+    DamageMotion: 432
+    Ai: 02
+  - Id: 2575
+    AegisName: G_COCO
+    Name: Coco
+    Level: 38
+    Hp: 836
+    Attack: 71
+    Attack2: 11
+    Defense: 37
+    Str: 22
+    Agi: 13
+    Vit: 30
+    Int: 20
+    Dex: 38
+    Luk: 10
+    AttackRange: 1
+    SkillRange: 10
+    ChaseRange: 12
+    Size: Small
+    Race: Brute
+    Element: Earth
+    ElementLevel: 1
+    WalkSpeed: 150
+    AttackDelay: 1864
+    AttackMotion: 864
+    DamageMotion: 1008
+    Ai: 02
+  - Id: 2576
+    AegisName: G_CREAMY
+    Name: Creamy
+    Level: 23
+    Hp: 378
+    Attack: 61
+    Attack2: 1
+    Defense: 28
+    MagicDefense: 20
+    Str: 16
+    Luk: 20
+    AttackRange: 1
+    SkillRange: 10
+    ChaseRange: 12
+    Size: Small
+    Race: Insect
+    Element: Wind
+    ElementLevel: 1
+    WalkSpeed: 150
+    AttackDelay: 1136
+    AttackMotion: 720
+    DamageMotion: 840
+    Ai: 02
+  - Id: 2577
+    AegisName: G_FABRE
+    Name: Fabre
+    Level: 6
+    Hp: 72
+    Attack: 12
+    Attack2: 3
+    Defense: 24
+    Str: 12
+    Agi: 5
+    Vit: 5
+    Int: 5
+    Dex: 12
+    Luk: 5
+    AttackRange: 1
+    SkillRange: 10
+    ChaseRange: 12
+    Size: Small
+    Race: Insect
+    Element: Earth
+    ElementLevel: 1
+    WalkSpeed: 400
+    AttackDelay: 1672
+    AttackMotion: 672
+    DamageMotion: 480
+    Ai: 02
+  - Id: 2578
+    AegisName: G_HORN
+    Name: Horn
+    Level: 32
+    Hp: 705
+    Attack: 64
+    Attack2: 11
+    Defense: 52
+    MagicDefense: 8
+    Str: 10
+    Agi: 12
+    Vit: 36
+    Int: 25
+    Dex: 21
+    Luk: 35
+    AttackRange: 1
+    SkillRange: 10
+    ChaseRange: 12
+    Size: Medium
+    Race: Insect
+    Element: Earth
+    ElementLevel: 1
+    WalkSpeed: 200
+    AttackDelay: 1528
+    AttackMotion: 528
+    DamageMotion: 288
+    Ai: 02
+  - Id: 2579
+    AegisName: G_HYLOZOIST
+    Name: Hylozoist
+    Level: 102
+    Hp: 12000
+    Attack: 548
+    Attack2: 81
+    Defense: 101
+    MagicDefense: 68
+    Str: 97
+    Agi: 67
+    Vit: 72
+    Int: 88
+    Dex: 83
+    Luk: 60
+    AttackRange: 1
+    SkillRange: 10
+    ChaseRange: 12
+    Size: Small
+    Race: Demon
+    Element: Dark
+    ElementLevel: 2
+    WalkSpeed: 155
+    AttackDelay: 741
+    AttackMotion: 1536
+    DamageMotion: 480
+    Ai: 02
+  - Id: 2580
+    AegisName: G_KAHO
+    Name: Kaho
+    Level: 98
+    Hp: 7045
+    Attack: 655
+    Attack2: 224
+    Defense: 106
+    MagicDefense: 55
+    Str: 81
+    Agi: 61
+    Vit: 55
+    Int: 65
+    Dex: 79
+    Luk: 73
+    AttackRange: 1
+    SkillRange: 10
+    ChaseRange: 12
+    Size: Medium
+    Race: Demon
+    Element: Fire
+    ElementLevel: 4
+    WalkSpeed: 150
+    AttackDelay: 1700
+    AttackMotion: 1000
+    DamageMotion: 500
+    Ai: 02
+  - Id: 2581
+    AegisName: G_LUDE
+    Name: Lude
+    Level: 101
+    Hp: 11574
+    Attack: 283
+    Attack2: 78
+    Defense: 90
+    MagicDefense: 53
+    Str: 97
+    Agi: 38
+    Vit: 55
+    Int: 82
+    Dex: 83
+    Luk: 55
+    AttackRange: 2
+    SkillRange: 10
+    ChaseRange: 12
+    Size: Small
+    Race: Undead
+    Element: Undead
+    ElementLevel: 1
+    WalkSpeed: 150
+    AttackDelay: 890
+    AttackMotion: 960
+    DamageMotion: 480
+    Ai: 02
+  - Id: 2582
+    AegisName: G_LUNATIC
+    Name: Lunatic
+    Level: 3
+    Hp: 55
+    Attack: 11
+    Attack2: 1
+    Defense: 18
+    Str: 10
+    Agi: 3
+    Vit: 3
+    Dex: 8
+    Luk: 5
+    AttackRange: 1
+    SkillRange: 10
+    ChaseRange: 12
+    Size: Small
+    Race: Brute
+    Element: Neutral
+    ElementLevel: 3
+    WalkSpeed: 200
+    AttackDelay: 1456
+    AttackMotion: 456
+    DamageMotion: 336
+    Ai: 02
+  - Id: 2583
+    AegisName: G_MARTIN
+    Name: Martin
+    Level: 39
+    Hp: 1056
+    Attack: 70
+    Attack2: 18
+    Defense: 58
+    MagicDefense: 19
+    Str: 25
+    Agi: 29
+    Vit: 28
+    Int: 15
+    Dex: 30
+    Luk: 10
+    AttackRange: 1
+    SkillRange: 10
+    ChaseRange: 12
+    Size: Small
+    Race: Brute
+    Element: Earth
+    ElementLevel: 2
+    WalkSpeed: 300
+    AttackDelay: 1480
+    AttackMotion: 480
+    DamageMotion: 480
+    Ai: 02
+  - Id: 2584
+    AegisName: G_MINERAL
+    Name: Mineral
+    Level: 96
+    Hp: 8300
+    Attack: 751
+    Attack2: 57
+    Defense: 127
+    MagicDefense: 23
+    Str: 70
+    Agi: 61
+    Vit: 40
+    Int: 50
+    Dex: 74
+    Luk: 50
+    AttackRange: 1
+    SkillRange: 10
+    ChaseRange: 12
+    Size: Small
+    Race: Formless
+    Element: Neutral
+    ElementLevel: 2
+    WalkSpeed: 250
+    AttackDelay: 648
+    AttackMotion: 480
+    DamageMotion: 360
+    Ai: 02
+  - Id: 2585
+    AegisName: G_MOLE
+    Name: Mole
+    Level: 85
+    Hp: 6228
+    Attack: 286
+    Attack2: 49
+    Defense: 82
+    MagicDefense: 16
+    Str: 53
+    Agi: 65
+    Vit: 31
+    Int: 30
+    Dex: 58
+    Luk: 31
+    AttackRange: 9
+    SkillRange: 10
+    ChaseRange: 12
+    Size: Small
+    Race: Brute
+    Element: Earth
+    ElementLevel: 2
+    WalkSpeed: 300
+    AttackDelay: 1400
+    AttackMotion: 960
+    DamageMotion: 504
+    Ai: 02
+  - Id: 2586
+    AegisName: G_NERAID
+    Name: Neraid
+    Level: 98
+    Hp: 9550
+    Attack: 255
+    Attack2: 71
+    Defense: 100
+    MagicDefense: 37
+    Str: 97
+    Agi: 45
+    Vit: 60
+    Int: 30
+    Dex: 83
+    Luk: 50
+    AttackRange: 1
+    SkillRange: 10
+    ChaseRange: 12
+    Size: Small
+    Race: Brute
+    Element: Earth
+    ElementLevel: 1
+    WalkSpeed: 200
+    AttackDelay: 776
+    AttackMotion: 576
+    DamageMotion: 288
+    Ai: 02
+  - Id: 2587
+    AegisName: G_OBSIDIAN
+    Name: Obsidian
+    Level: 97
+    Hp: 10088
+    Attack: 767
+    Attack2: 80
+    Defense: 129
+    MagicDefense: 37
+    Str: 84
+    Agi: 38
+    Vit: 40
+    Int: 60
+    Dex: 64
+    Luk: 50
+    AttackRange: 1
+    SkillRange: 10
+    ChaseRange: 12
+    Size: Small
+    Race: Formless
+    Element: Earth
+    ElementLevel: 2
+    WalkSpeed: 350
+    AttackDelay: 720
+    AttackMotion: 864
+    DamageMotion: 504
+    Ai: 02
+  - Id: 2588
+    AegisName: G_PITMAN
+    Name: Pitman
+    Level: 90
+    Hp: 7208
+    Attack: 200
+    Attack2: 60
+    Defense: 104
+    MagicDefense: 48
+    Str: 78
+    Agi: 56
+    Vit: 45
+    Int: 35
+    Dex: 60
+    Luk: 30
+    AttackRange: 1
+    SkillRange: 10
+    ChaseRange: 12
+    Size: Large
+    Race: Undead
+    Element: Earth
+    ElementLevel: 2
+    WalkSpeed: 180
+    AttackDelay: 960
+    AttackMotion: 336
+    DamageMotion: 300
+    Ai: 02
+  - Id: 2589
+    AegisName: G_POPORING
+    Name: Poporing
+    Level: 30
+    Hp: 524
+    Attack: 74
+    Attack2: 20
+    Defense: 36
+    MagicDefense: 17
+    Str: 17
+    Agi: 26
+    Vit: 20
+    Int: 18
+    Dex: 36
+    Luk: 5
+    AttackRange: 1
+    SkillRange: 10
+    ChaseRange: 12
+    Size: Medium
+    Race: Plant
+    Element: Poison
+    ElementLevel: 1
+    WalkSpeed: 300
+    AttackDelay: 1672
+    AttackMotion: 672
+    DamageMotion: 480
+    Ai: 02
+  - Id: 2590
+    AegisName: G_ROCKER
+    Name: Rocker
+    Level: 15
+    Hp: 185
+    Attack: 19
+    Attack2: 5
+    Defense: 16
+    MagicDefense: 3
+    Str: 12
+    Agi: 18
+    Vit: 8
+    Int: 10
+    Dex: 17
+    Luk: 5
+    AttackRange: 1
+    SkillRange: 10
+    ChaseRange: 12
+    Size: Medium
+    Race: Insect
+    Element: Earth
+    ElementLevel: 1
+    WalkSpeed: 200
+    AttackDelay: 1864
+    AttackMotion: 864
+    DamageMotion: 540
+    Ai: 02
+  - Id: 2591
+    AegisName: G_SAVAGE
+    Name: Savage
+    Level: 59
+    Hp: 2301
+    Attack: 181
+    Attack2: 23
+    Defense: 126
+    MagicDefense: 3
+    Str: 56
+    Agi: 21
+    Vit: 54
+    Int: 10
+    Dex: 52
+    Luk: 15
+    AttackRange: 1
+    SkillRange: 10
+    ChaseRange: 12
+    Size: Large
+    Race: Brute
+    Element: Earth
+    ElementLevel: 2
+    WalkSpeed: 150
+    AttackDelay: 1960
+    AttackMotion: 960
+    DamageMotion: 384
+    Ai: 02
+  - Id: 2592
+    AegisName: G_SIORAVA
+    Name: Siorava
+    Level: 87
+    Hp: 6500
+    Attack: 450
+    Attack2: 210
+    Defense: 20
+    MagicDefense: 40
+    Str: 10
+    Agi: 40
+    Vit: 66
+    Int: 70
+    Dex: 67
+    Luk: 10
+    AttackRange: 1
+    SkillRange: 10
+    ChaseRange: 12
+    Size: Small
+    Race: Formless
+    Element: Water
+    ElementLevel: 1
+    WalkSpeed: 250
+    AttackDelay: 1536
+    AttackMotion: 1296
+    DamageMotion: 576
+    Ai: 02
+  - Id: 2593
+    AegisName: G_SIROMA
+    Name: Siroma
+    Level: 98
+    Hp: 11910
+    Attack: 506
+    Attack2: 100
+    Defense: 64
+    MagicDefense: 38
+    Str: 83
+    Agi: 43
+    Vit: 50
+    Int: 70
+    Dex: 96
+    Luk: 60
+    AttackRange: 1
+    SkillRange: 10
+    ChaseRange: 12
+    Size: Small
+    Race: Formless
+    Element: Water
+    ElementLevel: 3
+    WalkSpeed: 180
+    AttackDelay: 432
+    AttackMotion: 648
+    DamageMotion: 240
+    Ai: 02
+  - Id: 2594
+    AegisName: G_SNOWIER
+    Name: Snowier
+    Level: 103
+    Hp: 13934
+    Attack: 763
+    Attack2: 82
+    Defense: 121
+    MagicDefense: 47
+    Str: 91
+    Agi: 61
+    Vit: 67
+    Int: 45
+    Dex: 83
+    Luk: 55
+    AttackRange: 2
+    SkillRange: 10
+    ChaseRange: 12
+    Size: Large
+    Race: Formless
+    Element: Water
+    ElementLevel: 2
+    WalkSpeed: 220
+    AttackDelay: 936
+    AttackMotion: 1020
+    DamageMotion: 420
+    Ai: 02
+  - Id: 2595
+    AegisName: G_STAINER
+    Name: Stainer
+    Level: 21
+    Hp: 365
+    Attack: 65
+    Attack2: 9
+    Defense: 22
+    MagicDefense: 25
+    Str: 10
+    Agi: 10
+    Vit: 24
+    Dex: 39
+    Luk: 15
+    AttackRange: 1
+    SkillRange: 10
+    ChaseRange: 12
+    Size: Small
+    Race: Insect
+    Element: Wind
+    ElementLevel: 1
+    WalkSpeed: 200
+    AttackDelay: 1688
+    AttackMotion: 1188
+    DamageMotion: 612
+    Ai: 02
+  - Id: 2596
+    AegisName: G_STAPO
+    Name: Stapo
+    Level: 95
+    Hp: 8805
+    Attack: 573
+    Attack2: 51
+    Defense: 129
+    MagicDefense: 36
+    Str: 20
+    Agi: 46
+    Vit: 25
+    Int: 35
+    Dex: 64
+    Luk: 30
+    AttackRange: 1
+    SkillRange: 10
+    ChaseRange: 12
+    Size: Small
+    Race: Formless
+    Element: Earth
+    ElementLevel: 2
+    WalkSpeed: 300
+    AttackDelay: 936
+    AttackMotion: 792
+    DamageMotion: 432
+    Ai: 02
+  - Id: 2597
+    AegisName: G_STEEL_CHONCHON
+    Name: Steel Chonchon
+    Level: 48
+    Hp: 1199
+    Attack: 77
+    Attack2: 35
+    Defense: 57
+    MagicDefense: 20
+    Str: 30
+    Agi: 62
+    Vit: 20
+    Int: 10
+    Dex: 56
+    Luk: 10
+    AttackRange: 1
+    SkillRange: 10
+    ChaseRange: 12
+    Size: Small
+    Race: Insect
+    Element: Wind
+    ElementLevel: 1
+    WalkSpeed: 150
+    AttackDelay: 1076
+    AttackMotion: 576
+    DamageMotion: 480
+    Ai: 02
+  - Id: 2598
+    AegisName: G_UNGOLIANT
+    Name: Ungoliant
+    Level: 94
+    Hp: 27070
+    Attack: 1296
+    Attack2: 144
+    Defense: 108
+    MagicDefense: 28
+    Str: 71
+    Agi: 70
+    Vit: 58
+    Int: 43
+    Dex: 110
+    Luk: 38
+    AttackRange: 1
+    SkillRange: 10
+    ChaseRange: 12
+    Size: Large
+    Race: Insect
+    Element: Poison
+    ElementLevel: 2
+    WalkSpeed: 350
+    AttackDelay: 420
+    AttackMotion: 576
+    DamageMotion: 420
+    Ai: 02
+  - Id: 2599
+    AegisName: G_WILD_RIDER
+    Name: Wild Rider
+    Level: 95
+    Hp: 33300
+    Attack: 1320
+    Attack2: 330
+    Defense: 480
+    MagicDefense: 22
+    Str: 89
+    Agi: 124
+    Vit: 89
+    Int: 56
+    Dex: 112
+    Luk: 56
+    AttackRange: 1
+    SkillRange: 10
+    ChaseRange: 12
+    Size: Large
+    Race: Fish
+    Element: Water
+    ElementLevel: 2
+    WalkSpeed: 120
+    AttackDelay: 432
+    AttackMotion: 792
+    DamageMotion: 360
+    Ai: 02
+  - Id: 2600
+    AegisName: G_WOLF
+    Name: Wolf
+    Level: 45
+    Hp: 1219
+    Attack: 80
+    Attack2: 11
+    Defense: 55
+    MagicDefense: 3
+    Str: 27
+    Agi: 24
+    Vit: 30
+    Int: 15
+    Dex: 33
+    Luk: 5
+    AttackRange: 1
+    SkillRange: 10
+    ChaseRange: 12
+    Size: Medium
+    Race: Brute
+    Element: Earth
+    ElementLevel: 1
+    WalkSpeed: 200
+    AttackDelay: 1054
+    AttackMotion: 504
+    DamageMotion: 432
+    Ai: 02
+  - Id: 2601
+    AegisName: G_YOYO
+    Name: Yoyo
+    Level: 38
+    Hp: 898
+    Attack: 63
+    Attack2: 11
+    Defense: 40
+    Str: 20
+    Agi: 11
+    Vit: 34
+    Int: 20
+    Dex: 19
+    Luk: 10
+    AttackRange: 1
+    SkillRange: 10
+    ChaseRange: 12
+    Size: Small
+    Race: Brute
+    Element: Earth
+    ElementLevel: 1
+    WalkSpeed: 200
+    AttackDelay: 1054
+    AttackMotion: 54
+    DamageMotion: 384
+    Ai: 02
+  - Id: 2602
+    AegisName: G_ZIPPER_BEAR
+    Name: Zipper Bear
+    Level: 90
+    Hp: 6620
+    Attack: 451
+    Attack2: 57
+    Defense: 130
+    MagicDefense: 40
+    Str: 68
+    Agi: 51
+    Vit: 50
+    Int: 35
+    Dex: 70
+    Luk: 20
+    AttackRange: 1
+    SkillRange: 10
+    ChaseRange: 12
+    Size: Medium
+    Race: Brute
+    Element: Dark
+    ElementLevel: 1
+    WalkSpeed: 155
+    AttackDelay: 780
+    AttackMotion: 1008
+    DamageMotion: 420
+    Ai: 02
   - Id: 2603
     AegisName: C1_ZOMBIE_SLAUGHTER
     Name: Swift Zombie Slaughter
@@ -76895,52 +77732,255 @@ Body:
       - Item: Timeholder_Card
         Rate: 1
         StealProtected: true
-#  - Id: 3075
-#    AegisName: WA_TREASURE
-#  - Id: 3076
-#    AegisName: WA_MONSTER_1
-#  - Id: 3077
-#    AegisName: WA_MONSTER_2
-#  - Id: 3078
-#    AegisName: WA_MONSTER_3
-#  - Id: 3079
-#    AegisName: WA_MONSTER_4
-#  - Id: 3080
-#    AegisName: WA_MONSTER_5
-#  - Id: 3081
-#    AegisName: WA_MONSTER_6
-#  - Id: 3082
-#    AegisName: WA_MONSTER_7
-#  - Id: 3083
-#    AegisName: WA_MONSTER_8
-#  - Id: 3084
-#    AegisName: WA_MONSTER_9
-#  - Id: 3085
-#    AegisName: WA_MONSTER_10
-#  - Id: 3086
-#    AegisName: WA_MERCENARY
-#    Name: Wa Mercenary
-#    Level: 101
-#    Hp: 20099
-#    Attack: 545
-#    Attack2: 218
-#    Defense: 66
-#    MagicDefense: 36
-#    Str: 20
-#    Agi: 46
-#    Vit: 25
-#    Int: 35
-#    Dex: 64
-#    Luk: 30
-#    SkillRange: 10
-#    ChaseRange: 12
-#    Size: Medium
-#    Race: Demihuman
-#    Element: Neutral
-#    ElementLevel: 1
-#    WalkSpeed: 230
-#    AttackDelay: 1415
-#    AttackMotion: 792
+  - Id: 3075
+    AegisName: WA_TREASURE
+    Name: Treasure
+    Level: 1
+    Hp: 3
+    Attack: 1
+    Attack2: 1
+    Defense: 100
+    Dex: 1199
+    SkillRange: 10
+    ChaseRange: 12
+    Size: Small
+    Race: Formless
+    Element: Holy
+    ElementLevel: 1
+    Class: Battlefield
+    Modes:
+      NoRandomWalk: true
+      IgnoreMagic: true
+      IgnoreMelee: true
+      IgnoreMisc: true
+      IgnoreRanged: true
+      KnockBackImmune: true
+    Drops:
+      - Item: Vit_Dish06
+        Rate: 3000
+      - Item: Agi_Dish06
+        Rate: 3000
+      - Item: Int_Dish06
+        Rate: 3000
+      - Item: Dex_Dish06
+        Rate: 3000
+      - Item: Yggdrasilberry
+        Rate: 1000
+  - Id: 3076
+    AegisName: WA_MONSTER_1
+    Name: Go!
+    Level: 100
+    Hp: 10000
+    Defense: 64
+    MagicDefense: 50
+    SkillRange: 10
+    ChaseRange: 12
+    Size: Small
+    Race: Angel
+    Element: Holy
+    ElementLevel: 3
+    WalkSpeed: 300
+    AttackDelay: 1332
+    AttackMotion: 288
+    DamageMotion: 384
+    Ai: 25
+    Modes:
+      NoRandomWalk: true
+  - Id: 3077
+    AegisName: WA_MONSTER_2
+    Name: Go!
+    Level: 100
+    Hp: 10500
+    Defense: 64
+    MagicDefense: 50
+    SkillRange: 10
+    ChaseRange: 12
+    Size: Small
+    Race: Angel
+    Element: Holy
+    ElementLevel: 3
+    WalkSpeed: 300
+    AttackDelay: 1332
+    AttackMotion: 288
+    Ai: 25
+    Modes:
+      NoRandomWalk: true
+  - Id: 3078
+    AegisName: WA_MONSTER_3
+    Name: Go!
+    Level: 105
+    Hp: 11000
+    Defense: 106
+    MagicDefense: 84
+    SkillRange: 10
+    ChaseRange: 12
+    Size: Small
+    Race: Angel
+    Element: Holy
+    ElementLevel: 3
+    WalkSpeed: 160
+    AttackDelay: 1025
+    AttackMotion: 720
+    Ai: 25
+    Modes:
+      NoRandomWalk: true
+  - Id: 3079
+    AegisName: WA_MONSTER_4
+    Name: Go!
+    Level: 120
+    Hp: 12000
+    Defense: 66
+    MagicDefense: 95
+    SkillRange: 10
+    ChaseRange: 12
+    Size: Small
+    Race: Angel
+    Element: Holy
+    ElementLevel: 3
+    WalkSpeed: 160
+    AttackDelay: 1025
+    AttackMotion: 720
+    Ai: 25
+    Modes:
+      NoRandomWalk: true
+  - Id: 3080
+    AegisName: WA_MONSTER_5
+    Name: Go!
+    SkillRange: 10
+    ChaseRange: 12
+    Size: Small
+    Race: Formless
+    Element: Neutral
+    ElementLevel: 4
+    WalkSpeed: 160
+    AttackDelay: 1025
+    AttackMotion: 720
+    Ai: 25
+    Modes:
+      NoRandomWalk: true
+  - Id: 3081
+    AegisName: WA_MONSTER_6
+    Name: Go!
+    Level: 125
+    Hp: 14000
+    Defense: 80
+    MagicDefense: 89
+    SkillRange: 10
+    ChaseRange: 12
+    Size: Small
+    Race: Angel
+    Element: Holy
+    ElementLevel: 3
+    WalkSpeed: 160
+    AttackDelay: 1025
+    AttackMotion: 720
+    Ai: 25
+    Modes:
+      NoRandomWalk: true
+  - Id: 3082
+    AegisName: WA_MONSTER_7
+    Name: Go!
+    Level: 131
+    Hp: 15000
+    Defense: 85
+    MagicDefense: 92
+    SkillRange: 10
+    ChaseRange: 12
+    Size: Small
+    Race: Angel
+    Element: Holy
+    ElementLevel: 2
+    WalkSpeed: 160
+    AttackDelay: 1025
+    AttackMotion: 720
+    Ai: 25
+    Modes:
+      NoRandomWalk: true
+  - Id: 3083
+    AegisName: WA_MONSTER_8
+    Name: Go!
+    Level: 131
+    Hp: 18000
+    Defense: 80
+    MagicDefense: 86
+    SkillRange: 10
+    ChaseRange: 12
+    Size: Small
+    Race: Angel
+    Element: Holy
+    ElementLevel: 2
+    WalkSpeed: 160
+    AttackDelay: 1025
+    AttackMotion: 720
+    Ai: 25
+    Modes:
+      NoRandomWalk: true
+  - Id: 3084
+    AegisName: WA_MONSTER_9
+    Name: Go!
+    Level: 135
+    Hp: 20000
+    Defense: 196
+    MagicDefense: 96
+    SkillRange: 10
+    ChaseRange: 12
+    Size: Small
+    Race: Angel
+    Element: Holy
+    ElementLevel: 3
+    WalkSpeed: 160
+    AttackDelay: 1025
+    AttackMotion: 720
+    Ai: 25
+    Modes:
+      NoRandomWalk: true
+  - Id: 3085
+    AegisName: WA_MONSTER_10
+    Name: Go!
+    SkillRange: 10
+    ChaseRange: 12
+    Size: Small
+    Race: Formless
+    Element: Neutral
+    ElementLevel: 4
+    WalkSpeed: 160
+    AttackDelay: 1025
+    AttackMotion: 720
+    Ai: 25
+    Modes:
+      NoRandomWalk: true
+  - Id: 3086
+    AegisName: WA_MERCENARY
+    Name: Mercenary
+    Level: 101
+    Hp: 20099
+    Attack: 557
+    Attack2: 775
+    Defense: 66
+    MagicDefense: 36
+    Str: 20
+    Agi: 46
+    Vit: 25
+    Int: 35
+    Dex: 64
+    Luk: 30
+    SkillRange: 10
+    ChaseRange: 12
+    Size: Medium
+    Race: Demihuman
+    Element: Neutral
+    ElementLevel: 1
+    WalkSpeed: 230
+    AttackDelay: 1415
+    AttackMotion: 792
+    Ai: 24
+    Class: Battlefield
+    Modes:
+      Aggressive: true
+      IgnoreMagic: true
+      IgnoreMelee: true
+      IgnoreMisc: true
+      IgnoreRanged: true
 #  - Id: 3087
 #    AegisName: M_NYDHOG
 #    Name: M Nydhog

+ 15 - 0
db/re/skill_nocast_db.txt

@@ -19,6 +19,7 @@
 // 1024 - cannot be used in zone 6 maps
 // 2048 - cannot be used in zone 7 maps
 // 4096 - cannot be used in zone 8 maps
+// 8192 - cannot be used in zone 9 maps
 //
 // Example:
 // 8,6  // Endure cannot be used in PvP and GvG maps (2+4)
@@ -229,3 +230,17 @@
 409,4096 // WE_CALLPARENT
 410,4096 // WE_CALLBABY
 5063,4096	//WE_CALLALLFAMILY
+
+//----------------------------------------------------------------------------
+// Zone 9 - Wave Mode
+//----------------------------------------------------------------------------
+26,8192	//AL_TELEPORT
+87,8192	//WZ_ICEWALL
+197,8192	//NPC_EMOTION
+219,8192	//RG_INTIMIDATE
+405,8192	//PF_SPIDERWEB
+474,8192	//NPC_EMOTION_ON
+674,8192	//NPC_EXPULSION
+2284,8192	//SC_FATALMENACE
+2294,8192	//SC_IGNORANCE
+2300,8192	//SC_DIMENSIONDOOR

+ 46 - 20
doc/script_commands.txt

@@ -143,7 +143,7 @@ to move away from their specified spawn region.
 
 Monster name is the name the monsters will have on screen, and has no relation
 whatsoever to their names anywhere else. It's the mob id that counts, which
-identifies monster record in 'mob_db.txt' database of monsters. If the mob name
+identifies monster record in 'mob_db.yml' database of monsters. If the mob name
 is given as "--ja--", the 'japanese name' field from the monster database is
 used, (which, in rAthena, actually contains an English name) if it's "--en--",
 it's the 'english name' from the monster database (which contains an uppercase
@@ -168,6 +168,7 @@ player who triggers the script must be within 'trigger' range for the event to
 work.
 
 There are two optional fields for monster size and AI.
+Natural enemies for AI monsters are normal monsters.
 
 <mob size> can be:
 	Size_Small	(0)
@@ -182,6 +183,7 @@ There are two optional fields for monster size and AI.
 	AI_ZANZOU	(4)		(Kagerou/Oboro skill)
 	AI_LEGION	(5)		(Sera skill)
 	AI_FAW		(6)		(Mechanic skill)
+	AI_WAVEMODE	(7)		Normal monsters will ignore attack from AI_WAVEMODE monsters
 
 Alternately, a monster spawned using 'boss_monster' instead of 'monster' is able
 to be detected on the map with the SC_BOSSMAPINFO status (used by Convex Mirror).
@@ -246,7 +248,7 @@ it's facing 5.)
 Sprite ID is the sprite number or constant used to display this particular NPC.
 You may also use a monster's ID instead to display a monster sprite for this NPC.
 It is possible to use a job sprite as well, but you must first define it as a
-monster sprite in 'mob_avail.txt', a full description on how to do this is not
+monster sprite in 'mob_avail.yml', a full description on how to do this is not
 in the scope of this manual.
 A '-1' Sprite ID will make the NPC invisible (and unclickable).
 A '111' Sprite ID will make an NPC which does not have a sprite, but is still
@@ -2954,7 +2956,7 @@ recreate these items perfectly if they are destroyed. Here's what you get:
 @inventorylist_option_id5[]        - fifth array of random option IDs
 @inventorylist_option_value5[]     - fifth array of random option values
 @inventorylist_option_parameter5[] - fifth array of random option parameters
-@inventorylist_tradable            - Returns if an item is tradable or not (Pass item_trade.txt, bound, and rental restrictions).
+@inventorylist_tradable            - Returns if an item is tradable or not (Pass item_db.yml, bound, and rental restrictions).
 @inventorylist_favorite            - Returns if an item is favorite or not
 
 This could be handy to save/restore a character's inventory, since no other
@@ -3085,7 +3087,7 @@ Examples
 *mergeitem2({"<item name>"{,<char_id>}});
 
 Merge all stackable items that separated by GUID flags
-(either by flag 4 item_flag.txt or GUID  in item_group).
+(UniqueId in item_db or in item_group).
 If no item ID/name given, all possible items in player's inventory will be merged.
 
 ---------------------------------------
@@ -3435,7 +3437,7 @@ of his/her guild, or, if a guild ID is specified, of that guild.
 *getcastlename("<map name>")
 
 This function returns the name of the castle when given the map name for that
-castle. The data is read from 'db/castle_db.txt'.
+castle. The data is read from 'db/castle_db.yml'.
 
 ---------------------------------------
 
@@ -4781,7 +4783,7 @@ eggs, and may hatch from either, although, I'm not sure what kind of a mess will
 this really cause.
 
 'getitem3' is advance version of 'getitem2' that also use Item Random Option as additional values.
-<RandomIDArray>    : Array variable of ID for item random option, see db/[pre-]re/item_randomopt_db.txt
+<RandomIDArray>    : Array variable of ID for item random option, see db/[pre-]re/item_randomopt_db.yml
 <RandomValueArray> : Array variable of item random option's value.
 <RandomParamArray> : Array variable of item random option's param.
 
@@ -4823,7 +4825,7 @@ some cases cannot be traded or stored.
 For a list of bound types see 'getitembound'.
 
 'getitembound3' is advance version of 'getitembound2' that also use Item Random Option as additional values.
-<RandomIDArray>    : Array variable of ID for item random option, see db/[pre-]re/item_randomopt_db.txt
+<RandomIDArray>    : Array variable of ID for item random option, see db/[pre-]re/item_randomopt_db.yml
 <RandomValueArray> : Array variable of item random option's value.
 <RandomParamArray> : Array variable of item random option's param.
 
@@ -4889,7 +4891,7 @@ in <time> seconds and be automatically deleted. See 'rentitem' for further detai
 See 'getitem2' for an explanation of the expanded parameters.
 
 'rentitem3' is advance version of 'rentitem2' that also use Item Random Option as additional values.
-<RandomIDArray>    : Array variable of ID for item random option, see db/[pre-]re/item_randomopt_db.txt
+<RandomIDArray>    : Array variable of ID for item random option, see db/[pre-]re/item_randomopt_db.yml
 <RandomValueArray> : Array variable of item random option's value.
 <RandomParamArray> : Array variable of item random option's param.
 
@@ -4929,7 +4931,7 @@ further details.
 See 'getitem2' for an explanation of the expanded parameters.
 
 'makeitem3' is advance version of 'makeitem2' that also use Item Random Option as additional values.
-<RandomIDArray>    : Array variable of ID for item random option, see db/[pre-]re/item_randomopt_db.txt
+<RandomIDArray>    : Array variable of ID for item random option, see db/[pre-]re/item_randomopt_db.yml
 <RandomValueArray> : Array variable of item random option's value.
 <RandomParamArray> : Array variable of item random option's param.
 
@@ -5015,7 +5017,7 @@ This command will remove a specified amount of items from the invoking/target ch
 See 'getitem2' for an explanation of the expanded parameters.
 
 'delitem3' is advance version of 'delitem2' that also use Item Random Option as criteria.
-<RandomIDArray>    : Array variable of ID for item random option, see db/[pre-]re/item_randomopt_db.txt
+<RandomIDArray>    : Array variable of ID for item random option, see db/[pre-]re/item_randomopt_db.yml
 <RandomValueArray> : Array variable of item random option's value.
 <RandomParamArray> : Array variable of item random option's param.
 
@@ -5109,7 +5111,7 @@ other parameters that the invoking character has in the inventory.
 See 'getitem2' for an explanation of the expanded parameters.
 
 'countitem3' is advance version of 'countitem2' that also use Item Random Option as criteria.
-<RandomIDArray>    : Array variable of ID for item random option, see db/[pre-]re/item_randomopt_db.txt
+<RandomIDArray>    : Array variable of ID for item random option, see db/[pre-]re/item_randomopt_db.yml
 <RandomValueArray> : Array variable of item random option's value.
 <RandomParamArray> : Array variable of item random option's param.
 
@@ -5150,7 +5152,7 @@ other parameters that the invoking character has in the inventory.
 See 'getitem2' for an explanation of the expanded parameters.
 
 'rentalcountitem3' is advance version of 'rentalcountitem2' that also use Item Random Option as criteria.
-<RandomIDArray>    : Array variable of ID for item random option, see db/[pre-]re/item_randomopt_db.txt
+<RandomIDArray>    : Array variable of ID for item random option, see db/[pre-]re/item_randomopt_db.yml
 <RandomValueArray> : Array variable of item random option's value.
 <RandomParamArray> : Array variable of item random option's param.
 
@@ -5178,7 +5180,7 @@ Example:
 *groupranditem <group id>{,<sub_group>};
 
 Returns the item_id of a random item picked from the group specified. The
-different groups and their group number are specified in 'db/(pre-)re/item_group_db.txt'.
+different groups and their group number are specified in 'db/(pre-)re/item_group_db.yml'.
 
 When used in conjunction with other functions, you can get a random item. For
 example, for a random pet lure:
@@ -5196,7 +5198,7 @@ More info, see doc/item_group.txt.
 
 Similar to the above example, this command allows players to obtain the specified
 quantity of a random item from the group "<group id>". The different groups and
-their group number are specified in db/(pre-)re/item_group_db.txt
+their group number are specified in db/(pre-)re/item_group_db.yml
 
 If 'quantity' is not defined or 0, it will uses defined amount from Item Group list.
 
@@ -6417,6 +6419,7 @@ The variable 'killedgid' is set to the ID (unique mob game ID) of the monster ki
 	AI_ZANZOU	(4)		(Kagerou/Oboro skill)
 	AI_LEGION	(5)		(Sera skill)
 	AI_FAW		(6)		(Mechanic skill)
+	AI_WAVEMODE	(7)		Normal monsters will ignore attack from AI_WAVEMODE monsters
 
     monster "place",60,100,"Poring",1002,1,"NPCNAME::OnLabel";
 
@@ -6520,7 +6523,7 @@ command, simply use 1 for type. Any other number won't be recognized.
 *strmobinfo(<type>,<monster id>);
 
 This function will return information about a monster record in the database, as
-per 'db/(pre-)re/mob_db.txt'. Type is the kind of information returned. Valid types are:
+per 'db/(pre-)re/mob_db.yml'. Type is the kind of information returned. Valid types are:
 It will return 0 if there is no such monster (or the type value is invalid),
 or an empty string if you requested the monster's name.
 
@@ -6623,6 +6626,22 @@ Examples:
 
 ---------------------------------------
 
+*mob_setidleevent <GID>,<event>;
+
+This command will attach an event label to the monster with the given <GID> which will execute
+when the <GID> is idle.
+
+Example:
+	monster "prontera",0,0,"Quest Poring",1002,1;
+	mob_setidleevent $@mobid[0], "NPC NAME::OnIdle";
+	end;
+
+OnIdle:
+	mobchat getattachedrid(),0,0x00FF00,"I'm IDLE!";
+	end;
+
+---------------------------------------
+
 *disablenpc {"<NPC object name>"};
 *enablenpc {"<NPC object name>"};
 
@@ -7636,7 +7655,7 @@ unnerving.
 Only a few NPC sprites have walking animations, and those that do, do not get
 the animation invoked when moving the NPC, due to the problem in the NPC walking
 code, which looks a bit silly. You might have better success by defining a job-
-sprite based sprite id in 'db/mob_avail.txt' with this.
+sprite based sprite id in 'db/mob_avail.yml' with this.
 
 ---------------------------------------
 
@@ -8068,10 +8087,10 @@ flag: Specify target
 
 ---------------------------------------
 
-*unitskilluseid <GID>,<skill id>,<skill lvl>{,<target id>,<casttime>};
-*unitskilluseid <GID>,"<skill name>",<skill lvl>{,<target id>,<casttime>};
-*unitskillusepos <GID>,<skill id>,<skill lvl>,<x>,<y>{,<casttime>};
-*unitskillusepos <GID>,"<skill name>",<skill lvl>,<x>,<y>{,<casttime>};
+*unitskilluseid <GID>,<skill id>,<skill lvl>{,<target id>,<casttime>,<cancel>,<Line_ID>};
+*unitskilluseid <GID>,"<skill name>",<skill lvl>{,<target id>,<casttime>,<cancel>,<Line_ID>};
+*unitskillusepos <GID>,<skill id>,<skill lvl>,<x>,<y>{,<casttime>,<cancel>,<Line_ID>};
+*unitskillusepos <GID>,"<skill name>",<skill lvl>,<x>,<y>{,<casttime>,<cancel>,<Line_ID>};
 
 This is the replacement of the older commands, these use the same values for
 GID as the other unit* commands (See 'GID').
@@ -8081,6 +8100,12 @@ Cast time is the amount of seconds to add or remove from the skill. Use a positi
 add and negative value to subtract. Using 0 or no value will use the default skill cast time.
 For the position, the x and y are given in the UnitSkillUsePos.
 
+<cancel> defines if the cast can be interrupted when hit (true/false).
+CastCancel from skill_db.yml is the default value of <cancel>.
+
+If <Line_ID> is defined (positive number, default 0) the monster will say the message from 'Line_ID'
+in mob_chat_db.yml when casting the skill.
+
 ---------------------------------------
 
 *unitexists <GID>;
@@ -8208,6 +8233,7 @@ Parameters (indexes) for monsters are:
 	UMOB_ROBE
 	UMOB_BODY2
 	UMOB_GROUP_ID
+	UMOB_IGNORE_CELL_STACK_LIMIT
 
 -----
 

+ 808 - 0
npc/re/instances/WaveMode.txt

@@ -0,0 +1,808 @@
+//===== rAthena Script =======================================
+//= Wave Mode
+//===== Description: =========================================
+//= [Walkthrough Conversion]
+//= Wave Mode Forest and Sky Instances
+//- Officially monsters can use their skills
+//    (NPC_SUMMONSLAVE, at least). NPC_EMOTION and
+//    NPC_EMOTION_ON have been blocked since it disrupts the
+//    walk system of the instance on rAthena.
+//- Note: The instance is currently disabled on KRO.
+//===== Changelogs: ==========================================
+//= 1.0 First version. [Capuche]
+//============================================================
+
+// Simple function to move the monster when idle.
+// Move the monster to the next coordinates + end the script on successful; kill the monster + return on failure
+// callfunc( "F_mobidle", <npc name + idle label>, <size coord>, <defined x array>, <x shift>,  <defined y array>, <defined spot-spot distance array> );
+function	script	F_mobidle	{
+	sleep2 1000;	// stop if no RID
+
+	.@game_id = getattachedrid();
+	.@dist_min = 300;
+	.@size = getarg(1);
+	.@dx = getarg(3);
+	getunitdata .@game_id, .@data;
+
+	for ( .@i = 0; .@i < .@size; .@i++ ) {
+		.@dist_to_spot[.@i] = distance( .@data[UMOB_X], .@data[UMOB_Y], (getelementofarray( getarg(2),.@i ) + .@dx), getelementofarray( getarg(4),.@i ) );
+		if (.@dist_min >= .@dist_to_spot[.@i]) {
+			.@dist_min = .@dist_to_spot[.@i];
+			.@index = .@i;
+		}
+	}
+
+	if (.@dist_min <= 1) {
+		.@index++;
+		if (.@index >= .@size) {
+			unitskilluseid .@game_id,301,1,.@game_id,1,false,41;	// SA_INSTANTDEATH
+			return;
+		}
+	}
+	else if (.@index < (.@size -1)) {
+		.@total[0] = .@dist_min + getelementofarray( getarg(5), .@index );
+		.@total[1] = .@dist_to_spot[.@index + 1] + getelementofarray( getarg(5), .@index+1 );
+		if (.@total[0] > .@total[1])
+			.@index = .@index + 1;
+	}
+
+	if (.@dist_to_spot[.@index] > 14) {
+		unitkill .@game_id;
+		end;
+	}
+	if (!.@data[UMOB_TARGETID]) {
+		unitwalk .@game_id, (getelementofarray( getarg(2),.@index ) + .@dx), getelementofarray( getarg(4),.@index );
+		sleep2 50;	// for now a delay between unitwalk and mob_setidleevent is needed
+	}
+	mob_setidleevent .@game_id, getarg(0);
+	end;
+}
+
+prontera,146,75,1	script	Zonda Rep#pron	4_F_ZONDAGIRL,{
+	.@player_name$ = strcharinfo(0);
+	getmapxy .@map_name$,.@x,.@y, BL_PC;
+
+	if (is_party_leader() == true) {
+		.@party_id = getcharid(1);
+		getpartymember .@party_id, 1;
+		getpartymember .@party_id, 2;
+		for ( .@i = 0; .@i < $@partymembercount; .@i++ ) {
+			if (isloggedin($@partymemberaid[.@i], $@partymembercid[.@i]) == 1)
+				.@count_online++;
+		}
+		.@menu_entry$ = "Request entry.";
+	}
+
+	mes "[Belka]";
+	mes "Welcome to Zonda, where innovation begins. What can I do for you?";
+	next;
+	switch( select( "Why are you here?", .@menu_entry$, "Enter ^6B9900<Wave Mode - Forest>^000000.", "Enter ^6B9900<Wave Mode - Sky>^000000.", "Cancel." ) ) {
+	case 1:
+		mes "[Belka]";
+		mes "We now offer a new service. Have you heard about the dimensional rifts?";
+		next;
+		mes "[Belka]";
+		mes "In case you haven't, many organizations and scientists study the rifts formed between dimensions.";
+		next;
+		mes "[Belka]";
+		mes "One of them is my company, Zonda, and after long, painstaking research...";
+		next;
+		mes "[Belka]";
+		mes "We've developed two different dimensional rifts that we call Wave Modes - Forest and Sky!";
+		next;
+		mes "[Belka]";
+		mes "Do you have any questions about Zonda's ambitious new project, Wave Mode?";
+		while(true) {
+			next;
+			switch( select( "About ^6B9900<Wave Mode - Forest>^000000", "About ^6B9900<Wave Mode - Sky>^000000", "No." ) ) {
+			case 1:
+				mes "[Belka]";
+				mes "The ^6B9900<Wave Mode - Forest>^000000";
+				mes "Introducing the first Wave Mode service, Zonda's objective is to work with your party members to keep monster waves from reaching the other side of the bridge.";
+				next;
+				mes "[Belka]";
+				mes "Monsters will advance without fighting, but the party will fail if 20 monsters are let go..";
+				break;
+			case 2:
+				mes "[Belka]";
+				mes "The ^6B9900<Wave Mode - Sky>^000000";
+				mes "Available once a day. Like the other Wave Mode, keep the monsters away from reaching the other side of the map.";
+				next;
+				mes "[Belka]";
+				mes "Feel free to come back with your party.";
+				break;
+			case 3:
+				mes "[Belka]";
+				mes "Thank you for visiting Zonda, where innovation begins.";
+				close;
+			}
+			next;
+			mes "[Belka]";
+			mes "Any other questions?";
+		}
+	case 2:
+		mes "[Belka]";
+		mes "Which Wave Mode would you like to enter: Forest or Sky?";
+		next;
+		.@s = select( "Enter ^6B9900<Wave Mode - Forest>^000000.", "Enter ^6B9900<Wave Mode - Sky>^000000." ) - 1;
+		setarray .@instance_name$[0], "Wave Mode - Forest", "Wave Mode - Sky";
+		mes "[Belka]";
+		mes "" + .@count_online + " party " + (.@count_online == 1 ? "member" : "members") + " found " + .@player_name$ + ", right? To enter the ^6B9900<" + .@instance_name$[.@s] + ">^000000, please sign here.";
+		next;
+		select("Sign.");
+		mes "[Belka]";
+		mes "" + .@player_name$ + " has requested to enter the ^6B9900<" + .@instance_name$[.@s] + ">^000000. Please come back when it's your turn to enter.";
+		if (instance_create(.@instance_name$[.@s]) < 0) {
+			mes "Party Name: " + getpartyname( getcharid(1) );
+			mes "Party Leader: " + strcharinfo(0);
+			mes "^0000ff" + .@instance_name$[.@s] + " ^000000 - Reservation Failed.";
+			close;
+		}
+		close;
+	case 3:
+		switch( instance_enter("Wave Mode - Forest") ) {
+		case IE_OTHER:
+			mes "[Belka]";
+			mes "An unknown error has occurred.";
+			close;
+		case IE_NOINSTANCE:
+		case IE_NOMEMBER:
+			mes "[Belka]";
+			mes "Please wait for ^6B9900<Wave Mode - Forest>^000000 stabilization.";
+			close;
+		case IE_OK:
+			mapannounce .@map_name$, "" + .@player_name$ + " of the party " + getpartyname(getcharid(1)) + " is entering <Wave Mode - Forest>.", bc_map,0xFF99;
+			// warp "1@def01",50,21;
+			break;
+		}
+		break;
+	case 4:
+		switch( instance_enter("Wave Mode - Sky") ) {
+		case IE_OTHER:
+			mes "[Belka]";
+			mes "An unknown error has occurred.";
+			close;
+		case IE_NOINSTANCE:
+		case IE_NOMEMBER:
+			mes "[Belka]";
+			mes "Currently the ^6B9900<Wave Mode - Sky>^000000 is being stabilized for your convenience. Please wait.";
+			close;
+		case IE_OK:
+			mapannounce .@map_name$, "" + .@player_name$ + " of the party " + getpartyname(getcharid(1)) + " is entering <Wave Mode - Sky>.", bc_map,0xFF99;
+			// warp "1@def02",29,35;
+			break;
+		}
+		break;
+	case 5:
+		mes "[Belka]";
+		mes "Thank you for visiting Zonda, where innovation begins.";
+		close;
+	}
+	wave_mode_map$ = .@map_name$;
+	wave_mode_x = .@x;
+	wave_mode_y = .@y;
+	end;
+}
+payon,166,98,1	duplicate(Zonda Rep#pron)	Zonda Rep#pay	4_F_ZONDAGIRL
+moc_para01,45,89,3	duplicate(Zonda Rep#pron)	Zonda Rep#para	4_F_ZONDAGIRL
+morocc,168,271,4	duplicate(Zonda Rep#pron)	Zonda Rep#mor	4_F_ZONDAGIRL
+
+
+// Wave mode forest
+1@def01,50,21,0	script	#wave_mode_forest_entrance	HIDDEN_WARP_NPC,1,1,{
+	end;
+OnTouch:
+	disablenpc instance_npcname("#wave_mode_forest_entrance");
+	initnpctimer;
+	end;
+OnTimer2000:
+	mapannounce 'map_def01$, "We would like to thank all loyal customers of the Cool Event Corporation.", bc_map;
+	end;
+OnTimer7000:
+	mapannounce 'map_def01$, "<Wave mode - Forest> prevent monsters from reaching the other side of the bridge.", bc_map;
+	end;
+OnTimer12000:
+	mapannounce 'map_def01$, "If 20 monsters reach the other side, the game is over.", bc_map;
+	end;
+OnTimer17000:
+	mapannounce 'map_def01$, "Ok, here they come.", bc_map;
+	end;
+OnTimer22000:
+	stopnpctimer;
+	donpcevent instance_npcname("#wave_mode_forest_system") + "::OnStart";
+	end;
+}
+
+1@def01,1,1,0	script	#wave_mode_forest_system	-1,{
+	end;
+OnStart:
+	initnpctimer;
+	end;
+OnTimer1000:
+	mapannounce 'map_def01$, "3", bc_map;
+	end;
+OnTimer2000:
+	mapannounce 'map_def01$, "2", bc_map;
+	end;
+OnTimer3000:
+	mapannounce 'map_def01$, "1", bc_map;
+	end;
+OnTimer4000:
+	'wave++;
+	if ('wave % 5)
+		mapannounce 'map_def01$, "-- Wave " + 'wave + " --", bc_map;
+	else
+		mapannounce 'map_def01$, "!! Champions summoned !!", bc_map;
+	donpcevent 'npc_name$ + "::OnSpawn";
+	end;
+OnTimer24000:
+	mapannounce 'map_def01$, "Next monsters will come out soon. Get ready.", bc_map;
+	initnpctimer;
+	end;
+OnStop:
+	stopnpctimer;
+	end;
+}
+
+1@def01,1,1,0	script	#wave_mode_forest_spawn	-1,{
+	end;
+OnSpawn:
+	switch( 'wave % 70 ) {
+	case 1:
+		'mob_id = 2401;	// G_PORING
+		break;
+	case 2:
+		'mob_id = 2582;	// G_LUNATIC
+		break;
+	case 3:
+		'mob_id = 2573;	// G_CHONCHON
+		break;
+	case 4:
+		'mob_id = 2590;	// G_ROCKER
+		break;
+	case 5:
+		'mob_id = 2699;	// C1_PORING
+		break;
+
+	case 6:
+		'mob_id = 2577;	// G_FABRE
+		break;
+	case 7:
+		'mob_id = 1747;	// G_SNAKE
+		break;
+	case 8:
+		'mob_id = 2595;	// G_STAINER
+		break;
+	case 9:
+		'mob_id = 2576;	// G_CREAMY
+		break;
+	case 10:
+		'mob_id = 2678;	// C3_RODA_FROG
+		break;
+
+	case 11:
+		'mob_id = 2572;	// G_CARAMEL
+		break;
+	case 12:
+		'mob_id = 1603;	// G_BIGFOOT
+		break;
+	case 13:
+		'mob_id = 2589;	// G_POPORING
+		break;
+	case 14:
+		'mob_id = 2578;	// G_HORN
+		break;
+	case 15:
+		'mob_id = 2670;	// C5_SCORPION
+		break;
+
+	case 16:
+		'mob_id = 2601;	// G_YOYO
+		break;
+	case 17:
+		'mob_id = 2575;	// G_COCO
+		break;
+	case 18:
+		'mob_id = 2583;	// G_MARTIN
+		break;
+	case 19:
+		'mob_id = 2600;	// G_WOLF
+		break;
+	case 20:
+		'mob_id = 2705;	// C2_POISON_SPORE
+		break;
+
+	case 21:
+		'mob_id = 1430;	// G_ARGOS
+		break;
+	case 22:
+		'mob_id = 2597;	// G_STEEL_CHONCHON
+		break;
+	case 23:
+		'mob_id = 1431;	// G_BAPHOMET_
+		break;
+	case 24:
+		'mob_id = 2591;	// G_SAVAGE
+		break;
+	case 25:
+		'mob_id = 2857;	// C5_DENIRO
+		break;
+
+	case 26:
+		'mob_id = 1457;	// G_MANTIS
+		break;
+	case 27:
+		'mob_id = 1424;	// G_SIDE_WINDER
+		break;
+	case 28:
+		'mob_id = 1429;	// G_ARGIOPE
+		break;
+	case 29:
+		'mob_id = 1441;	// G_PENOMENA
+		break;
+	case 30:
+		'mob_id = 2648;	// C3_SOLDIER_SKELETON
+		break;
+
+	case 31:
+		'mob_id = 1422;	// G_HUNTER_FLY
+		break;
+	case 32:
+		'mob_id = 2585;	// G_MOLE
+		break;
+	case 33:
+		'mob_id = 2592;	// G_SIORAVA
+		break;
+	case 34:
+		'mob_id = 2571;	// G_BUTOIJO
+		break;
+	case 35:
+		'mob_id = 2673;	// C3_SAVAGE
+		break;
+
+	case 36:
+		'mob_id = 2574;	// G_CIVIL_SERVANT
+		break;
+	case 37:
+		'mob_id = 1459;	// G_MARIONETTE
+		break;
+	case 38:
+		'mob_id = 1565;	// G_WILD_GINSENG
+		break;
+	case 39:
+		'mob_id = 2602;	// G_ZIPPER_BEAR
+		break;
+	case 40:
+		'mob_id = 2644;	// C4_STALACTIC_GOLEM
+		break;
+
+	case 41:
+		'mob_id = 2588;	// G_PITMAN
+		break;
+	case 42:
+		'mob_id = 1624;	// G_WASTE_STOVE
+		break;
+	case 43:
+		'mob_id = 2570;	// G_BREEZE
+		break;
+	case 44:
+		'mob_id = 1573;	// G_ELDER
+		break;
+	case 45:
+		'mob_id = 2811;	// C3_GRAND_PECO
+		break;
+
+	case 46:
+		'mob_id = 2598;	// G_UNGOLIANT
+		break;
+	case 47:
+		'mob_id = 1606;	// G_GARM_BABY
+		break;
+	case 48:
+		'mob_id = 1794;	// G_ROWEEN
+		break;
+	case 49:
+		'mob_id = 2596;	// G_STAPO
+		break;
+	case 50:
+		'mob_id = 2838;	// C5_EVIL_DRUID
+		break;
+
+	case 51:
+		'mob_id = 2569;	// G_ANOPHELES
+		break;
+	case 52:
+		'mob_id = 2584;	// G_MINERAL
+		break;
+	case 53:
+		'mob_id = 2599;	// G_WILD_RIDER
+		break;
+	case 54:
+		'mob_id = 1531;	// G_EVIL_CLOUD_HERMIT
+		break;
+	case 55:
+		'mob_id = 2612;	// C5_WOOD_GOBLIN
+		break;
+
+	case 56:
+		'mob_id = 2587;	// G_OBSIDIAN
+		break;
+	case 57:
+		'mob_id = 1564;	// G_WICKED_NYMPH
+		break;
+	case 58:
+		'mob_id = 2586;	// G_NERAID
+		break;
+	case 59:
+		'mob_id = 1483;	// G_RYBIO
+		break;
+	case 60:
+		'mob_id = 2888;	// C2_BANASPATY
+		break;
+
+	case 61:
+		'mob_id = 2593;	// G_SIROMA
+		break;
+	case 62:
+		'mob_id = 2580;	// G_KAHO
+		break;
+	case 63:
+		'mob_id = 1600;	// G_HEATER
+		break;
+	case 64:
+		'mob_id = 1791;	// G_GALION
+		break;
+	case 65:
+		'mob_id = 2629;	// C3_UNGOLIANT
+		break;
+
+	case 66:
+		'mob_id = 2581;	// G_LUDE
+		break;
+	case 67:
+		'mob_id = 2579;	// G_HYLOZOIST
+		break;
+	case 68:
+		'mob_id = 1549;	// G_LAVA_GOLEM
+		break;
+	case 69:
+		'mob_id = 2594;	// G_SNOWIER
+		break;
+	default:
+		'mob_id = 2730;	// C2_NOVUS
+		break;
+	}
+	initnpctimer;
+	end;
+OnTimer1000:
+	stopnpctimer;
+	if (('wave % 5) == 0) {	// champion
+		donpcevent 'npc_name$ + "::OnSpawn0";
+		donpcevent 'npc_name$ + "::OnSpawn1";
+		donpcevent 'npc_name$ + "::OnSpawn2";
+		donpcevent 'npc_name$ + "::OnSpawn3";
+		donpcevent 'npc_name$ + "::OnSpawn4";
+		end;
+	}
+	if ('wave == 1)	// first wave at x = 51
+		.@dx = 3;
+	else
+		.@dx = 2;
+	for ( .@i = 0; .@i < 24; .@i++ ) {
+		donpcevent 'npc_name$ + "::OnSpawn" + .@dx;
+		sleep 300;
+	}
+	// total ~7 secs
+	end;
+OnSpawn0: callsub( S_Spawn, 0 );
+OnSpawn1: callsub( S_Spawn, 1 );
+OnSpawn2: callsub( S_Spawn, 2 );
+OnSpawn3: callsub( S_Spawn, 3 );
+OnSpawn4: callsub( S_Spawn, 4 );
+S_Spawn:
+	.@x = 48 + getarg(0);
+	monster 'map_def01$,.@x,74, "Invader!", 'mob_id,1;
+	.@gid = $@mobid[0];
+	setunitdata .@gid, UMOB_MODE, ( MD_CANMOVE|MD_NORANDOMWALK );
+	setunitdata .@gid, UMOB_IGNORE_CELL_STACK_LIMIT, true;
+	mob_setidleevent .@gid, 'npc_name$ + "::OnIdle" + getarg(0);
+	end;
+
+OnIdle0: callsub( S_Idle, 0 );
+OnIdle1: callsub( S_Idle, 1 );
+OnIdle2: callsub( S_Idle, 2 );
+OnIdle3: callsub( S_Idle, 3 );
+OnIdle4: callsub( S_Idle, 4 );
+S_Idle:
+	callfunc( "F_mobidle", ('npc_name$ + "::OnIdle" + getarg(0)), 'size_coord, 'x_mob, getarg(0), 'y_mob, 'dist_spot_AZ );
+	'mob_escaped++;
+	if ('mob_escaped <= 20)
+		mapannounce 'map_def01$, "" + 'mob_escaped + " " + ('mob_escaped == 1 ? "monster has" : "monsters have") + " escaped.", bc_map;
+	if ('mob_escaped == 20)
+		donpcevent instance_npcname("#wave_mode_forest_out") + "::OnFail";
+	end;
+}
+
+// 1@def01,50,23,0	script	#wave_mode_forest_warp	WARPNPC,2,2,{
+1@def01,50,30,0	script	#wave_mode_forest_warp	WARPNPC,2,2,{// official warp out
+	end;
+OnTouch:
+	if (wave_mode_map$ == "")
+		warp "prontera",0,0;
+	else {
+		warp wave_mode_map$, wave_mode_x, wave_mode_y;
+		wave_mode_map$ = "";
+		wave_mode_x = wave_mode_y = 0;
+	}
+	end;
+}
+
+1@def01,1,1,0	script	#wave_mode_forest_out	-1,{
+	end;
+OnFail:
+	donpcevent instance_npcname("#wave_mode_forest_system") + "::OnStop";
+
+	mapannounce 'map_def01$, "You have failed the <Wave mode - Forest> challenge.", bc_map;
+	enablenpc instance_npcname("#wave_mode_forest_warp");
+	initnpctimer;
+	end;
+OnTimer1000:
+	mapannounce 'map_def01$, "<Wave mode - Forest> service has closed. You will be returned to the place you entered if you use the warp at the entrance.", bc_map;
+	end;
+OnTimer30000:
+	stopnpctimer;
+	instance_destroy();
+	end;
+
+OnInstanceInit:
+	'wave = 'mob_escaped = 0;
+
+	'map_def01$ = instance_mapname("1@def01");
+	'npc_name$ = instance_npcname("#wave_mode_forest_spawn");
+
+	disablenpc instance_npcname("#wave_mode_forest_system");
+	disablenpc instance_npcname("#wave_mode_forest_warp");
+	disablenpc instance_npcname("#wave_mode_forest_out");
+
+	setarray 'x_mob[0], 48, 48, 48, 48, 48, 48, 48;
+	setarray 'y_mob[0], 74, 65, 56, 48, 40, 31, 23;
+
+	'size_coord = getarraysize('y_mob);
+	for ( .@i = 0; .@i < 'size_coord -1; .@i++ ) {
+		.@dist_mob[.@i+1] = distance( 'x_mob[.@i], 'y_mob[.@i], 'x_mob[.@i+1], 'y_mob[.@i+1] );
+		.@total_mob += .@dist_mob[.@i+1];
+	}
+	for ( .@i = 0; .@i < 'size_coord -1; .@i++ )
+		'dist_spot_AZ[.@i] = .@total_mob - .@dist_mob[.@i];
+	end;
+}
+
+
+// Wave mode sky
+1@def02,30,35,0	script	#wave_mode_sky_entrance	WARPNPC,1,1,{
+	end;
+OnTouch:
+	if ('status_instance == 1)
+		end;
+	else if ('status_instance == 0) {
+		'status_instance = 1;
+		initnpctimer;
+		disablenpc instance_npcname("#wave_mode_sky_entrance");
+	}
+	else if ('status_instance == 2) {
+		if (wave_mode_map$ == "")
+			warp "prontera",0,0;
+		else {
+			warp wave_mode_map$, wave_mode_x, wave_mode_y;
+			wave_mode_map$ = "";
+			wave_mode_x = wave_mode_y = 0;
+		}
+	}
+	end;
+OnTimer4000:
+	stopnpctimer;
+	donpcevent instance_npcname("#wave_mode_sky_system") + "::OnStart";
+	end;
+}
+
+1@def02,1,1,0	script	#wave_mode_sky_system	-1,{
+	end;
+OnStart:
+	initnpctimer;
+	mapannounce 'map_def02$, "We would like to thank all costumers who always use Zonda Agency.", bc_map;
+	end;
+OnTimer1000:
+	mapannounce 'map_def02$, "3", bc_map;
+	end;
+OnTimer2000:
+	mapannounce 'map_def02$, "2", bc_map;
+	end;
+OnTimer3000:
+	mapannounce 'map_def02$, "1", bc_map;
+	end;
+OnTimer4000:
+	'wave_num++;
+	if ('wave_num % 5) {
+		donpcevent 'npc_name_mob$ + "::OnSpawn";
+		donpcevent 'npc_name_mercenary$ + "::OnStart";
+		donpcevent 'npc_name_mercenary$ + "::OnStart";
+	}
+	else {
+		donpcevent 'npc_name_treasure$ + "::OnStart";
+	}
+	end;
+OnTimer24000:
+	mapannounce 'map_def02$, "Next monster wave will come out soon. Get ready.", bc_map;
+	initnpctimer;
+	end;
+OnStop:
+	stopnpctimer;
+	end;
+}
+
+1@def02,1,1,0	script	#wave_mode_sky_treasure	-1,{
+	end;
+OnStart:
+	if ('treasure_num < 5)
+		'treasure_num++;
+	mapannounce 'map_def02$, "!! " + 'treasure_num + " treasure box appeared !!", bc_map;
+	for ( .@i = 0; .@i < 'treasure_num; .@i++ ) {
+		monster 'map_def02$,0,0, "Treasure box",3075,1;	// WA_TREASURE
+		'treasure_gid[.@i] = $@mobid[0];
+	}
+	initnpctimer;
+	end;
+OnTimer16500: callsub( S_Dice, ET_DICE3 );
+OnTimer17500: callsub( S_Dice, ET_DICE2 );
+OnTimer18500: callsub( S_Dice, ET_DICE1 );
+OnTimer19500:
+	for ( .@i = 0; .@i < 'treasure_num; .@i++ ) {
+		if (unitexists('treasure_gid[.@i]))
+			unitskilluseid 'treasure_gid[.@i],301,1,'treasure_gid[.@i],-1;	// SA_INSTANTDEATH
+	}
+	donpcevent 'npc_name_treasure$ + "::OnStop";
+	end;
+
+S_Dice:
+	.@emotion_num = getarg(0);
+	for ( .@i = 0; .@i < 'treasure_num; .@i++ ) {
+		if (unitexists('treasure_gid[.@i]))
+			emotion .@emotion_num, 'treasure_gid[.@i];
+	}
+	end;
+
+OnStop:
+	deletearray 'treasure_gid[0], 'treasure_num;
+	stopnpctimer;
+	end;
+}
+
+1@def02,1,1,0	script	#wave_mode_sky_mercenary	-1,{
+	end;
+OnStart:
+	monster 'map_def02$,29,35, "Mercenary", 3086,1, "",0,AI_WAVEMODE;	// WA_MERCENARY
+	.@gid = $@mobid[0];
+	emotion ET_SURPRISE, .@gid;
+	setunitdata .@gid, UMOB_IGNORE_CELL_STACK_LIMIT, true;
+	mob_setidleevent .@gid, 'npc_name_mercenary$ + "::OnIdle";
+	sleep 45000;
+	if (unitexists(.@gid))
+		unitskilluseid .@gid,301,1,.@gid,1,false;	// SA_INSTANTDEATH
+	end;
+
+OnIdle:
+	callfunc( "F_mobidle", ('npc_name_mercenary$ + "::OnIdle"), 'size_coord, 'x_merc, 0, 'y_merc, 'dist_spot_ZA );
+	end;
+}
+
+1@def02,1,1,0	script	#wave_mode_sky_mob_spawn	-1,{
+	end;
+OnSpawn:
+	mapannounce 'map_def02$, "-- Wave " + 'wave_num + " --", bc_map;
+
+	.@i = ('wave_num % 10) - 1;
+	setarray .@mob_list[0],
+		3076,	// WA_MONSTER_1
+		3077,	// WA_MONSTER_2
+		3078,	// WA_MONSTER_3
+		3079,	// WA_MONSTER_4
+		3080,	// WA_MONSTER_5 (skipped)
+		3081,	// WA_MONSTER_6
+		3082,	// WA_MONSTER_7
+		3083,	// WA_MONSTER_8
+		3084,	// WA_MONSTER_9
+		3085;	// WA_MONSTER_10 (skipped)
+	'mob_id = .@mob_list[.@i];
+	initnpctimer;
+	end;
+OnTimer1000: callsub( S_Spawn, true );	// aggressive
+OnTimer1500: callsub( S_Spawn, false );	// passive
+OnTimer2000: callsub( S_Spawn, true );
+OnTimer2500: callsub( S_Spawn, false );
+OnTimer3000: callsub( S_Spawn, true );
+OnTimer3500: callsub( S_Spawn, false );
+OnTimer4000: callsub( S_Spawn, true );
+OnTimer4500: callsub( S_Spawn, false );
+OnTimer5000: callsub( S_Spawn, true );
+OnTimer5500: callsub( S_Spawn, false );
+OnTimer6000: callsub( S_Spawn, true );
+OnTimer6500: callsub( S_Spawn, false );
+OnTimer7000: callsub( S_Spawn, true );
+OnTimer7500: callsub( S_Spawn, false );
+OnTimer8000: callsub( S_Spawn, true );
+OnTimer8500:
+	stopnpctimer;
+	end;
+
+S_Spawn:
+	monster 'map_def02$,48,67, "Go!", 'mob_id,1;
+	if (getarg(0) == true)
+		setunitdata $@mobid[0], UMOB_MODE, ( MD_CANMOVE|MD_NORANDOMWALK|MD_AGGRESSIVE|MD_CANATTACK );
+	.@gid = $@mobid[0];
+	emotion ET_SURPRISE, .@gid;
+	setunitdata .@gid, UMOB_IGNORE_CELL_STACK_LIMIT, true;
+	mob_setidleevent .@gid, 'npc_name_mob$ + "::OnIdle";
+	end;
+
+OnIdle:
+	// monster are walking to the nearest next spot
+	callfunc( "F_mobidle", ('npc_name_mob$ + "::OnIdle"), 'size_coord, 'x_mob, 0, 'y_mob, 'dist_spot_AZ );
+	'mob_escaped++;
+	if ('mob_escaped <= 20)
+		mapannounce 'map_def02$, "" + 'mob_escaped + " " + ('mob_escaped == 1 ? "monster has" : "monsters have") + " escaped.", bc_map;
+	if ('mob_escaped == 20)
+		donpcevent instance_npcname("#wave_mode_sky_out") + "::OnFail";
+	end;
+}
+
+
+1@def02,1,1,0	script	#wave_mode_sky_out	-1,{
+	end;
+OnFail:
+	// monsters timers continue
+	donpcevent instance_npcname("#wave_mode_sky_system") + "::OnStop";
+
+	mapannounce 'map_def02$, "You have failed the <Wave mode - Sky> challenge.", bc_map;
+	'status_instance = 2;
+	enablenpc instance_npcname("#wave_mode_sky_entrance");
+	initnpctimer;
+	end;
+OnTimer1000:
+	mapannounce 'map_def02$, "<Wave mode - Sky> service has closed. You will be returned to the place you entered if you use the warp at the entrance.", bc_map;
+	end;
+OnTimer30000:
+	stopnpctimer;
+	instance_destroy();
+	end;
+
+OnInstanceInit:
+	deletearray 'treasure_gid[0], 'treasure_num;
+	'wave_num = 'treasure_num = 'status_instance = 'mob_escaped = 0;
+
+	'map_def02$ = instance_mapname("1@def02");
+
+	'npc_name_mob$ = instance_npcname("#wave_mode_sky_mob_spawn");
+	'npc_name_treasure$ = instance_npcname("#wave_mode_sky_treasure");
+	'npc_name_mercenary$ = instance_npcname("#wave_mode_sky_mercenary");
+
+	disablenpc instance_npcname("#wave_mode_sky_out");
+
+	setarray 'x_mob[0], 48, 38, 30, 30, 29, 38, 47, 51, 50, 42, 33, 29;
+	setarray 'y_mob[0], 67, 67, 64, 58, 52, 52, 51, 45, 36, 36, 36, 35;
+
+	setarray 'x_merc[0], 29, 33, 42, 50, 51, 47, 38, 29, 30, 30, 38, 47;
+	setarray 'y_merc[0], 35, 36, 36, 36, 45, 51, 52, 52, 58, 64, 67, 67;
+
+	'size_coord = getarraysize('x_mob);
+	for ( .@i = 0; .@i < 'size_coord -1; .@i++ ) {
+		.@dist_mob[.@i+1] = distance( 'x_mob[.@i], 'y_mob[.@i], 'x_mob[.@i+1], 'y_mob[.@i+1] );
+		.@total_mob += .@dist_mob[.@i+1];
+		.@dist_merc[.@i+1] = distance( 'x_merc[.@i], 'y_merc[.@i], 'x_merc[.@i+1], 'y_merc[.@i+1] );
+		.@total_merc += .@dist_merc[.@i+1];
+	}
+	for ( .@i = 0; .@i < 'size_coord -1; .@i++ ) {
+		'dist_spot_AZ[.@i] = .@total_mob - .@dist_mob[.@i];
+		'dist_spot_ZA[.@i] = .@total_merc - .@dist_merc[.@i];
+	}
+	end;
+}

+ 3 - 3
npc/re/mapflag/restricted.txt

@@ -25,9 +25,9 @@
 2@gl_k	mapflag	restricted	6
 
 // Wave Mode Memorial Dungeon ====
-1@def01	mapflag	restricted	6
-1@def02	mapflag	restricted	6
-1@def03	mapflag	restricted	6
+1@def01	mapflag	restricted	9
+1@def02	mapflag	restricted	9
+1@def03	mapflag	restricted	9
 
 // Heroes' Trail - Part 1 ========
 1@face	mapflag	restricted	6

+ 1 - 1
npc/re/scripts_athena.conf

@@ -87,7 +87,7 @@ npc: npc/re/instances/RoomOfConsciousness.txt
 npc: npc/re/instances/SarahAndFenrir.txt
 npc: npc/re/instances/SaraMemory.txt
 npc: npc/re/instances/SkyFortress.txt
-
+//npc: npc/re/instances/WaveMode.txt
 npc: npc/re/instances/WernerLaboratoryCentralRoom.txt
 npc: npc/re/instances/WolfchevLaboratory.txt
 //npc: npc/custom/official/GeffenMagicTournament.txt

+ 2 - 2
src/map/battle.cpp

@@ -8424,9 +8424,9 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f
 			{ //Normal mobs
 				if(
 					( target->type == BL_MOB && t_bl->type == BL_PC && ( ((TBL_MOB*)target)->special_state.ai != AI_ZANZOU && ((TBL_MOB*)target)->special_state.ai != AI_ATTACK ) ) ||
-					( t_bl->type == BL_MOB && !((TBL_MOB*)t_bl)->special_state.ai )
+					( t_bl->type == BL_MOB && (((TBL_MOB*)t_bl)->special_state.ai == AI_NONE || ((TBL_MOB*)t_bl)->special_state.ai == AI_WAVEMODE ))
 				  )
-					state |= BCT_PARTY; //Normal mobs with no ai are friends.
+					state |= BCT_PARTY; //Normal mobs with no ai or with AI_WAVEMODE are friends.
 				else
 					state |= BCT_ENEMY; //However, all else are enemies.
 			}

+ 1 - 0
src/map/map.hpp

@@ -381,6 +381,7 @@ enum mob_ai {
 	AI_LEGION,
 	AI_FAW,
 	AI_GUILD,
+	AI_WAVEMODE,
 	AI_MAX
 };
 

+ 38 - 20
src/map/mob.cpp

@@ -1516,6 +1516,10 @@ int mob_unlocktarget(struct mob_data *md, t_tick tick)
 		//Because it is not unset when the mob finishes walking.
 		md->state.skillstate = MSS_IDLE;
 	case MSS_IDLE:
+		if( md->ud.walktimer == INVALID_TIMER && md->idle_event[0] && npc_event_do_id( md->idle_event, md->bl.id ) > 0 ){
+			md->idle_event[0] = 0;
+			break;
+		}
 		// Idle skill.
 		if (!(++md->ud.walk_count%IDLE_SKILL_INTERVAL) && mobskill_use(md, tick, -1))
 			break;
@@ -1543,7 +1547,8 @@ int mob_unlocktarget(struct mob_data *md, t_tick tick)
 		md->ud.target_to = 0;
 		unit_set_target(&md->ud, 0);
 	}
-	if (battle_config.official_cell_stack_limit > 0
+	
+	if (!md->ud.state.ignore_cell_stack_limit && battle_config.official_cell_stack_limit > 0
 		&& (md->min_chase == md->db->range3 || battle_config.mob_ai & 0x8)
 		&& map_count_oncell(md->bl.m, md->bl.x, md->bl.y, BL_CHAR | BL_NPC, 1) > battle_config.official_cell_stack_limit) {
 		unit_walktoxy(&md->bl, md->bl.x, md->bl.y, 8);
@@ -2045,6 +2050,15 @@ static int mob_ai_sub_lazy(struct mob_data *md, va_list args)
 		return 0;
 	}
 
+	if (md->ud.walktimer == INVALID_TIMER) {
+		// Because it is not unset when the mob finishes walking.
+		md->state.skillstate = MSS_IDLE;
+		if (md->idle_event[0] && npc_event_do_id( md->idle_event, md->bl.id ) > 0) {
+			md->idle_event[0] = 0;
+			return 0;
+		}
+	}
+
 	if( DIFF_TICK(md->next_walktime,tick) < 0 && status_has_mode(&md->status,MD_CANMOVE) && unit_can_move(&md->bl) )
 	{
 		// Move probability for mobs away from players
@@ -2056,9 +2070,6 @@ static int mob_ai_sub_lazy(struct mob_data *md, va_list args)
 	}
 	else if( md->ud.walktimer == INVALID_TIMER )
 	{
-		//Because it is not unset when the mob finishes walking.
-		md->state.skillstate = MSS_IDLE;
-
 		// Probability for mobs far from players from doing their IDLE skill.
 		// In Aegis, this is 100% for mobs that have been activated by players and none otherwise.
 		if( mob_is_spotted(md) &&
@@ -3657,6 +3668,24 @@ struct mob_data *mob_getfriendstatus(struct mob_data *md,int cond1,int cond2)
 	return fr;
 }
 
+// Display message from mob_chat_db.yml
+bool mob_chat_display_message(mob_data &md, uint16 msg_id) {
+	std::shared_ptr<s_mob_chat> mc = mob_chat_db.find(msg_id);
+
+	if (mc != nullptr) {
+		std::string name = md.name, output;
+		std::size_t unique = name.find("#");
+
+		if (unique != std::string::npos)
+			name = name.substr(0, unique); // discard extra name identifier if present [Daegaladh]
+		output = name + " : " + mc->msg;
+
+		clif_messagecolor(&md.bl, mc->color, output.c_str(), true, AREA_CHAT_WOC);
+		return true;
+	}
+	return false;
+}
+
 /*==========================================
  * Skill use judging
  *------------------------------------------*/
@@ -3856,18 +3885,7 @@ int mobskill_use(struct mob_data *md, t_tick tick, int event)
 		}
 		//Skill used. Post-setups...
 		if ( ms[i]->msg_id ){ //Display color message [SnakeDrak]
-			std::shared_ptr<s_mob_chat> mc = mob_chat_db.find(ms[i]->msg_id);
-
-			if (mc) {
-				std::string name = md->name, output;
-				std::size_t unique = name.find("#");
-
-				if (unique != std::string::npos)
-					name = name.substr(0, unique); // discard extra name identifier if present [Daegaladh]
-				output = name + " : " + mc->msg;
-
-				clif_messagecolor(&md->bl, mc->color, output.c_str(), true, AREA_CHAT_WOC);
-			}
+			mob_chat_display_message(*md, ms[i]->msg_id);
 		}
 		if(!(battle_config.mob_ai&0x200)) { //pass on delay to same skill.
 			for (j = 0; j < ms.size(); j++)
@@ -4446,7 +4464,7 @@ uint64 MobDatabase::parseBodyNode(const YAML::Node &node) {
 			mob->status.rhw.atk2 = 0;
 #endif
 	}
-	
+
 	if (this->nodeExists(node, "Defense")) {
 		uint16 def;
 
@@ -4463,7 +4481,7 @@ uint64 MobDatabase::parseBodyNode(const YAML::Node &node) {
 		if (!exists)
 			mob->status.def = 0;
 	}
-	
+
 	if (this->nodeExists(node, "MagicDefense")) {
 		uint16 def;
 
@@ -4480,7 +4498,7 @@ uint64 MobDatabase::parseBodyNode(const YAML::Node &node) {
 		if (!exists)
 			mob->status.mdef = 0;
 	}
-	
+
 	if (this->nodeExists(node, "Str")) {
 		uint16 stat;
 
@@ -4552,7 +4570,7 @@ uint64 MobDatabase::parseBodyNode(const YAML::Node &node) {
 		if (!exists)
 			mob->status.luk = 1;
 	}
-	
+
 	if (this->nodeExists(node, "AttackRange")) {
 		uint16 range;
 

+ 2 - 0
src/map/mob.hpp

@@ -333,6 +333,7 @@ struct mob_data {
 	int8 skill_idx; // Index of last used skill from db->skill[]
 	t_tick skilldelay[MAX_MOBSKILL];
 	char npc_event[EVENT_NAME_LENGTH];
+	char idle_event[EVENT_NAME_LENGTH];
 	/**
 	 * Did this monster summon something?
 	 * Used to flag summon deletions, saves a worth amount of memory
@@ -487,6 +488,7 @@ int mob_class_change(struct mob_data *md,int mob_id);
 int mob_warpslave(struct block_list *bl, int range);
 int mob_linksearch(struct block_list *bl,va_list ap);
 
+bool mob_chat_display_message (mob_data &md, uint16 msg_id);
 int mobskill_use(struct mob_data *md,t_tick tick,int event);
 int mobskill_event(struct mob_data *md,struct block_list *src,t_tick tick, int flag);
 int mob_summonslave(struct mob_data *md2,int *value,int amount,uint16 skill_id);

+ 61 - 9
src/map/script.cpp

@@ -18157,6 +18157,7 @@ BUILDIN_FUNC(getunitdata)
 			getunitdata_sub(UMOB_ROBE, md->vd->robe);
 			getunitdata_sub(UMOB_BODY2, md->vd->body_style);
 			getunitdata_sub(UMOB_GROUP_ID, md->ud.group_id);
+			getunitdata_sub(UMOB_IGNORE_CELL_STACK_LIMIT, md->ud.state.ignore_cell_stack_limit);
 			break;
 
 		case BL_HOM:
@@ -18561,6 +18562,7 @@ BUILDIN_FUNC(setunitdata)
 			case UMOB_ROBE: clif_changelook(bl, LOOK_ROBE, (unsigned short)value); break;
 			case UMOB_BODY2: clif_changelook(bl, LOOK_BODY2, (unsigned short)value); break;
 			case UMOB_GROUP_ID: md->ud.group_id = value; unit_refresh(bl); break;
+			case UMOB_IGNORE_CELL_STACK_LIMIT: md->ud.state.ignore_cell_stack_limit = value > 0; break;
 			default:
 				ShowError("buildin_setunitdata: Unknown data identifier %d for BL_MOB.\n", type);
 				return SCRIPT_CMD_FAILURE;
@@ -19284,8 +19286,8 @@ BUILDIN_FUNC(unitemote)
 
 /// Makes the unit cast the skill on the target or self if no target is specified.
 ///
-/// unitskilluseid <unit_id>,<skill_id>,<skill_lv>{,<target_id>,<casttime>};
-/// unitskilluseid <unit_id>,"<skill name>",<skill_lv>{,<target_id>,<casttime>};
+/// unitskilluseid <unit_id>,<skill_id>,<skill_lv>{,<target_id>,<casttime>,<cancel>,<Line_ID>};
+/// unitskilluseid <unit_id>,"<skill name>",<skill_lv>{,<target_id>,<casttime>,<cancel>,<Line_ID>};
 BUILDIN_FUNC(unitskilluseid)
 {
 	int unit_id, target_id, casttime;
@@ -19311,15 +19313,26 @@ BUILDIN_FUNC(unitskilluseid)
 	skill_lv = script_getnum(st,4);
 	target_id = ( script_hasdata(st,5) ? script_getnum(st,5) : unit_id );
 	casttime = ( script_hasdata(st,6) ? script_getnum(st,6) : 0 );
-	
+	bool cancel = ( script_hasdata(st,7) ? script_getnum(st,7) > 0 : skill_get_castcancel(skill_id) );
+	int msg_id = (script_hasdata(st, 8) ? script_getnum(st, 8) : 0);
+
 	if(script_rid2bl(2,bl)){
+		if (msg_id > 0) {
+			if (bl->type != BL_MOB) {
+				ShowError("buildin_unitskilluseid: Msg can only be used for monster.\n");
+				return SCRIPT_CMD_FAILURE;
+			}
+			TBL_MOB* md = map_id2md(bl->id);
+			if (md)
+				mob_chat_display_message(*md, static_cast<uint16>(msg_id));
+		}
 		if (bl->type == BL_NPC) {
 			if (!((TBL_NPC*)bl)->status.hp)
 				status_calc_npc(((TBL_NPC*)bl), SCO_FIRST);
 			else
 				status_calc_npc(((TBL_NPC*)bl), SCO_NONE);
 		}
-		unit_skilluse_id2(bl, target_id, skill_id, skill_lv, (casttime * 1000) + skill_castfix(bl, skill_id, skill_lv), skill_get_castcancel(skill_id));
+		unit_skilluse_id2(bl, target_id, skill_id, skill_lv, (casttime * 1000) + skill_castfix(bl, skill_id, skill_lv), cancel);
 	}
 
 	return SCRIPT_CMD_SUCCESS;
@@ -19327,8 +19340,8 @@ BUILDIN_FUNC(unitskilluseid)
 
 /// Makes the unit cast the skill on the target position.
 ///
-/// unitskillusepos <unit_id>,<skill_id>,<skill_lv>,<target_x>,<target_y>{,<casttime>};
-/// unitskillusepos <unit_id>,"<skill name>",<skill_lv>,<target_x>,<target_y>{,<casttime>};
+/// unitskillusepos <unit_id>,<skill_id>,<skill_lv>,<target_x>,<target_y>{,<casttime>,<cancel>,<Line_ID>};
+/// unitskillusepos <unit_id>,"<skill name>",<skill_lv>,<target_x>,<target_y>{,<casttime>,<cancel>,<Line_ID>};
 BUILDIN_FUNC(unitskillusepos)
 {
 	int skill_x, skill_y, casttime;
@@ -19354,15 +19367,26 @@ BUILDIN_FUNC(unitskillusepos)
 	skill_x  = script_getnum(st,5);
 	skill_y  = script_getnum(st,6);
 	casttime = ( script_hasdata(st,7) ? script_getnum(st,7) : 0 );
+	bool cancel = ( script_hasdata(st,8) ? script_getnum(st,8) > 0 : skill_get_castcancel(skill_id) );
+	int msg_id = (script_hasdata(st, 9) ? script_getnum(st, 9) : 0);
 
 	if(script_rid2bl(2,bl)){
+		if (msg_id > 0) {
+			if (bl->type != BL_MOB) {
+				ShowError("buildin_unitskilluseid: Msg can only be used for monster.\n");
+				return SCRIPT_CMD_FAILURE;
+			}
+			TBL_MOB* md = map_id2md(bl->id);
+			if (md)
+				mob_chat_display_message(*md, static_cast<uint16>(msg_id));
+		}
 		if (bl->type == BL_NPC) {
 			if (!((TBL_NPC*)bl)->status.hp)
 				status_calc_npc(((TBL_NPC*)bl), SCO_FIRST);
 			else
 				status_calc_npc(((TBL_NPC*)bl), SCO_NONE);
 		}
-		unit_skilluse_pos2(bl, skill_x, skill_y, skill_id, skill_lv, (casttime * 1000) + skill_castfix(bl, skill_id, skill_lv), skill_get_castcancel(skill_id));
+		unit_skilluse_pos2(bl, skill_x, skill_y, skill_id, skill_lv, (casttime * 1000) + skill_castfix(bl, skill_id, skill_lv), cancel);
 	}
 
 	return SCRIPT_CMD_SUCCESS;
@@ -25256,6 +25280,33 @@ BUILDIN_FUNC(getenchantgrade){
 	return SCRIPT_CMD_SUCCESS;
 }
 
+/*==========================================
+ * mob_setidleevent( <monster game ID>, "<event label>" )
+ *------------------------------------------*/
+BUILDIN_FUNC(mob_setidleevent){
+	struct block_list* bl;
+
+	if( !script_rid2bl( 2, bl ) ){
+		return SCRIPT_CMD_FAILURE;
+	}
+
+	if( bl->type != BL_MOB ){
+		ShowError( "buildin_mob_setidleevent: the target GID was not a monster.\n" );
+		return SCRIPT_CMD_FAILURE;
+	}
+
+	struct mob_data* md = (struct mob_data*)bl;
+	if (md == nullptr)
+		return SCRIPT_CMD_FAILURE;
+
+	const char* idle_event = script_getstr( st, 3 );
+
+	check_event( st, idle_event );
+	safestrncpy( md->idle_event, idle_event, EVENT_NAME_LENGTH );
+
+	return SCRIPT_CMD_SUCCESS;
+}
+
 #include "../custom/script.inc"
 
 // declarations that were supposed to be exported from npc_chat.cpp
@@ -25709,8 +25760,8 @@ struct script_function buildin_func[] = {
 	BUILDIN_DEF(unitstopwalk,"i?"),
 	BUILDIN_DEF(unittalk,"is?"),
 	BUILDIN_DEF_DEPRECATED(unitemote,"ii","20170811"),
-	BUILDIN_DEF(unitskilluseid,"ivi??"), // originally by Qamera [Celest]
-	BUILDIN_DEF(unitskillusepos,"iviii?"), // [Celest]
+	BUILDIN_DEF(unitskilluseid,"ivi????"), // originally by Qamera [Celest]
+	BUILDIN_DEF(unitskillusepos,"iviii???"), // [Celest]
 // <--- [zBuffer] List of unit control commands
 	BUILDIN_DEF(sleep,"i"),
 	BUILDIN_DEF(sleep2,"i"),
@@ -25950,6 +26001,7 @@ struct script_function buildin_func[] = {
 
 	BUILDIN_DEF(getenchantgrade, ""),
 
+	BUILDIN_DEF(mob_setidleevent, "is"),
 #include "../custom/script_def.inc"
 
 	{NULL,NULL,NULL},

+ 1 - 0
src/map/script.hpp

@@ -480,6 +480,7 @@ enum unitdata_mobtypes {
 	UMOB_ROBE,
 	UMOB_BODY2,
 	UMOB_GROUP_ID,
+	UMOB_IGNORE_CELL_STACK_LIMIT,
 };
 
 enum unitdata_homuntypes {

+ 2 - 0
src/map/script_constants.hpp

@@ -3847,6 +3847,7 @@
 	export_constant(AI_LEGION);
 	export_constant(AI_FAW);
 	export_constant(AI_GUILD);
+	export_constant(AI_WAVEMODE);
 
 	/* battle flags */
 	export_constant(BF_NONE);
@@ -4380,6 +4381,7 @@
 	export_constant(UMOB_ROBE);
 	export_constant(UMOB_BODY2);
 	export_constant(UMOB_GROUP_ID);
+	export_constant(UMOB_IGNORE_CELL_STACK_LIMIT);
 
 	/* unit control - homunculus */
 	export_constant(UHOM_SIZE);

+ 2 - 1
src/map/unit.cpp

@@ -628,7 +628,8 @@ static TIMER_FUNC(unit_walktoxy_timer)
 		ud->to_x = bl->x;
 		ud->to_y = bl->y;
 
-		if(battle_config.official_cell_stack_limit > 0
+		if (!ud->state.ignore_cell_stack_limit
+			&& battle_config.official_cell_stack_limit > 0
 			&& map_count_oncell(bl->m, x, y, BL_CHAR|BL_NPC, 1) > battle_config.official_cell_stack_limit) {
 			//Walked on occupied cell, call unit_walktoxy again
 			if(ud->steptimer != INVALID_TIMER) {

+ 1 - 0
src/map/unit.hpp

@@ -57,6 +57,7 @@ struct unit_data {
 		unsigned walk_script : 1;
 		unsigned blockedmove : 1;
 		unsigned blockedskill : 1;
+		unsigned ignore_cell_stack_limit : 1;
 	} state;
 	char walk_done_event[EVENT_NAME_LENGTH];
 	char title[NAME_LENGTH];