浏览代码

Release of Doram Race!
* Requires client 2015-10-01 and newer.
* All skills are usable from from the base list to all 3 branch types.
-- Some skills still need their official activation chance and durations.
* Adjusted the char-server start point and start item split functions to be more dynamic.
Thanks to Rytech and @NovaRagnarok for their information!

aleos89 9 年之前
父节点
当前提交
daa9e018f4

+ 1 - 0
conf/battle/player.conf

@@ -97,6 +97,7 @@ max_third_trans_parameter: 130
 max_baby_parameter: 80
 max_baby_third_parameter: 117
 max_extended_parameter: 125
+max_summoner_parameter: 120
 
 // Status points bonus for transcendent class
 transcendent_status_points: 52

+ 5 - 1
conf/char_athena.conf

@@ -111,14 +111,18 @@ save_log: yes
 // Format: <map_name>,<x>,<y>{:<map_name>,<x>,<y>...}
 // Max number of start points is MAX_STARTPOINT in char.h (default 5)
 // Location is randomly picked on character creation.
+// NOTE: For Doram, this requires client 20151001 or newer.
 start_point: iz_int,97,90:iz_int01,97,90:iz_int02,97,90:iz_int03,97,90:iz_int04,97,90
 start_point_pre: new_1-1,53,111:new_2-1,53,111:new_3-1,53,111:new_4-1,53,111:new_5-1,53,111
+start_point_doram: lasa_fild01,48,297
 
 // Starting items for new characters
 // Max number of items is MAX_STARTITEM in char.c (default 32)
-// Format: <id>,<amount>,<position>:<id>,<amount>,<position>:...
+// Format: <id>,<amount>,<position>{:<id>,<amount>,<position>...}
 // To auto-equip an item, include the position where it will be equipped; otherwise, use zero.
+// NOTE: For Doram, this requires client 20151001 or newer.
 start_items: 1201,1,2:2301,1,16
+start_items_doram: 1681,1,2:2301,1,16
 
 // Starting zeny for new characters
 start_zeny: 0

+ 1 - 1
conf/help.txt

@@ -102,7 +102,7 @@ jobchange: "Params: <job name|ID>\n" "Changes your job.\n"
 	"     23 Super Novice      24 Gunslinger              25 Ninja                 4045 Super Baby\n"
 	"4046 Taekwon           4047 Star Gladiator     4049 Soul Linker            4050 Gangsi\n"
 	"4051 Death Knight    4052 Dark Collector    4190 Ex. Super Novice  4191 Ex. Super Baby\n"
-	"4211 Kagerou            4212 Oboro             4215 Rebellion\n"
+	"4211 Kagerou            4212 Oboro             4215 Rebellion        4218 Summoner\n"
 	"----- Baby Novice And Baby 1st Class -----\n"
 	"4023 Baby Novice      4024 Baby Swordman    4025 Baby Magician   4026 Baby Archer\n"
 	"4027 Baby Acolyte      4028 Baby Merchant       4029 Baby Thief\n"

+ 1 - 0
conf/msg_conf/map_msg.conf

@@ -719,6 +719,7 @@
 694: Hanbok
 695: Rebellion
 696: Oktoberfest
+697: Summoner
 
 // @vip
 700: Usage: @vip <time> <character name>

+ 2 - 1
conf/msg_conf/map_msg_chn.conf

@@ -672,7 +672,8 @@
 693: 魅影追蹤者 T
 694: 韓服
 695: Rebellion
-
+696: Oktoberfest
+697: Summoner
 
 //------------------------------------
 // More atcommands message

+ 2 - 1
conf/msg_conf/map_msg_frn.conf

@@ -684,7 +684,8 @@
 693: Shadow Chaser T
 694: Hanbok
 695: Rebellion
-
+696: Oktoberfest
+697: Summoner
 
 //------------------------------------
 // More atcommands message

+ 18 - 0
conf/msg_conf/map_msg_grm.conf

@@ -572,5 +572,23 @@
 660: Besiegt von
 661: [^EE0000%s^000000]
 
+681: Rune Knight T
+682: Warlock T
+683: Ranger T
+684: Arch Bishop T
+685: Mechanic T
+686: Guillotine Cross T
+687: Royal Guard T
+688: Sorcerer T
+689: Minstrel T
+690: Wanderer T
+691: Sura T
+692: Genetic T
+693: Shadow Chaser T
+694: Hanbok
+695: Rebellion
+696: Oktoberfest
+697: Summoner
+
 //Custom translations
 import: conf/msg_conf/import/map_msg_grm_conf.txt

+ 1 - 0
conf/msg_conf/map_msg_idn.conf

@@ -718,6 +718,7 @@
 694: Hanbok
 695: Rebellion
 696: Oktoberfest
+697: Summoner
 
 // @vip
 700: Penggunaan: @vip <waktu> <nama pemain>

+ 2 - 1
conf/msg_conf/map_msg_por.conf

@@ -664,7 +664,8 @@
 693: Renegado T
 694: Hanbok
 695: Rebellion
-
+696: Oktoberfest
+697: Summoner
 
 //------------------------------------
 // Mais mensagens de atcommand

+ 3 - 1
conf/msg_conf/map_msg_rus.conf

@@ -683,8 +683,10 @@
 693: Shadow Chaser T
 694: Hanbok
 695: Rebellion
+696: Oktoberfest
+697: Summoner
 
-//695-899 妖 煩藁本排賭凭
+//698-899 妖 煩藁本排賭凭
 
 //------------------------------------
 // 剋釶奛辷� 鞐諛蔟逶� 褌赭辟

+ 2 - 1
conf/msg_conf/map_msg_spn.conf

@@ -671,7 +671,8 @@
 693: Shadow Chaser T
 694: Hanbok
 695: Rebellion
-
+696: Oktoberfest
+697: Summoner
 
 //------------------------------------
 // Más mensajes relacionados con comandos

+ 2 - 1
conf/msg_conf/map_msg_tha.conf

@@ -678,7 +678,8 @@
 693: Shadow Chaser T
 694: Hanbok
 695: Rebellion
-
+696: Oktoberfest
+697: Summoner
 
 //------------------------------------
 // More atcommands message

+ 52 - 6
db/const.txt

@@ -1515,13 +1515,30 @@ EF_MIRESULT_MAKE_FAIL	1018
 EF_ALL_RAY_OF_PROTECTION	1019
 EF_VENOMFOG	1020
 EF_DUSTSTORM	1021
-//1022 - 1039 Unknown
+EF_LEVEL160	1022
+EF_LEVEL160_SUB	1023
+EF_MAPCHAIN	1024
+EF_MAGIC_FLOOR	1025
+EF_ICEMINE	1026
+EF_FLAMECORSS	1027
+EF_ICEMINE_1	1028
+EF_DANCE_BLADE_ATK	1029
+EF_DARKPIERCING	1030
+EF_INVINCIBLEOFF2	1031
+EF_MAXPAIN	1032
+EF_DEATHSUMMON	1033
+EF_MOONSTAR	1034
+EF_STRANGELIGHTS	1035
+EF_SUPER_STAR	1036
+EF_YELLOBODY	1037
+EF_COLORPAPER2	1038
+EF_EVILS_PAW	1039
 EF_GC_DARKCROW	1040
 EF_RK_DRAGONBREATH_WATER	1041
 EF_ALL_FULL_THROTTLE	1042
 EF_SR_FLASHCOMBO	1043
 EF_RK_LUXANIMA	1044
-//1045 Unknown
+EF_CLOUD10	1045
 EF_SO_ELEMENTAL_SHIELD	1046
 EF_AB_OFFERTORIUM	1047
 EF_WL_TELEKINESIS_INTENSE	1048
@@ -1536,15 +1553,44 @@ EF_RA_UNLIMIT	1056
 EF_AB_OFFERTORIUM_RING	1057
 EF_SC_ESCAPE	1058
 EF_WM_FRIGG_SONG	1059
-EF_C_MAKER	1060
-//1061 Unknown
+EF_FLICKER	1060
+EF_C_MAKER	1061
 EF_HAMMER_OF_GOD	1062
-//1063 - 1065 Unknown
+EF_MASS_SPIRAL	1063
+EF_FIRE_RAIN	1064
+EF_WHITEBODY	1065
 EF_BANISHING_BUSTER	1066
 EF_SLUGSHOT	1067
 EF_D_TAIL	1068
-//1069 - 1077 Unknown
+EF_BIND_TRAP1	1069
+EF_BIND_TRAP2	1070
+EF_BIND_TRAP3	1071
+EF_JUMPBODY1	1072
+EF_ANIMATED_EMITTER	1073
+EF_RL_EXPLOSION	1074
+EF_C_MAKER_1	1075
+EF_QD_SHOT	1076
+EF_P_ALTER	1077
 EF_S_STORM	1078
+EF_MUSIC_HAT	1079
+EF_CLOUD_KILL	1080
+EF_ESCAPE	1081
+EF_XENO_SLASHER	1082
+EF_FLOWERSMOKE	1083
+EF_FSTONE	1084
+EF_QSCARABA	1085
+EF_LJOSALFAR	1086
+EF_HAPPINESSSTAR	1087
+EF_POWER_OF_GAIA	1088
+EF_MAPLE_FALLS	1089
+EF_MARKING_USE_CHANGEMONSTER	1090
+EF_MAGICAL_FEATHER	1091
+EF_MERMAID_LONGING	1092
+EF_GIFT_OF_SNOW	1093
+EF_ACH_COMPLETE	1094
+EF_TIME_ACCESSORY	1095
+EF_SPRITEMABLE	1096
+EF_TUNAPARTY	1097
 
 WARPNPC	45
 1_ETC_01	46

+ 2 - 0
db/job_db2.txt

@@ -289,3 +289,5 @@
 4212,5,0,4,0,2,3,0,1,6,0,5,1,2,0,4,6,3,0,1,5,2,0,6,3,4,0,5,0,2,0,1,4,0,5,4,0,3,5,1,0,2,4,1,0,5,6,2,1,0,5
 // Rebellion
 4215,0,5,0,4,0,3,5,4,2,6,0,0,3,4,0,2,5,4,3,6,0,0,3,5,1,4,2,0,0,6,3,0,5,4,1,0,0,5,0,2,6,0,5,3,4,0,0,0,0,1
+// Summoner
+4218,5,0,3,0,5,3,0,2,4,0,2,4,5,0,2,4,5,0,2,4,5,0,6,3,5,0,2,0,6,0,4,5,0,6,0,4,6,0,2,0,5,4,3,0,5,6,3,2,0,5

+ 2 - 0
db/re/item_db.txt

@@ -1012,6 +1012,7 @@
 1677,Blue_Wand,Blue Wand,5,10,,0,50,,1,1,0x00000200,56,2,2,3,100,1,10,{ bonus bStr,5; bonus bInt,5; },{},{}
 1678,Ru_Gold_Wand,Ru Gold Wand,5,0,,0,50,,1,2,0x00000200,56,2,2,3,120,1,10,{ bonus bDex,8; bonus bInt,8; },{},{}
 1680,Crimson_One-Handed_Staff,Crimson One-Handed Staff,5,10,,600,60,,1,2,0x00800015,63,2,2,3,70,1,10,{ .@r = getrefine(); bonus bInt,4; bonus bMatk,70+((BaseLevel/10)*5)+(.@r<=15?pow(.@r,2):225); bonus bUnbreakableWeapon,1; },{},{}
+1681,Short_Foxtail_Staff,Short Foxtail Staff,5,20,,0,30,,1,0,0x80000000,7,2,2,1,1,1,10,{},{},{}
 1682,Shadow_Staff,Shadow Staff,5,0,,600,70:130,,1,2,0x00000200,56,2,2,4,90,1,10,{ .@r = getrefine(); bonus2 bSkillAtk,"WL_HELLINFERNO",(getskilllv("WL_HELLINFERNO") >= 5 ? 100 : 0) + (.@r*10); bonus2 bIgnoreMdefRaceRate,RC_All,5; autobonus "{ bonus2 bVariableCastrate,\"WL_HELLINFERNO\",-30; }",.@r*20,5000,BF_MAGIC,"{ specialeffect2 EF_SPELLBREAKER }"; },{},{}
 //===================================================================
 // Bows
@@ -5996,6 +5997,7 @@
 11598,Bitter_Cacao_Bean,Bitter Cacao Bean,0,10,,0,,,,0,0xFFFFFFFF,63,2,,,,,,{},{},{}
 11599,Superstar_Potion,Superstar Potion,0,10,,10,,,,0,0xFFFFFFFF,63,2,,,,,,{},{},{}
 11600,Shining_Holy_Water,Shining Holy Water,0,10,,15,,,,0,0xFFFFFFFF,63,2,,,,,,{ if(strcharinfo(3)=="prt_q") { bonus_script "{ bonus2 bSubSize,Size_All,10; }",600; sc_end SC_SILENCE; sc_end SC_POISON; sc_end SC_CURSE; heal 1000,0; } },{},{}
+11602,Catnip_Fruit,Catnip Fruit,0,15,,1,,,,,0xFFFFFFFF,63,2,,,,,,{ itemheal rand(10,40),0; },{},{}
 //
 11701,Girl_Bunch_Of_Flower_,Girl's Bouquet,0,20,,50,,,,,0xFFFFFFFF,63,2,,,,,,{ itemheal rand(105,145),0; },{},{}
 11702,Moon_Cookie,Moon Cookie,0,0,,300,,,,,0xFFFFFFFF,63,2,,,,,,{ },{},{}

文件差异内容过多而无法显示
+ 0 - 0
db/re/job_basehpsp_db.txt


+ 2 - 0
db/re/job_db1.txt

@@ -271,3 +271,5 @@
 4212,	26000,75   ,500  ,540  ,400  ,500  ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 , 750 ,2000 ,500
 // Rebellion
 4215,   28000,90   ,650  ,469  ,540  ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,520  ,620  ,570  ,970  ,1070 ,2000 ,2000 ,600
+// Summoner
+4218,	20000,75   ,500  ,700  ,490  ,570  ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,590  ,2000 ,2000 ,2000 ,2000 ,470  ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,590  ,590

文件差异内容过多而无法显示
+ 0 - 0
db/re/job_exp.txt


+ 41 - 0
db/re/skill_cast_db.txt

@@ -1762,6 +1762,47 @@
 //-- ALL_FULL_THROTTLE
 5014,0,500,0,10000:15000:20000:25000:30000,10000,1800000,-1
 
+//===== Summoner ===========================
+//-- SU_BITE
+5019,1000,1000,0,0,0,0,0
+//-- SU_HIDE
+5020,0,1000,0,-1,0,15000,0
+//-- SU_SCRATCH
+5021,0,1000,0,10000,0,3000:2000:1000,0
+//-- SU_STOOP
+5022,0,1000,0,6000,0,15000,0
+//-- SU_LOPE
+5023,500,1000,0,0,0,2000:4000:6000,0
+//-- SU_SV_STEMSPEAR
+5026,2500,1000,0,10000,0,0,0
+//-- SU_CN_POWDERING
+5027,1500,1000,0,3000:4000:5000:6000:7000,0,0,0
+//-- SU_CN_METEOR
+5028,6000,1000,0,500,5000,2000:3000:4000:5000:6000,0
+//-- SU_SV_ROOTTWIST
+5029,0,1000,0,7000:9000:11000:13000:15000,0,3000,0
+//-- SU_SV_ROOTTWIST_ATK
+5030,0,1000,0,0,0,0
+//-- SU_SCAROFTAROU
+5032,500,1000,0,9000,1000,0,0
+//-- SU_PICKYPECK
+5033,2500,1000,0,0,0,0,0
+//-- SU_PICKYPECK_DOUBLE_ATK
+5034,0,1000,0,0,0,0,0
+//-- SU_ARCLOUSEDASH
+5035,2500,1000,0,60000:70000:80000:90000:100000,0,10000,0
+//-- SU_LUNATICCARROTBEAT
+5036,3000,1000,0,1000,0,8000,0
+//-- SU_TUNABELLY
+5038,2000,1000,0,0,0,8000:10000:12000:14000:16000,0
+//-- SU_TUNAPARTY
+5039,0,1000,0,30000,0,20000,0
+//-- SU_BUNCHOFSHRIMP
+5040,0,1000,0,60000:90000:120000:150000:180000,0,10000,0
+//-- SU_FRESHSHRIMP
+5041,0,1000,0,120000,0,7000,0
+//==========================================
+
 //===== Homunculus Skills ==================
 //-- HLIF_HEAL
 8001,0,2000,0,0,0,0,-1

+ 30 - 0
db/re/skill_db.txt

@@ -1328,6 +1328,36 @@
 5013,0,6,4,0,0x3,0,5,1,no,0,0,0,none,0,0x0, LG_KINGS_GRACE,King's Grace
 5014,0,6,4,0,0x1,0,5,1,no,0,0,0,none,0,0x0, ALL_FULL_THROTTLE,Full Throttle
 
+// Summoner
+5018,0,0,0,0,0,0,1,0,no,0,0,0,none,0,0x0,		SU_BASIC_SKILL,New Basic Skill
+5019,2,6,1,-1,0,0,1,1,yes,0,0,0,weapon,0,0x0,	SU_BITE,Bite
+5020,0,6,4,0,0x1,0,1,1,yes,0,0,0,none,0,0x0,	SU_HIDE,Hide
+5021,2,6,1,-1,0x2,1,3,1,yes,0,0,0,weapon,0,0x0,	SU_SCRATCH,Scratch
+5022,0,6,4,0,0x1,0,1,1,yes,0,0,0,none,0,0x0,	SU_STOOP,Stoop
+5023,6:10:14,6,2,0,0x1,0,3,1,yes,0,0,0,none,0,0x0,	SU_LOPE,Lope
+5024,0,0,0,0,0,0,1,0,no,0,0,0,none,0,0x0,		SU_SPRITEMABLE,Spirit Marble
+5025,0,0,0,0,0,0,1,0,no,0,0,0,none,0,0x0,		SU_POWEROFLAND,Power of Land
+5026,9,6,1,2:3:1:4:8,0x0,0,5,1,yes,0,0,0,magic,0,0x0,		SU_SV_STEMSPEAR,Silvervine Stem Spear
+5027,9,6,1,0,0x3,0,5,1,yes,0,0,1,none,0,0x0,		SU_CN_POWDERING,Catnip Powdering
+5028,9,8,2,0,0,1:1:2:2:3,5,1:2:3:4:5,yes,0,0,0,magic,0,0x0,		SU_CN_METEOR,Catnip Meteor
+5029,9,6,1,0,0x1,0,5,1,yes,0,0,1,none,0,0x0,		SU_SV_ROOTTWIST,Silvervine Root Twist
+5030,0,6,1,5,0x30,0,5,1,no,0,0,1,magic,0,0x0,	SU_SV_ROOTTWIST_ATK,Silver Vine Root Twist Attack
+5031,0,0,0,0,0,0,1,0,no,0,0,0,none,0,0x0,		SU_POWEROFLIFE,Power of Life
+5032,9,6,1,-1,0,0,5,1,yes,0,0,0,weapon,0,0x0,	SU_SCAROFTAROU,Scar of Tarou
+5033,9,8,1,-1,0,0,5,-5,yes,0,0,0,weapon,0,0x0,	SU_PICKYPECK,Picky Peck
+5034,0,8,1,-1,0,0,5,-5,yes,0,0,0,weapon,0,0x0,	SU_PICKYPECK_DOUBLE_ATK,Picky Peck Double Attack
+5035,9,6,16,0,0x1,0,5,1,yes,0,0,0,none,0,0x0,		SU_ARCLOUSEDASH,Arclouse Dash
+5036,9,8,1,-1,0x2,1:1:2:2:3,5,1:2:3:4:5,yes,0,0,0,weapon,0,0x0,	SU_LUNATICCARROTBEAT,Lunatic Carrot Beat
+5037,0,0,0,0,0,0,1,0,no,0,0,0,none,0,0x0,		SU_POWEROFSEA,Power of Sea
+5038,9,6,16,0,0x1,0,5,1,yes,0,0,0,none,0,0x0,		SU_TUNABELLY,Tuna Belly
+5039,9,6,16,0,0x1,0,5,1,yes,0,0,0,none,0,0x0,		SU_TUNAPARTY,Tuna Party
+5040,0,6,4,0,0x3,-1,5,1,yes,0,0,0,none,0,0x0,		SU_BUNCHOFSHRIMP,Bunch of Shrimp
+5041,9,6,16,0,0x3,0,5,1,yes,0,0,0,none,0,0x0,		SU_FRESHSHRIMP,Fresh Shrimp
+
+// Unknown Unconfirmed Summoner Skills - Animations Show On These
+//5042,0,0,0,0,0,0,5,0,yes,0,0,0,none,0,0x0,		SU_CN_METEOR_SEC,
+//5043,0,0,0,0,0,0,5,0,yes,0,0,0,none,0,0x0,		SU_LUNATICCARROTBEAT_SEC,
+
 //****
 // Homunculus S
 8001,9,6,4,0,0x1,0,5,1,no,0,0,0,magic,0,0x0,	HLIF_HEAL,Healing Touch

+ 3 - 0
db/re/skill_nocast_db.txt

@@ -91,6 +91,7 @@
 691,8	//CASH_ASSUMPITO
 2284,8	//SC_FATALMENACE
 2300,8	//SC_DIMENSIONDOOR
+5023,8	//SU_LOPE
 
 //----------------------------------------------------------------------------
 // Mixed
@@ -131,6 +132,7 @@
 //----------------------------------------------------------------------------
 421,64	//TK_JUMPKICK
 426,64	//TK_HIGHJUMP
+5023,64	//SU_LOPE
 
 //----------------------------------------------------------------------------
 // Zone 3 - Izlude Battle Arena
@@ -145,6 +147,7 @@
 //----------------------------------------------------------------------------
 426,256 //TK_HIGHJUMP
 290,256	//SA_ABRACADABRA
+5023,256	//SU_LOPE
 
 //----------------------------------------------------------------------------
 // Zone 5 - Sealed Shrine

+ 25 - 0
db/re/skill_require_db.txt

@@ -972,6 +972,31 @@
 5013,0,0,200:180:160:140:120,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0			//LG_KINGS_GRACE
 5014,0,0,1,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0								//ALL_FULL_THROTTLE
 
+// Summoner
+5019,0,0,10,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0									//SU_BITE
+5020,0,0,30,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0									//SU_HIDE
+5021,0,0,20:25:30,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0							//SU_SCRATCH
+5022,0,0,10,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0									//SU_STOOP
+5023,0,0,30:30:30,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0							//SU_LOPE
+5026,0,0,40:40:40:40:40,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0						//SU_SV_STEMSPEAR
+5027,0,0,40:36:32:28:24,0,0,0,99,0,0,none,0,0,11602,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0					//SU_CN_POWDERING
+5028,0,0,20:35:50:65:80,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0						//SU_CN_METEOR
+5029,0,0,10:12:14:16:18,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0						//SU_SV_ROOTTWIST
+5030,0,0,1,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0									//SU_SV_ROOTTWIST_ATK
+5032,0,0,10:14:18:22:26,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0						//SU_SCAROFTAROU
+5033,0,0,10:19:28:37:46,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0						//SU_PICKYPECK
+5034,0,0,1,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0									//SU_PICKYPECK_DOUBLE_ATK
+5035,0,0,12:20:28:36:44,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0						//SU_ARCLOUSEDASH
+5036,0,0,15:25:35:45:55,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0						//SU_LUNATICCARROTBEAT
+5038,0,0,20:30:40:50:60,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0						//SU_TUNABELLY
+5039,0,0,20:30:40:50:60,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0						//SU_TUNAPARTY
+5040,0,0,44:48:52:56:60,0,0,0,99,0,0,none,0,0,567,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0					//SU_BUNCHOFSHRIMP
+5041,0,0,22:24:26:28:30,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0						//SU_FRESHSHRIMP
+
+// Unknown Summoner Skills
+//5042,0,0,1,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0								//
+//5043,0,0,1,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0								//
+
 8001,0,0,13:16:19:22:25,0,0,0,99,0,0,none,0,0,545,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0				//HLIF_HEAL
 8002,0,0,20:25:30:35:40,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0					//HLIF_AVOID
 8004,0,0,100,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0							//HLIF_CHANGE

+ 24 - 0
db/re/skill_tree.txt

@@ -5668,3 +5668,27 @@
 4215,2569,5,2553,1,0,0,0,0,0,0,0,0 //RL_AM_BLAST#Anti-Material Blast#
 4215,2570,5,2554,3,0,0,0,0,0,0,0,0 //RL_SLUGSHOT#Slug Shot#
 4215,2571,5,2569,3,0,0,0,0,0,0,0,0 //RL_HAMMER_OF_GOD#Hammer of God#
+//Summoner
+4218,5018,1,0,0,0,0,0,0,0,0,0,0 //SU_BASIC_SKILL##
+4218,5019,1,5018,1,0,0,0,0,0,0,0,0 //SU_BITE##
+4218,5020,1,5019,1,0,0,0,0,0,0,0,0 //SU_HIDE##
+4218,5021,3,5020,1,0,0,0,0,0,0,0,0 //SU_SCRATCH##
+4218,5022,1,5021,3,0,0,0,0,0,0,0,0 //SU_STOOP##
+4218,5023,3,5022,1,0,0,0,0,0,0,0,0 //SU_LOPE##
+4218,5024,1,5023,3,0,0,0,0,0,0,0,0 //SU_SPRITEMABLE##
+4218,5025,1,5027,3,0,0,0,0,0,0,0,0 //SU_POWEROFLAND##
+4218,5026,5,5024,1,0,0,0,0,0,0,0,0 //SU_SV_STEMSPEAR##
+4218,5027,5,5028,3,0,0,0,0,0,0,0,0 //SU_CN_POWDERING##
+4218,5028,5,5029,3,0,0,0,0,0,0,0,0 //SU_CN_METEOR##
+4218,5029,5,5026,3,0,0,0,0,0,0,0,0 //SU_SV_ROOTTWIST##
+4218,5031,1,5036,3,0,0,0,0,0,0,0,0 //SU_POWEROFLIFE##
+4218,5032,5,5035,3,0,0,0,0,0,0,0,0 //SU_SCAROFTAROU##
+4218,5033,5,5024,1,0,0,0,0,0,0,0,0 //SU_PICKYPECK##
+4218,5035,5,5033,3,0,0,0,0,0,0,0,0 //SU_ARCLOUSEDASH##
+4218,5036,5,5032,3,0,0,0,0,0,0,0,0 //SU_LUNATICCARROTBEAT##
+4218,5037,1,5039,3,0,0,0,0,0,0,0,0 //SU_POWEROFSEA##
+4218,5038,5,5040,3,0,0,0,0,0,0,0,0 //SU_TUNABELLY##
+4218,5039,5,5038,3,0,0,0,0,0,0,0,0 //SU_TUNAPARTY##
+4218,5040,5,5041,3,0,0,0,0,0,0,0,0 //SU_BUNCHOFSHRIMP##
+4218,5041,5,5024,1,0,0,0,0,0,0,0,0 //SU_FRESHSHRIMP##
+4218,681,1,0,0,0,0,0,0,0,0,0,0 //ALL_INCCARRY#Enlarge Weight Limit R#

+ 4 - 0
db/re/skill_unit_db.txt

@@ -177,6 +177,10 @@
 5010,0x91,    ,  0, 1,1000,all,   0x002	//SC_ESCAPE
 5013,0x102,   ,  3, 0,  -1,all,   0x2002	//LG_KINGS_GRACE
 
+5027,0x106,   ,  1:1:2:2:3, 0,  -1,enemy, 0x2010 // SU_CN_POWDERING
+5028,0x86,    ,  1, 0,1000,enemy, 0x10 // SU_CN_METEOR
+5029,0x107,   ,  0, 0,1000,enemy, 0x10 // SU_SV_ROOTTWIST
+
 8020,0xf5,    ,  3, 0,2300:2100:1900:1700:1500,enemy,   0x018	//MH_POISON_MIST
 8033,0x7e,    ,  0, 0,  -1,all,   0x003	//MH_STEINWAND
 8025,0x86,    ,  0, 2:2:3:3:4,1000,enemy, 0x018	//MH_XENO_SLASHER

+ 2 - 1
doc/item_db.txt

@@ -3,7 +3,7 @@
 //===== By: ==================================================
 //= rAthena Dev Team
 //===== Last Updated: ========================================
-//= 20130819
+//= 20160319
 //===== Description: =========================================
 //= Explanation of the item_db.txt file and structure.
 //============================================================
@@ -104,6 +104,7 @@ Job: Equippable jobs. Uses the following bitmask table:
 	Dark Collector (2^28): 0x10000000
 	Kagerou/Oboro  (2^29): 0x20000000
 	Rebellion      (2^30): 0x40000000
+	Summoner       (2^31): 0x80000000
 
 	Novice + Swordman + Magician + Archer = 0x0000000F, why?
 	Because: 10 = A, 11 = B, 12 = C, 13 = D, 14 = E, and 15 = F

+ 73 - 40
src/char/char.c

@@ -1419,6 +1419,8 @@ int char_make_new_char_sql(struct char_session_data* sd, char* name_, int str, i
 #endif
 	char name[NAME_LENGTH];
 	char esc_name[NAME_LENGTH*2+1];
+	struct point tmp_start_point[MAX_STARTPOINT];
+	struct startitem tmp_start_items[MAX_STARTITEM];
 	uint32 char_id;
 	int flag, k, start_point_idx = rand() % charserv_config.start_point_count;
 
@@ -1426,6 +1428,11 @@ int char_make_new_char_sql(struct char_session_data* sd, char* name_, int str, i
 	normalize_name(name,TRIM_CHARS);
 	Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH));
 
+	memset(tmp_start_point, 0, MAX_STARTPOINT * sizeof(struct point));
+	memset(tmp_start_items, 0, MAX_STARTITEM * sizeof(struct startitem));
+	memcpy(tmp_start_point, charserv_config.start_point, MAX_STARTPOINT * sizeof(struct point));
+	memcpy(tmp_start_items, charserv_config.start_items, MAX_STARTITEM * sizeof(struct startitem));
+
 	flag = char_check_char_name(name,esc_name);
 	if( flag < 0 )
 		return flag;
@@ -1480,8 +1487,17 @@ int char_make_new_char_sql(struct char_session_data* sd, char* name_, int str, i
 	}
 
 #if PACKETVER >= 20151001
-	if (start_job != JOB_NOVICE)
+	if (start_job != JOB_NOVICE && start_job != JOB_SUMMONER)
 		return -2; // Invalid job
+
+	// Check for Doram based information.
+	if (start_job == JOB_SUMMONER) { // Check for just this job for now.
+		memset(tmp_start_point, 0, MAX_STARTPOINT * sizeof(struct point));
+		memset(tmp_start_items, 0, MAX_STARTITEM * sizeof(struct startitem));
+		memcpy(tmp_start_point, charserv_config.start_point_doram, MAX_STARTPOINT * sizeof(struct point));
+		memcpy(tmp_start_items, charserv_config.start_items_doram, MAX_STARTITEM * sizeof(struct startitem));
+		start_point_idx = rand() % charserv_config.start_point_count_doram;
+	}
 #endif
 
 	//Insert the new char entry to the database
@@ -1491,21 +1507,21 @@ int char_make_new_char_sql(struct char_session_data* sd, char* name_, int str, i
 		"'%d', '%d', '%s', '%d', '%d',  '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%s', '%d', '%d', '%s', '%d', '%d', '%c')",
 		schema_config.char_db, sd->account_id , slot, esc_name, start_job, charserv_config.start_zeny, 48, str, agi, vit, int_, dex, luk,
 		(40 * (100 + vit)/100) , (40 * (100 + vit)/100 ),  (11 * (100 + int_)/100), (11 * (100 + int_)/100), hair_style, hair_color,
-		mapindex_id2name(charserv_config.start_point[start_point_idx].map), charserv_config.start_point[start_point_idx].x, charserv_config.start_point[start_point_idx].y, mapindex_id2name(charserv_config.start_point[start_point_idx].map), charserv_config.start_point[start_point_idx].x, charserv_config.start_point[start_point_idx].y, sex) )
+		mapindex_id2name(tmp_start_point[start_point_idx].map), tmp_start_point[start_point_idx].x, tmp_start_point[start_point_idx].y, mapindex_id2name(tmp_start_point[start_point_idx].map), tmp_start_point[start_point_idx].x, tmp_start_point[start_point_idx].y, sex) )
 #elif PACKETVER >= 20120307
 	if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`account_id`, `char_num`, `name`, `zeny`, `status_point`, `str`, `agi`, `vit`, `int`, `dex`, `luk`, `max_hp`, `hp`,"
 		"`max_sp`, `sp`, `hair`, `hair_color`, `last_map`, `last_x`, `last_y`, `save_map`, `save_x`, `save_y`) VALUES ("
 		"'%d', '%d', '%s', '%d',  '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%s', '%d', '%d', '%s', '%d', '%d')",
 		schema_config.char_db, sd->account_id , slot, esc_name, charserv_config.start_zeny, 48, str, agi, vit, int_, dex, luk,
 		(40 * (100 + vit)/100) , (40 * (100 + vit)/100 ),  (11 * (100 + int_)/100), (11 * (100 + int_)/100), hair_style, hair_color,
-		mapindex_id2name(charserv_config.start_point[start_point_idx].map), charserv_config.start_point[start_point_idx].x, charserv_config.start_point[start_point_idx].y, mapindex_id2name(charserv_config.start_point[start_point_idx].map), charserv_config.start_point[start_point_idx].x, charserv_config.start_point[start_point_idx].y) )
+		mapindex_id2name(tmp_start_point[start_point_idx].map), tmp_start_point[start_point_idx].x, tmp_start_point[start_point_idx].y, mapindex_id2name(tmp_start_point[start_point_idx].map), tmp_start_point[start_point_idx].x, tmp_start_point[start_point_idx].y) )
 #else
 	if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`account_id`, `char_num`, `name`, `zeny`, `str`, `agi`, `vit`, `int`, `dex`, `luk`, `max_hp`, `hp`,"
 		"`max_sp`, `sp`, `hair`, `hair_color`, `last_map`, `last_x`, `last_y`, `save_map`, `save_x`, `save_y`) VALUES ("
 		"'%d', '%d', '%s', '%d',  '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%s', '%d', '%d', '%s', '%d', '%d')",
 		schema_config.char_db, sd->account_id , slot, esc_name, charserv_config.start_zeny, str, agi, vit, int_, dex, luk,
 		(40 * (100 + vit)/100) , (40 * (100 + vit)/100 ),  (11 * (100 + int_)/100), (11 * (100 + int_)/100), hair_style, hair_color,
-		mapindex_id2name(charserv_config.start_point[start_point_idx].map), charserv_config.start_point[start_point_idx].x, charserv_config.start_point[start_point_idx].y, mapindex_id2name(charserv_config.start_point[start_point_idx].map), charserv_config.start_point[start_point_idx].x, charserv_config.start_point[start_point_idx].y) )
+		mapindex_id2name(tmp_start_point[start_point_idx].map), tmp_start_point[start_point_idx].x, tmp_start_point[start_point_idx].y, mapindex_id2name(tmp_start_point[start_point_idx].map), tmp_start_point[start_point_idx].x, tmp_start_point[start_point_idx].y) )
 #endif
 	{
 		Sql_ShowDebug(sql_handle);
@@ -1515,8 +1531,8 @@ int char_make_new_char_sql(struct char_session_data* sd, char* name_, int str, i
 	//Retrieve the newly auto-generated char id
 	char_id = (int)Sql_LastInsertId(sql_handle);
 	//Give the char the default items
-	for (k = 0; k <= MAX_STARTITEM && charserv_config.start_items[k].nameid != 0; k ++) {
-		if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`char_id`,`nameid`, `amount`, `equip`, `identify`) VALUES ('%d', '%hu', '%hu', '%hu', '%d')", schema_config.inventory_db, char_id, charserv_config.start_items[k].nameid, charserv_config.start_items[k].amount, charserv_config.start_items[k].pos, 1) )
+	for (k = 0; k <= MAX_STARTITEM && tmp_start_items[k].nameid != 0; k ++) {
+		if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`char_id`,`nameid`, `amount`, `equip`, `identify`) VALUES ('%d', '%hu', '%hu', '%hu', '%d')", schema_config.inventory_db, char_id, tmp_start_items[k].nameid, tmp_start_items[k].amount, tmp_start_items[k].pos, 1) )
 			Sql_ShowDebug(sql_handle);
 	}
 
@@ -2661,6 +2677,13 @@ void char_set_defaults(){
 	charserv_config.start_point[0].y = MAP_DEFAULT_Y;
 	charserv_config.start_point_count = 1;
 
+#if PACKETVER >= 20151001
+	charserv_config.start_point_doram[0].map = mapindex_name2id(MAP_DEFAULT_NAME);
+	charserv_config.start_point_doram[0].x = MAP_DEFAULT_X;
+	charserv_config.start_point_doram[0].y = MAP_DEFAULT_Y;
+	charserv_config.start_point_count_doram = 1;
+#endif
+
 	charserv_config.start_items[0].nameid = 1201;
 	charserv_config.start_items[0].amount = 1;
 	charserv_config.start_items[0].pos = 2;
@@ -2668,6 +2691,15 @@ void char_set_defaults(){
 	charserv_config.start_items[1].amount = 1;
 	charserv_config.start_items[1].pos = 16;
 
+#if PACKETVER >= 20150101
+	charserv_config.start_items_doram[0].nameid = 1681;
+	charserv_config.start_items_doram[0].amount = 1;
+	charserv_config.start_items_doram[0].pos = 2;
+	charserv_config.start_items_doram[1].nameid = 2301;
+	charserv_config.start_items_doram[1].amount = 1;
+	charserv_config.start_items_doram[1].pos = 16;
+#endif
+
 	charserv_config.console = 0;
 	charserv_config.max_connect_user = -1;
 	charserv_config.gm_allow_group = -1;
@@ -2682,48 +2714,43 @@ void char_set_defaults(){
 
 /**
  * Split start_point configuration values.
+ * @param w1_value: Value from w1
  * @param w2_value: Value from w2
+ * @param start: Start point reference
+ * @param count: Start point count reference
  */
-static void char_config_split_startpoint(char *w2_value)
+static void char_config_split_startpoint(char *w1_value, char *w2_value, struct point start_point[MAX_STARTPOINT], short *count)
 {
-	char *lineitem, **fields, config_name[20];
+	char *lineitem, **fields;
 	int i = 0, fields_length = 3 + 1;
 
-	memset(config_name, 0, sizeof(config_name));
-
-#ifdef RENEWAL
-	strcat(config_name, "start_point");
-#else
-	strcat(config_name, "start_point_pre");
-#endif
-
-	charserv_config.start_point_count = 0; // Reset to begin reading
+	(*count) = 0; // Reset to begin reading
 
 	fields = (char **)aMalloc(fields_length * sizeof(char *));
 	if (fields == NULL)
 		return; // Failed to allocate memory.
 	lineitem = strtok(w2_value, ":");
 
-	while (lineitem != NULL && charserv_config.start_point_count < MAX_STARTPOINT) {
+	while (lineitem != NULL && (*count) < MAX_STARTPOINT) {
 		int n = sv_split(lineitem, strlen(lineitem), 0, ',', fields, fields_length, SV_NOESCAPE_NOTERMINATE);
 
 		if (n + 1 < fields_length) {
-			ShowDebug("%s: not enough arguments for %s! Skipping...\n", config_name, lineitem);
+			ShowDebug("%s: not enough arguments for %s! Skipping...\n", w1_value, lineitem);
 			lineitem = strtok(NULL, ":"); //next lineitem
 			continue;
 		}
 
-		charserv_config.start_point[i].map = mapindex_name2id(fields[1]);
-		if (!charserv_config.start_point[i].map) {
-			ShowError("Start point %s not found in map-index cache. Setting to default location.\n", charserv_config.start_point[i].map);
-			charserv_config.start_point[i].map = mapindex_name2id(MAP_DEFAULT_NAME);
-			charserv_config.start_point[i].x = MAP_DEFAULT_X;
-			charserv_config.start_point[i].y = MAP_DEFAULT_Y;
+		start_point[i].map = mapindex_name2id(fields[1]);
+		if (!start_point[i].map) {
+			ShowError("Start point %s not found in map-index cache. Setting to default location.\n", start_point[i].map);
+			start_point[i].map = mapindex_name2id(MAP_DEFAULT_NAME);
+			start_point[i].x = MAP_DEFAULT_X;
+			start_point[i].y = MAP_DEFAULT_Y;
 		} else {
-			charserv_config.start_point[i].x = max(0, atoi(fields[2]));
-			charserv_config.start_point[i].y = max(0, atoi(fields[3]));
+			start_point[i].x = max(0, atoi(fields[2]));
+			start_point[i].y = max(0, atoi(fields[3]));
 		}
-		charserv_config.start_point_count++;
+		(*count)++;
 
 		lineitem = strtok(NULL, ":"); //next lineitem
 		i++;
@@ -2733,17 +2760,15 @@ static void char_config_split_startpoint(char *w2_value)
 
 /**
  * Split start_items configuration values.
+ * @param w1_value: Value from w1
  * @param w2_value: Value from w2
+ * @param start: Start item reference
  */
-static void char_config_split_startitem(char *w2_value)
+static void char_config_split_startitem(char *w1_value, char *w2_value, struct startitem start_items[MAX_STARTITEM])
 {
-	char *lineitem, **fields, config_name[20];
+	char *lineitem, **fields;
 	int i = 0, fields_length = 3 + 1;
 
-	memset(config_name, 0, sizeof(config_name));
-
-	strcat(config_name, "start_items");
-
 	fields = (char **)aMalloc(fields_length * sizeof(char *));
 	if (fields == NULL)
 		return; // Failed to allocate memory.
@@ -2753,15 +2778,15 @@ static void char_config_split_startitem(char *w2_value)
 		int n = sv_split(lineitem, strlen(lineitem), 0, ',', fields, fields_length, SV_NOESCAPE_NOTERMINATE);
 
 		if (n + 1 < fields_length) {
-			ShowDebug("%s: not enough arguments for %s! Skipping...\n", config_name, lineitem);
+			ShowDebug("%s: not enough arguments for %s! Skipping...\n", w1_value, lineitem);
 			lineitem = strtok(NULL, ":"); //next lineitem
 			continue;
 		}
 
 		// TODO: Item ID verification
-		charserv_config.start_items[i].nameid = max(0, atoi(fields[1]));
-		charserv_config.start_items[i].amount = max(0, atoi(fields[2]));
-		charserv_config.start_items[i].pos = max(0, atoi(fields[3]));
+		start_items[i].nameid = max(0, atoi(fields[1]));
+		start_items[i].amount = max(0, atoi(fields[2]));
+		start_items[i].pos = max(0, atoi(fields[3]));
 
 		lineitem = strtok(NULL, ":"); //next lineitem
 		i++;
@@ -2865,13 +2890,21 @@ bool char_config_read(const char* cfgName, bool normal){
 #else
 		} else if (strcmpi(w1, "start_point_pre") == 0) {
 #endif
-			char_config_split_startpoint(w2);
+			char_config_split_startpoint(w1, w2, charserv_config.start_point, &charserv_config.start_point_count);
+#if PACKETVER >= 20151001
+		} else if (strcmpi(w1, "start_point_doram") == 0) {
+			char_config_split_startpoint(w1, w2, charserv_config.start_point_doram, &charserv_config.start_point_count_doram);
+#endif
 		} else if (strcmpi(w1, "start_zeny") == 0) {
 			charserv_config.start_zeny = atoi(w2);
 			if (charserv_config.start_zeny < 0)
 				charserv_config.start_zeny = 0;
 		} else if (strcmpi(w1, "start_items") == 0) {
-			char_config_split_startitem(w2);
+			char_config_split_startitem(w1, w2, charserv_config.start_items);
+#if PACKETVER >= 20151001
+		} else if (strcmpi(w1, "start_items_doram") == 0) {
+			char_config_split_startitem(w1, w2, charserv_config.start_items_doram);
+#endif
 		} else if(strcmpi(w1,"log_char")==0) {		//log char or not [devil]
 			charserv_config.log_char = atoi(w2);
 		} else if (strcmpi(w1, "unknown_char_name") == 0) {

+ 3 - 3
src/char/char.h

@@ -145,9 +145,9 @@ struct CharServ_Config {
 	int log_inter;	// loggin inter or not [devil]
 	int char_check_db;	///cheking sql-table at begining ?
 
-	struct point start_point[MAX_STARTPOINT]; // Initial position the player will spawn on the server
-	short start_point_count; // Number of positions read
-	struct startitem start_items[MAX_STARTITEM]; // Initial items the player with spawn with on the server
+	struct point start_point[MAX_STARTPOINT], start_point_doram[MAX_STARTPOINT]; // Initial position the player will spawn on the server
+	short start_point_count, start_point_count_doram; // Number of positions read
+	struct startitem start_items[MAX_STARTITEM], start_items_doram[MAX_STARTITEM]; // Initial items the player with spawn with on the server
 	int console;
 	int max_connect_user;
 	int gm_allow_group;

+ 2 - 0
src/common/mmo.h

@@ -792,6 +792,8 @@ enum e_job {
 
 	JOB_REBELLION = 4215,
 
+	JOB_SUMMONER = 4218,
+
 	JOB_MAX,
 };
 

+ 58 - 4
src/map/battle.c

@@ -1294,6 +1294,9 @@ int64 battle_calc_damage(struct block_list *src,struct block_list *bl,struct Dam
 		if (sc->data[SC_WATER_BARRIER])
 			damage = damage * 80 / 100; // 20% reduction to all type attacks
 
+		if (sc->data[SC_SU_STOOP])
+			damage -= damage * 90 / 100;
+
 		// Compressed code, fixed by map.h [Epoque]
 		if (src->type == BL_MOB) {
 			int i;
@@ -1385,10 +1388,20 @@ int64 battle_calc_damage(struct block_list *src,struct block_list *bl,struct Dam
 				status_change_end(bl, SC_KYRIE, INVALID_TIMER);
 		}
 
+		if ((sce = sc->data[SC_TUNAPARTY]) && damage > 0) {
+			clif_specialeffect(bl, 336, AREA);
+			sce->val2 -= (int)cap_value(damage, INT_MIN, INT_MAX);
+			if (sce->val2 >= 0)
+				damage = 0;
+			else
+			  	damage = -sce->val2;
+			if (/*(--sce->val3) <= 0 ||*/ (sce->val2 <= 0))
+				status_change_end(bl, SC_TUNAPARTY, INVALID_TIMER);
+		}
+
 		if( sc->data[SC_MEIKYOUSISUI] && rnd()%100 < 40 ) // custom value
 			damage = 0;
 
-
 		if (!damage)
 			return 0;
 
@@ -4232,6 +4245,24 @@ static int battle_calc_attack_skill_ratio(struct Damage wd, struct block_list *s
 		case RL_AM_BLAST:
 			skillratio += -100 + 300 * skill_lv + status_get_dex(src) / 5; //(custom)
 			break;
+		case SU_BITE:
+			skillratio += 100;
+			break;
+		case SU_SCRATCH:
+			skillratio += -50 + 50 * skill_lv;
+			break;
+		case SU_SCAROFTAROU:
+			skillratio += -100 + 100 * skill_lv;
+			break;
+		case SU_PICKYPECK:
+		case SU_PICKYPECK_DOUBLE_ATK:
+			skillratio += 100 + 100 * skill_lv;
+			if (status_get_max_hp(target) / 100 <= 50)
+				skillratio *= 2;
+			break;
+		case SU_LUNATICCARROTBEAT:
+			skillratio += 100 + 100 * skill_lv;
+			break;
 	}
 	return skillratio;
 }
@@ -4443,15 +4474,28 @@ struct Damage battle_attack_sc_bonus(struct Damage wd, struct block_list *src, s
 			}
 		}
 
-		if((wd.flag&(BF_LONG|BF_MAGIC)) == BF_LONG) { // Monster Transformation bonus
-			if (sc->data[SC_MTF_RANGEATK]) {
+		if((wd.flag&(BF_LONG|BF_MAGIC)) == BF_LONG) {
+			if (sc->data[SC_MTF_RANGEATK]) { // Monster Transformation bonus
 				ATK_ADDRATE(wd.damage, wd.damage2, sc->data[SC_MTF_RANGEATK]->val1);
 				RE_ALLATK_ADDRATE(wd, sc->data[SC_MTF_RANGEATK]->val1);
 			}
-			if (sc->data[SC_MTF_RANGEATK2]) {
+			if (sc->data[SC_MTF_RANGEATK2]) { // Monster Transformation bonus
 				ATK_ADDRATE(wd.damage, wd.damage2, sc->data[SC_MTF_RANGEATK2]->val1);
 				RE_ALLATK_ADDRATE(wd, sc->data[SC_MTF_RANGEATK2]->val1);
 			}
+			if (sc->data[SC_ARCLOUSEDASH] && sc->data[SC_ARCLOUSEDASH]->val4) {
+				ATK_ADDRATE(wd.damage, wd.damage2, sc->data[SC_ARCLOUSEDASH]->val4);
+				RE_ALLATK_ADDRATE(wd, sc->data[SC_ARCLOUSEDASH]->val4);
+			}
+		}
+	}
+
+	if ((wd.flag&(BF_LONG|BF_MAGIC)) == BF_LONG) {
+		if (sd && pc_checkskill(sd, SU_POWEROFLIFE) > 0) {
+			if (pc_checkskill(sd, SU_SCAROFTAROU) == 5 && pc_checkskill(sd, SU_PICKYPECK) == 5 && pc_checkskill(sd, SU_ARCLOUSEDASH) == 5 && pc_checkskill(sd, SU_LUNATICCARROTBEAT) == 5) {
+				ATK_ADDRATE(wd.damage, wd.damage2, 20);
+				RE_ALLATK_ADDRATE(wd, 20);
+			}
 		}
 	}
 
@@ -5646,6 +5690,9 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list
 					ad.damage >>= 1;
 #endif
 				break;
+			case SU_SV_ROOTTWIST_ATK:
+				ad.damage = 100;
+				break;
 			default: {
 				if (sstatus->matk_max > sstatus->matk_min) {
 					MATK_ADD(sstatus->matk_min+rnd()%(sstatus->matk_max-sstatus->matk_min));
@@ -6024,6 +6071,12 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list
 					case MH_POISON_MIST:
 						skillratio += -100 + 40 * skill_lv * status_get_lv(src) / 100;
 						break;
+					case SU_SV_STEMSPEAR:
+						skillratio += 600;
+						break;
+					case SU_CN_METEOR:
+						skillratio += 100 + 100 * skill_lv;
+						break;
 				}
 
 				MATK_RATE(skillratio);
@@ -8090,6 +8143,7 @@ static const struct _battle_data {
 	{ "max_trans_parameter",				&battle_config.max_trans_parameter,				99,		10,		SHRT_MAX,		},
 	{ "max_third_trans_parameter",			&battle_config.max_third_trans_parameter,		135,	10,		SHRT_MAX,		},
 	{ "max_extended_parameter",				&battle_config.max_extended_parameter,			125,	10,		SHRT_MAX,		},
+	{ "max_summoner_parameter",				&battle_config.max_summoner_parameter,			120,	10,		SHRT_MAX,		},
 	{ "skill_amotion_leniency",             &battle_config.skill_amotion_leniency,          0,      0,      300             },
 	{ "mvp_tomb_enabled",                   &battle_config.mvp_tomb_enabled,                1,      0,      1               },
 	{ "feature.atcommand_suggestions",      &battle_config.atcommand_suggestions_enabled,   0,      0,      1               },

+ 1 - 0
src/map/battle.h

@@ -506,6 +506,7 @@ extern struct Battle_Config
 	int max_trans_parameter;
 	int max_third_trans_parameter;
 	int max_extended_parameter;
+	int max_summoner_parameter;
 	int max_third_aspd;
 	int vcast_stat_scale;
 

+ 10 - 9
src/map/clif.c

@@ -10550,7 +10550,7 @@ void clif_parse_QuitGame(int fd, struct map_session_data *sd)
 {
 	/*	Rovert's prevent logout option fixed [Valaris]	*/
 	//int type = RFIFOW(fd,packet_db[sd->packet_ver][RFIFOW(fd,0)].pos[0]);
-	if( !sd->sc.data[SC_CLOAKING] && !sd->sc.data[SC_HIDING] && !sd->sc.data[SC_CHASEWALK] && !sd->sc.data[SC_CLOAKINGEXCEED] &&
+	if( !sd->sc.data[SC_CLOAKING] && !sd->sc.data[SC_HIDING] && !sd->sc.data[SC_CHASEWALK] && !sd->sc.data[SC_CLOAKINGEXCEED] && !sd->sc.data[SC_SUHIDE] &&
 		(!battle_config.prevent_logout || DIFF_TICK(gettick(), sd->canlog_tick) > battle_config.prevent_logout) )
 	{
 		set_eof(fd);
@@ -10752,7 +10752,7 @@ void clif_parse_Emotion(int fd, struct map_session_data *sd)
 {
 	int emoticon = RFIFOB(fd,packet_db[sd->packet_ver][RFIFOW(fd,0)].pos[0]);
 
-	if (battle_config.basic_skill_check == 0 || pc_checkskill(sd, NV_BASIC) >= 2) {
+	if (battle_config.basic_skill_check == 0 || pc_checkskill(sd, NV_BASIC) >= 2 || pc_checkskill(sd, SU_BASIC_SKILL) >= 1) {
 		if (emoticon == E_MUTE) {// prevent use of the mute emote [Valaris]
 			clif_skill_fail(sd, 1, USESKILL_FAIL_LEVEL, 1);
 			return;
@@ -10813,7 +10813,8 @@ void clif_parse_ActionRequest_sub(struct map_session_data *sd, int action_type,
 		(sd->sc.data[SC_TRICKDEAD] ||
 		(sd->sc.data[SC_AUTOCOUNTER] && action_type != 0x07) ||
 		 sd->sc.data[SC_BLADESTOP] ||
-		 sd->sc.data[SC__MANHOLE] ))
+		 sd->sc.data[SC__MANHOLE] ||
+		 sd->sc.data[SC_SUHIDE] ))
 		return;
 
 	if(action_type != 0x00 && action_type != 0x07)
@@ -10847,7 +10848,7 @@ void clif_parse_ActionRequest_sub(struct map_session_data *sd, int action_type,
 		unit_attack(&sd->bl, target_id, action_type != 0);
 		break;
 	case 0x02: // sitdown
-		if (battle_config.basic_skill_check && pc_checkskill(sd, NV_BASIC) < 3) {
+		if (battle_config.basic_skill_check && pc_checkskill(sd, NV_BASIC) < 3 && pc_checkskill(sd, SU_BASIC_SKILL) < 1) {
 			clif_skill_fail(sd, 1, USESKILL_FAIL_LEVEL, 2);
 			break;
 		}
@@ -10930,7 +10931,7 @@ void clif_parse_Restart(int fd, struct map_session_data *sd)
 		break;
 	case 0x01:
 		/*	Rovert's Prevent logout option - Fixed [Valaris]	*/
-		if( !sd->sc.data[SC_CLOAKING] && !sd->sc.data[SC_HIDING] && !sd->sc.data[SC_CHASEWALK] && !sd->sc.data[SC_CLOAKINGEXCEED] &&
+		if( !sd->sc.data[SC_CLOAKING] && !sd->sc.data[SC_HIDING] && !sd->sc.data[SC_CHASEWALK] && !sd->sc.data[SC_CLOAKINGEXCEED] && !sd->sc.data[SC_SUHIDE] &&
 			(!battle_config.prevent_logout || DIFF_TICK(gettick(), sd->canlog_tick) > battle_config.prevent_logout) )
 		{	//Send to char-server for character selection.
 			pc_damage_log_clear(sd,0);
@@ -11418,7 +11419,7 @@ void clif_parse_CreateChatRoom(int fd, struct map_session_data* sd)
 
 	if (sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOROOM)
 		return;
-	if(battle_config.basic_skill_check && pc_checkskill(sd,NV_BASIC) < 4) {
+	if(battle_config.basic_skill_check && pc_checkskill(sd,NV_BASIC) < 4 && pc_checkskill(sd, SU_BASIC_SKILL) < 1) {
 		clif_skill_fail(sd,1,USESKILL_FAIL_LEVEL,3);
 		return;
 	}
@@ -11539,7 +11540,7 @@ void clif_parse_TradeRequest(int fd,struct map_session_data *sd)
 		return;
 	}
 
-	if( battle_config.basic_skill_check && pc_checkskill(sd,NV_BASIC) < 1) {
+	if( battle_config.basic_skill_check && pc_checkskill(sd,NV_BASIC) < 1 && pc_checkskill(sd, SU_BASIC_SKILL) < 1) {
 		clif_skill_fail(sd,1,USESKILL_FAIL_LEVEL,0);
 		return;
 	}
@@ -12598,7 +12599,7 @@ void clif_parse_CreateParty(int fd, struct map_session_data *sd){
 		clif_displaymessage(fd, msg_txt(sd,227));
 		return;
 	}
-	if( battle_config.basic_skill_check && pc_checkskill(sd,NV_BASIC) < 7 ) {
+	if( battle_config.basic_skill_check && pc_checkskill(sd,NV_BASIC) < 7 && pc_checkskill(sd, SU_BASIC_SKILL) < 1 ) {
 		clif_skill_fail(sd,1,USESKILL_FAIL_LEVEL,4);
 		return;
 	}
@@ -12618,7 +12619,7 @@ void clif_parse_CreateParty2(int fd, struct map_session_data *sd){
 		clif_displaymessage(fd, msg_txt(sd,227));
 		return;
 	}
-	if( battle_config.basic_skill_check && pc_checkskill(sd,NV_BASIC) < 7 ) {
+	if( battle_config.basic_skill_check && pc_checkskill(sd,NV_BASIC) < 7 && pc_checkskill(sd, SU_BASIC_SKILL) < 1 ) {
 		clif_skill_fail(sd,1,USESKILL_FAIL_LEVEL,4);
 		return;
 	}

+ 2 - 0
src/map/itemdb.c

@@ -352,6 +352,8 @@ static void itemdb_jobid2mapid(unsigned int *bclass, unsigned int jobmask)
 		bclass[1] |= 1<<MAPID_NINJA;
 	if (jobmask & 1<<30) //Rebellion
 		bclass[1] |= 1<<MAPID_GUNSLINGER;
+	if (jobmask & 1<<31) //Summoner
+		bclass[0] |= 1<<MAPID_SUMMONER;
 }
 
 /**

+ 2 - 0
src/map/itemdb.h

@@ -43,6 +43,7 @@ enum item_itemid
 	ITEMID_WHITE_POTION					= 504,
 	ITEMID_BLUE_POTION					= 505,
 	ITEMID_APPLE						= 512,
+	ITEMID_CARROT						= 515,
 	ITEMID_HOLY_WATER					= 523,
 	ITEMID_PUMPKIN						= 535,
 	ITEMID_RED_SLIM_POTION				= 545,
@@ -91,6 +92,7 @@ enum item_itemid
 	ITEMID_SKULL_						= 7420,
 	ITEMID_TOKEN_OF_SIEGFRIED			= 7621,
 	ITEMID_TRAP_ALLOY					= 7940,
+	ITEMID_CATNIP_FRUIT					= 11602,
 	ITEMID_MERCENARY_RED_POTION			= 12184,
 	ITEMID_MERCENARY_BLUE_POTION		= 12185,
 	ITEMID_BATTLE_MANUAL				= 12208,

+ 2 - 0
src/map/map.c

@@ -393,6 +393,7 @@ int map_moveblock(struct block_list *bl, int x1, int y1, unsigned int tick)
 //		status_change_end(bl, SC_BLADESTOP, INVALID_TIMER); //Won't stop when you are knocked away, go figure...
 		status_change_end(bl, SC_TATAMIGAESHI, INVALID_TIMER);
 		status_change_end(bl, SC_MAGICROD, INVALID_TIMER);
+		status_change_end(bl, SC_SU_STOOP, INVALID_TIMER);
 		if (sc->data[SC_PROPERTYWALK] &&
 			sc->data[SC_PROPERTYWALK]->val3 >= skill_get_maxcount(sc->data[SC_PROPERTYWALK]->val1,sc->data[SC_PROPERTYWALK]->val2) )
 			status_change_end(bl,SC_PROPERTYWALK,INVALID_TIMER);
@@ -2013,6 +2014,7 @@ int map_quit(struct map_session_data *sd) {
 		status_change_end(&sd->bl, SC_READYCOUNTER, INVALID_TIMER);
 		status_change_end(&sd->bl, SC_CBC, INVALID_TIMER);
 		status_change_end(&sd->bl, SC_EQC, INVALID_TIMER);
+		status_change_end(&sd->bl, SC_SPRITEMABLE, INVALID_TIMER);
 		// Remove visuals effect from headgear
 		status_change_end(&sd->bl, SC_MOONSTAR, INVALID_TIMER); 
 		status_change_end(&sd->bl, SC_SUPER_STAR, INVALID_TIMER); 

+ 1 - 0
src/map/map.h

@@ -146,6 +146,7 @@ enum e_mapid {
 	MAPID_HANBOK,
 	MAPID_GANGSI,
 	MAPID_OKTOBERFEST,
+	MAPID_SUMMONER,
 //2-1 Jobs
 	MAPID_SUPER_NOVICE = JOBL_2_1|0x0,
 	MAPID_KNIGHT,

+ 23 - 3
src/map/pc.c

@@ -4722,7 +4722,8 @@ bool pc_isUseitem(struct map_session_data *sd,int n)
 		sd->sc.data[SC__MANHOLE] ||
 		sd->sc.data[SC_KAGEHUMI] ||
 		(sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOITEM) ||
-		sd->sc.data[SC_HEAT_BARREL_AFTER]))
+		sd->sc.data[SC_HEAT_BARREL_AFTER] ||
+		sd->sc.data[SC_SUHIDE]))
 		return false;
 	
 	if (!pc_isItemClass(sd,item))
@@ -5738,6 +5739,8 @@ int pc_jobid2mapid(unsigned short b_class)
 		case JOB_BABY_SURA:             return MAPID_BABY_SURA;
 		case JOB_BABY_GENETIC:          return MAPID_BABY_GENETIC;
 		case JOB_BABY_CHASER:           return MAPID_BABY_CHASER;
+	//Doram Jobs
+		case JOB_SUMMONER:              return MAPID_SUMMONER;
 		default:
 			return -1;
 	}
@@ -5874,6 +5877,8 @@ int pc_mapid2jobid(unsigned short class_, int sex)
 		case MAPID_BABY_SURA:             return JOB_BABY_SURA;
 		case MAPID_BABY_GENETIC:          return JOB_BABY_GENETIC;
 		case MAPID_BABY_CHASER:           return JOB_BABY_CHASER;
+	//Doram Jobs
+		case MAPID_SUMMONER:              return JOB_SUMMONER;
 		default:
 			return -1;
 	}
@@ -6101,6 +6106,9 @@ const char* job_name(int class_)
 	case JOB_REBELLION:
 		return msg_txt(NULL,695);
 
+	case JOB_SUMMONER:
+		return msg_txt(NULL,697);
+
 	default:
 		return msg_txt(NULL,655);
 	}
@@ -7037,6 +7045,9 @@ int pc_resetskill(struct map_session_data* sd, int flag)
 
 		if( hom_is_active(sd->hd) && pc_checkskill(sd, AM_CALLHOMUN) )
 			hom_vaporize(sd, HOM_ST_ACTIVE);
+
+		if (sd->sc.data[SC_SPRITEMABLE] && pc_checkskill(sd, SU_SPRITEMABLE))
+			status_change_end(&sd->bl, SC_SPRITEMABLE, INVALID_TIMER);
 	}
 
 	for( i = 1; i < MAX_SKILL; i++ )
@@ -7061,7 +7072,7 @@ int pc_resetskill(struct map_session_data* sd, int flag)
 		}
 
 		// do not reset basic skill
-		if( skill_id == NV_BASIC && (sd->class_&MAPID_UPPERMASK) != MAPID_NOVICE )
+		if (skill_id == NV_BASIC && ((sd->class_&MAPID_UPPERMASK) != MAPID_NOVICE || (sd->class_&MAPID_BASEMASK) != MAPID_SUMMONER) )
 			continue;
 
 		if( sd->status.skill[i].flag == SKILL_FLAG_PERM_GRANTED )
@@ -8083,6 +8094,8 @@ int pc_itemheal(struct map_session_data *sd,int itemid, int hp,int sp)
 		if (sd->sc.data[SC_EXTREMITYFIST2])
 			sp = 0;
 #endif
+		if (sd->sc.data[SC_BITESCAR])
+			hp = 0;
 	}
 
 	return status_heal(&sd->bl, hp, sp, 1);
@@ -8279,6 +8292,9 @@ bool pc_jobchange(struct map_session_data *sd,int job, char upper)
 
 	status_set_viewdata(&sd->bl, job);
 	clif_changelook(&sd->bl,LOOK_BASE,sd->vd.class_); // move sprite update to prevent client crashes with incompatible equipment [Valaris]
+#if PACKETVER >= 20151001
+	clif_changelook(&sd->bl, LOOK_HAIR, sd->vd.hair_style); // Update player's head (only matters when switching to or from Doram)
+#endif
 	if(sd->vd.cloth_color)
 		clif_changelook(&sd->bl,LOOK_CLOTHES_COLOR,sd->vd.cloth_color);
 	/*
@@ -8325,6 +8341,9 @@ bool pc_jobchange(struct map_session_data *sd,int job, char upper)
 	if(hom_is_active(sd->hd) && !pc_checkskill(sd, AM_CALLHOMUN))
 		hom_vaporize(sd, HOM_ST_ACTIVE);
 
+	if (sd->sc.data[SC_SPRITEMABLE] && !pc_checkskill(sd, SU_SPRITEMABLE))
+		status_change_end(&sd->bl, SC_SPRITEMABLE, INVALID_TIMER);
+
 	if(sd->status.manner < 0)
 		clif_changestatus(sd,SP_MANNER,sd->status.manner);
 
@@ -11678,7 +11697,8 @@ short pc_maxparameter(struct map_session_data *sd, enum e_params param) {
 			return max_param;
 	}
 
-	return ((class_&MAPID_UPPERMASK) == MAPID_KAGEROUOBORO || (class_&MAPID_UPPERMASK) == MAPID_REBELLION) ? battle_config.max_extended_parameter :
+	return (class_&MAPID_BASEMASK) == MAPID_SUMMONER ? battle_config.max_summoner_parameter :
+		((class_&MAPID_UPPERMASK) == MAPID_KAGEROUOBORO || (class_&MAPID_UPPERMASK) == MAPID_REBELLION) ? battle_config.max_extended_parameter :
 		((class_&JOBL_THIRD) ? ((class_&JOBL_UPPER) ? battle_config.max_third_trans_parameter : ((class_&JOBL_BABY) ? battle_config.max_baby_third_parameter : battle_config.max_third_parameter)) : 
 		((class_&JOBL_BABY) ? battle_config.max_baby_parameter :
 		((class_&JOBL_UPPER) ? battle_config.max_trans_parameter : battle_config.max_parameter)));

+ 1 - 1
src/map/pc.h

@@ -867,7 +867,7 @@ short pc_maxaspd(struct map_session_data *sd);
 	( (class_) >= JOB_BABY_RUNE      && (class_) <= JOB_BABY_MECHANIC2 ) || \
 	( (class_) >= JOB_SUPER_NOVICE_E && (class_) <= JOB_SUPER_BABY_E   ) || \
 	( (class_) >= JOB_KAGEROU        && (class_) <= JOB_OBORO          ) || \
-	( (class_) >= JOB_REBELLION      && (class_) <  JOB_MAX            ) \
+	  (class_) == JOB_REBELLION      || (class_) == JOB_SUMMONER            \
 )
 #define pcdb_checkid(class_) pcdb_checkid_sub((unsigned int)class_)
 

+ 3 - 0
src/map/script.c

@@ -5820,6 +5820,9 @@ BUILDIN_FUNC(percentheal)
 		sp = 0;
 	}
 
+	if (sd->sc.data[SC_BITESCAR])
+		hp = 0;
+
 	pc_percentheal(sd,hp,sp);
 	return SCRIPT_CMD_SUCCESS;
 }

+ 27 - 0
src/map/script_constants.h

@@ -1345,6 +1345,16 @@
 	export_constant(SC_PROMOTE_HEALTH_RESERCH);
 	export_constant(SC_ENERGY_DRINK_RESERCH);
 	export_constant(SC_NORECOVER_STATE);
+	export_constant(SC_SUHIDE);
+	export_constant(SC_SU_STOOP);
+	export_constant(SC_SPRITEMABLE);
+	export_constant(SC_CATNIPPOWDER);
+	export_constant(SC_SV_ROOTTWIST);
+	export_constant(SC_BITESCAR);
+	export_constant(SC_ARCLOUSEDASH);
+	export_constant(SC_TUNAPARTY);
+	export_constant(SC_SHRIMP);
+	export_constant(SC_FRESHSHRIMP);
 #ifdef RENEWAL
 	export_constant(SC_EXTREMITYFIST2);
 #endif
@@ -2306,6 +2316,7 @@
 	export_constant(SI_LIMIT_POWER_BOOSTER);
 	export_constant(SI_TIME_ACCESSORY);
 	export_constant(SI_EP16_DEF);
+	export_constant(SI_NORMAL_ATKED_SP);
 	export_constant(SI_BODYSTATE_STONECURSE);
 	export_constant(SI_BODYSTATE_FREEZING);
 	export_constant(SI_BODYSTATE_STUN);
@@ -2323,6 +2334,10 @@
 	export_constant(SI_HEALTHSTATE_BLOODING);
 	export_constant(SI_HEALTHSTATE_HEAVYPOISON);
 	export_constant(SI_HEALTHSTATE_FEAR);
+	export_constant(SI_CHERRY_BLOSSOM_CAKE);
+	export_constant(SI_SU_STOOP);
+	export_constant(SI_CATNIPPOWDER);
+	export_constant(SI_SV_ROOTTWIST);
 	export_constant(SI_ATTACK_PROPERTY_NOTHING);
 	export_constant(SI_ATTACK_PROPERTY_WATER);
 	export_constant(SI_ATTACK_PROPERTY_GROUND);
@@ -2343,6 +2358,14 @@
 	export_constant(SI_RESIST_PROPERTY_DARKNESS);
 	export_constant(SI_RESIST_PROPERTY_TELEKINESIS);
 	export_constant(SI_RESIST_PROPERTY_UNDEAD);
+	export_constant(SI_BITESCAR);
+	export_constant(SI_ARCLOUSEDASH);
+	export_constant(SI_TUNAPARTY);
+	export_constant(SI_SHRIMP);
+	export_constant(SI_FRESHSHRIMP);
+	export_constant(SI_PERIOD_RECEIVEITEM);
+	export_constant(SI_PERIOD_PLUSEXP);
+	export_constant(SI_PERIOD_PLUSJOBEXP);
 	export_constant(SI_RUNEHELM);
 	export_constant(SI_HELM_VERKANA);
 	export_constant(SI_HELM_RHYDO);
@@ -2351,6 +2374,10 @@
 	export_constant(SI_HELM_ISIA);
 	export_constant(SI_HELM_ASIR);
 	export_constant(SI_HELM_URJ);
+	export_constant(SI_SUHIDE);
+	export_constant(SI_DORAM_BUF_01);
+	export_constant(SI_DORAM_BUF_02);
+	export_constant(SI_SPRITEMABLE);
 
 	/* elements */
 	export_constant(ELE_NEUTRAL);

+ 176 - 11
src/map/skill.c

@@ -482,6 +482,11 @@ int skill_calc_heal(struct block_list *src, struct block_list *target, uint16 sk
 				hp += hp * skill * 2 / 100;
 			if( sd && tsd && sd->status.partner_id == tsd->status.char_id && (sd->class_&MAPID_UPPERMASK) == MAPID_SUPER_NOVICE && sd->status.sex == 0 )
 				hp *= 2;
+			if (sd && ((skill = pc_checkskill(sd, SU_POWEROFSEA)) > 0)) {
+				hp += hp * 10 / 100;
+				if (pc_checkskill(sd, SU_TUNABELLY) == 5 && pc_checkskill(sd, SU_TUNAPARTY) == 5 && pc_checkskill(sd, SU_BUNCHOFSHRIMP) == 5 && pc_checkskill(sd, SU_FRESHSHRIMP) == 5)
+					hp += hp * 20 / 100;
+			}
 			break;
 	}
 
@@ -916,6 +921,15 @@ struct s_skill_nounit_layout* skill_get_nounit_layout(uint16 skill_id, uint16 sk
 	return &skill_nounit_layout[0];
 }
 
+/** Stores temporary values.
+ * Common usages:
+ * [0] holds number of targets in area
+ * [1] holds the id of the original target
+ * [2] counts how many targets have been processed. counter is added in skill_area_sub if the foreach function flag is: flag&(SD_SPLASH|SD_PREAMBLE)
+ */
+static int skill_area_temp[8];
+static int64 skill_area_temp_i64[1];
+
 /*==========================================
  * Add effect to skill when hit succesfully target
  *------------------------------------------*/
@@ -1793,6 +1807,7 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1
 					case SC_REUSE_LIMIT_G:	case SC_REUSE_LIMIT_H:	case SC_REUSE_LIMIT_MTF:
 					case SC_REUSE_LIMIT_ASPD_POTION:	case SC_REUSE_MILLENNIUMSHIELD:	case SC_REUSE_CRUSHSTRIKE:
 					case SC_REUSE_STORMBLAST:	case SC_ALL_RIDING_REUSE_LIMIT:
+					case SC_SPRITEMABLE:		case SC_BITESCAR:
 						continue;
 					case SC_WHISTLE:		case SC_ASSNCROS:		case SC_POEMBRAGI:
 					case SC_APPLEIDUN:		case SC_HUMMING:		case SC_DONTFORGETME:
@@ -1831,6 +1846,23 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1
 		sc_start(src,bl,SC_STUN,100,skill_lv,skill_get_time2(skill_id,skill_lv));
 		status_change_end(bl, SC_C_MARKER, INVALID_TIMER);
 		break;
+	case SU_SCRATCH:
+		sc_start2(src, bl, SC_BLEEDING, (skill_lv * 3), skill_lv, src->id, skill_get_time(skill_id, skill_lv)); // TODO: What's the chance/time?
+		break;
+	case SU_SV_STEMSPEAR:
+		sc_start2(src, bl, SC_BLEEDING, 10, skill_lv, src->id, skill_get_time(skill_id, skill_lv));
+		break;
+	case SU_CN_METEOR:
+		if (skill_area_temp[3] == 1)
+				sc_start(src, bl, SC_CURSE, 10, skill_lv, skill_get_time2(skill_id, skill_lv)); // TODO: What's the chance/time?
+		break;
+	//case SU_SCAROFTAROU:
+	//	sc_start(src, bl, SC_STUN, 10, skill_lv, skill_get_time2(skill_id, skill_lv)); // TODO: What's the chance/time?
+	//	break;
+	case SU_LUNATICCARROTBEAT:
+		if (skill_area_temp[3] == 1)
+			sc_start(src, bl, SC_STUN, 10, skill_lv, skill_get_time(skill_id, skill_lv)); // TODO: What's the chance/time?
+		break;
 	} //end switch skill_id
 
 	if (md && battle_config.summons_trigger_autospells && md->master_id && md->special_state.ai)
@@ -2506,15 +2538,6 @@ int skill_strip_equip(struct block_list *src,struct block_list *bl, unsigned sho
 	return where?1:0;
 }
 
-/** Stores temporary values.
- * Common usages:
- * [0] holds number of targets in area
- * [1] holds the id of the original target
- * [2] counts how many targets have been processed. counter is added in skill_area_sub if the foreach function flag is: flag&(SD_SPLASH|SD_PREAMBLE)
- */
-static int skill_area_temp[8];
-static int64 skill_area_temp_i64[1];
-
 /**
  Used to knock back players, monsters, traps, etc
  * @param src Object that give knock back
@@ -2535,6 +2558,7 @@ short skill_blown(struct block_list* src, struct block_list* target, char count,
 {
 	int dx = 0, dy = 0;
 	uint8 reason = 0, checkflag = 0;
+	struct status_change *tsc = status_get_sc(target);
 
 	nullpo_ret(src);
 	nullpo_ret(target);
@@ -2569,6 +2593,9 @@ short skill_blown(struct block_list* src, struct block_list* target, char count,
 		dy = -diry[dir];
 	}
 
+	if (tsc && tsc->data[SC_SU_STOOP]) // Any knockback will cancel it.
+		status_change_end(target, SC_SU_STOOP, INVALID_TIMER);
+
 	return unit_blown(target, dx, dy, count, flag);	// Send over the proper flag
 }
 
@@ -4083,6 +4110,7 @@ static int skill_timerskill(int tid, unsigned int tick, int id, intptr_t data)
 			switch( skl->skill_id )
 			{
 				case WZ_METEOR:
+				case SU_CN_METEOR:
 					if( skl->type >= 0 )
 					{
 						int x = skl->type>>16, y = skl->type&0xFFFF;
@@ -4617,6 +4645,14 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint
 			skill_attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,flag);
 		break;
 
+	case SU_PICKYPECK:
+		clif_skill_nodamage(src, bl, skill_id, skill_lv, 1);
+	case SU_BITE:
+		skill_attack(BF_WEAPON, src, src, bl, skill_id, skill_lv, tick, flag);
+		if (status_get_lv(src) >= 30 && (rnd() % 100 < (int)(status_get_lv(src) / 30) + 10)) // TODO: Need activation chance.
+			skill_addtimerskill(src, tick + skill_get_delay(skill_id, skill_lv), bl->id, 0, 0, skill_id, skill_lv, BF_WEAPON, flag);
+		break;
+
 	//Splash attack skills.
 	case AS_GRIMTOOTH:
 	case MC_CARTREVOLUTION:
@@ -4672,6 +4708,8 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint
 	case RL_R_TRIP:
 	case MH_XENO_SLASHER:
 	case NC_ARMSCANNON:
+	case SU_SCRATCH:
+	case SU_LUNATICCARROTBEAT:
 		if( flag&1 ) {//Recursive invocation
 			int sflag = skill_area_temp[0] & 0xFFF;
 			int heal = 0;
@@ -4690,6 +4728,8 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint
 				clif_skill_nodamage(NULL, src, AL_HEAL, heal, 1);
 				status_heal(src,heal,0,0);
 			}
+			if (skill_id == SU_SCRATCH && status_get_lv(src) >= 30 && (rnd() % 100 < (int)(status_get_lv(src) / 30) + 10)) // TODO: Need activation chance.
+				skill_addtimerskill(src, tick + skill_get_delay(skill_id, skill_lv), bl->id, 0, 0, skill_id, skill_lv, BF_WEAPON, flag);
 		} else {
 			int starget = splash_target(src);
 
@@ -4698,8 +4738,11 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint
 			skill_area_temp[2] = 0;
 
 			switch ( skill_id ) {
+				case SU_LUNATICCARROTBEAT:
+					skill_area_temp[3] = 0;
 				case LG_EARTHDRIVE:
 				case GN_CARTCANNON:
+				case SU_SCRATCH:
 					clif_skill_nodamage(src,bl,skill_id,skill_lv,1);
 					break;
 				case LG_MOONSLASHER:
@@ -4737,6 +4780,15 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint
 				map_foreachinshootrange(skill_area_sub, bl, skill_get_splash(skill_id, skill_lv), starget, src, skill_id, skill_lv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill_castend_damage_id);
 			else
 				map_foreachinrange(skill_area_sub, bl, skill_get_splash(skill_id, skill_lv), starget, src, skill_id, skill_lv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill_castend_damage_id);
+
+			if (sd && skill_id == SU_LUNATICCARROTBEAT) {
+				short item_idx = pc_search_inventory(sd, ITEMID_CARROT);
+
+				if (item_idx >= 0) {
+					pc_delitem(sd, item_idx, 1, 0, 1, LOG_TYPE_CONSUME);
+					skill_area_temp[3] = 1;
+				}
+			}
 			if( skill_id == AS_SPLASHER ) {
 				map_freeblock_unlock(); // Don't consume a second gemstone.
 				return 0;
@@ -5719,6 +5771,14 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint
 		}
 		break;
 
+	case SU_SCAROFTAROU:
+		sc_start(src, bl, status_skill2sc(skill_id), 10, skill_lv, skill_get_time(skill_id, skill_lv)); // TODO: What's the activation chance for the Bite effect?
+	case SU_SV_STEMSPEAR:
+		skill_attack(skill_get_type(skill_id), src, src, bl, skill_id, skill_lv, tick, flag);
+		if (status_get_lv(src) >= 30 && (rnd() % 100 < (int)(status_get_lv(src) / 30) + 10)) // TODO: Need activation chance.
+			skill_addtimerskill(src, tick + skill_get_delay(skill_id, skill_lv), bl->id, 0, 0, skill_id, skill_lv, (skill_id == SU_SV_STEMSPEAR) ? BF_MAGIC : BF_WEAPON, flag);
+		break;
+
 	case 0:/* no skill - basic/normal attack */
 		if(sd) {
 			if (flag & 3){
@@ -5912,6 +5972,8 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
 				else if (tsc->data[SC_BERSERK] || tsc->data[SC_SATURDAYNIGHTFEVER])
 					heal = 0; //Needed so that it actually displays 0 when healing.
 			}
+			if (skill_id == AL_HEAL)
+				status_change_end(bl, SC_BITESCAR, INVALID_TIMER);
 			clif_skill_nodamage (src, bl, skill_id, heal, 1);
 			if( tsc && tsc->data[SC_AKAITSUKI] && heal && skill_id != HLIF_HEAL )
 				heal = ~heal + 1;
@@ -6299,6 +6361,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
 
 	case PR_KYRIE:
 	case MER_KYRIE:
+	case SU_TUNAPARTY:
 		clif_skill_nodamage(bl,bl,skill_id,skill_lv,
 			sc_start(src,bl,type,100,skill_lv,skill_get_time(skill_id,skill_lv)));
 		break;
@@ -6409,10 +6472,17 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
 	case RL_HEAT_BARREL:
 	case RL_P_ALTER:
 	case RL_E_CHAIN:
+	case SU_FRESHSHRIMP:
+	case SU_ARCLOUSEDASH:
 		clif_skill_nodamage(src,bl,skill_id,skill_lv,
 			sc_start(src,bl,type,100,skill_lv,skill_get_time(skill_id,skill_lv)));
 		break;
 
+	case SU_STOOP:
+		clif_skill_nodamage(src, bl, skill_id, skill_lv, 1);
+		sc_start(src, bl, type, 100, skill_lv, skill_get_time(skill_id, skill_lv));
+ 		break;
+
 	case KN_AUTOCOUNTER:
 		sc_start(src,bl,type,100,skill_lv,skill_get_time(skill_id,skill_lv));
 		skill_addtimerskill(src,tick + 100,bl->id,0,0,skill_id,skill_lv,BF_WEAPON,flag);
@@ -7104,6 +7174,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
 		status_change_end(bl, SC_SILENCE, INVALID_TIMER);
 		status_change_end(bl, SC_BLIND, INVALID_TIMER);
 		status_change_end(bl, SC_CONFUSION, INVALID_TIMER);
+		status_change_end(bl, SC_BITESCAR, INVALID_TIMER);
 		clif_skill_nodamage(src,bl,skill_id,skill_lv,1);
 		break;
 
@@ -7646,6 +7717,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
 					case SC_REUSE_LIMIT_G:	case SC_REUSE_LIMIT_H:	case SC_REUSE_LIMIT_MTF:
 					case SC_REUSE_LIMIT_ASPD_POTION:	case SC_REUSE_MILLENNIUMSHIELD:	case SC_REUSE_CRUSHSTRIKE:
 					case SC_REUSE_STORMBLAST:	case SC_ALL_RIDING_REUSE_LIMIT:
+					case SC_SPRITEMABLE:		case SC_BITESCAR:
 						continue;
 					//bugreport:4888 these songs may only be dispelled if you're not in their song area anymore
 					case SC_WHISTLE:
@@ -9153,6 +9225,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
 					case SC_REUSE_LIMIT_G:	case SC_REUSE_LIMIT_H:	case SC_REUSE_LIMIT_MTF:
 					case SC_REUSE_LIMIT_ASPD_POTION:	case SC_REUSE_MILLENNIUMSHIELD:	case SC_REUSE_CRUSHSTRIKE:
 					case SC_REUSE_STORMBLAST:	case SC_ALL_RIDING_REUSE_LIMIT:
+					case SC_SPRITEMABLE:
 					continue;
 				case SC_ASSUMPTIO:
 					if( bl->type == BL_MOB )
@@ -9523,6 +9596,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
 		clif_skill_damage(src,bl,tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6);
 		if (rnd()%100 < (25 + 25 * skill_lv))
 			map_foreachinrange(skill_destroy_trap,bl,skill_get_splash(skill_id,skill_lv),BL_SKILL,tick);
+		status_change_end(bl, SC_SV_ROOTTWIST, INVALID_TIMER);
 		break;
 
 	case LG_REFLECTDAMAGE:
@@ -10721,6 +10795,37 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
 		}
 		break;
 
+	case SU_HIDE:
+		if (tsce) {
+			clif_skill_nodamage(src, bl, skill_id, skill_lv, 1);
+			status_change_end(bl, type, INVALID_TIMER);
+			map_freeblock_unlock();
+			return 0;
+		}
+		clif_skill_nodamage(src, bl, skill_id, skill_lv, 1);
+		sc_start(src, bl, type, 100, skill_lv, skill_get_time(skill_id, skill_lv));
+ 		break;
+
+	case SU_TUNABELLY:
+	{
+		int heal;
+
+		if (!dstmd || dstmd->mob_id != MOBID_EMPERIUM || !mob_is_battleground(dstmd)) {
+			heal = ((2 * skill_lv - 1) * 10) * status_get_max_hp(bl) / 100;
+			status_heal(bl, heal, 0, 0);
+		}
+
+		clif_skill_nodamage(src, bl, skill_id, heal, 1);
+	}
+		break;
+
+	case SU_BUNCHOFSHRIMP:
+		if (sd == NULL || sd->status.party_id == 0 || flag&1)
+			clif_skill_nodamage(bl, bl, skill_id, skill_lv, sc_start(src, bl, type, 100, skill_lv, skill_get_time(skill_id, skill_lv)));
+		else if (sd)
+			party_foreachsamemap(skill_area_sub, sd, skill_get_splash(skill_id, skill_lv), src, skill_id, skill_lv, tick, flag|BCT_PARTY|1, skill_castend_nodamage_id);
+		break;
+
 	default:
 		ShowWarning("skill_castend_nodamage_id: Unknown skill used:%d\n",skill_id);
 		clif_skill_nodamage(src,bl,skill_id,skill_lv,1);
@@ -10964,6 +11069,8 @@ int skill_castend_id(int tid, unsigned int tick, int id, intptr_t data)
 				}
 			case GN_WALLOFTHORN:
 			case SC_ESCAPE:
+			case SU_CN_POWDERING:
+			case SU_SV_ROOTTWIST:
 				ud->skillx = target->x;
 				ud->skilly = target->y;
 				ud->skilltimer = tid;
@@ -11347,6 +11454,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui
 		case LG_EARTHDRIVE:
 		case SC_ESCAPE:
 		case RL_HAMMER_OF_GOD:
+		case SU_CN_METEOR:
 			break; //Effect is displayed on respective switch case.
 		default:
 			if(skill_get_inf(skill_id)&INF_SELF_SKILL)
@@ -11513,6 +11621,8 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui
 	case MH_XENO_SLASHER:
 	case LG_KINGS_GRACE:
 	case RL_B_TRAP:
+	case SU_CN_POWDERING:
+	case SU_SV_ROOTTWIST:
 		flag|=1;//Set flag to 1 to prevent deleting ammo (it will be deleted on group-delete).
 	case GS_GROUNDDRIFT: //Ammo should be deleted right away.
 	case GN_WALLOFTHORN:
@@ -11560,10 +11670,21 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui
 		skill_unitsetting(src,skill_id,skill_lv,x,y,0);
 		break;
 
-	case WZ_METEOR: {
+	case WZ_METEOR:
+	case SU_CN_METEOR: {
 			int area = skill_get_splash(skill_id, skill_lv);
 			short tmpx = 0, tmpy = 0, x1 = 0, y1 = 0;
 
+			if (sd && skill_id == SU_CN_METEOR) {
+				short item_idx = pc_search_inventory(sd, ITEMID_CATNIP_FRUIT);
+
+				if (item_idx >= 0) {
+					pc_delitem(sd, item_idx, 1, 0, 1, LOG_TYPE_CONSUME);
+					skill_area_temp[3] = 1;
+				} else
+					skill_area_temp[3] = 0;
+			}
+
 			for( i = 0; i < 2 + (skill_lv>>1); i++ ) {
 				// Creates a random Cell in the Splash Area
 				tmpx = x - area + rnd()%(area * 2 + 1);
@@ -12093,6 +12214,18 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui
 		}
 		break;
 
+	case SU_LOPE:
+		if (map[src->m].flag.noteleport && !(map[src->m].flag.battleground || map_flag_gvg2(src->m))) {
+			x = src->x;
+			y = src->y;
+		}
+		clif_skill_nodamage(src, src, SU_LOPE, skill_lv, 1);
+		if (!map_count_oncell(src->m, x, y, BL_PC|BL_NPC|BL_MOB, 0) && path_search(NULL, src->m, src->x, src->y, x, y, 1, CELL_CHKNOREACH)) {
+			clif_slide(src, x, y);
+			unit_movepos(src, x, y, 1, 0);
+		}
+		break;
+
 	default:
 		ShowWarning("skill_castend_pos2: Unknown skill used:%d\n",skill_id);
 		return 1;
@@ -13158,6 +13291,13 @@ static int skill_unit_onplace(struct skill_unit *unit, struct block_list *bl, un
 				status_change_start(ss, bl, type, 10000, sg->skill_lv, 0, 0, 0, sg->limit, SCSTART_NOICON);
 			break;
 
+		case UNT_CATNIPPOWDER:
+			if (sg->src_id == bl->id || (status_get_mode(bl)&MD_BOSS))
+				break; // Does not affect the caster or Boss.
+			if (!sce && battle_check_target(&unit->bl, bl, BCT_ENEMY) > 0)
+				sc_start(ss, bl, type, 100, sg->skill_lv, skill_get_time(sg->skill_id, sg->skill_lv));
+			break;
+
 		case UNT_GD_LEADERSHIP:
 		case UNT_GD_GLORYWOUNDS:
 		case UNT_GD_SOULCOLD:
@@ -13277,6 +13417,9 @@ int skill_unit_onplace_timer(struct skill_unit *unit, struct block_list *bl, uns
 						++count < SKILLUNITTIMER_INTERVAL/sg->interval && !status_isdead(bl) );
 				}
 				break;
+				case WZ_HEAVENDRIVE:
+					status_change_end(bl, SC_SV_ROOTTWIST, INVALID_TIMER);
+				break;
 #ifndef RENEWAL // The storm gust counter was dropped in renewal
 				case WZ_STORMGUST: //SG counter does not reset per stormgust. IE: One hit from a SG and two hits from another will freeze you.
 					if (tsc)
@@ -13318,7 +13461,6 @@ int skill_unit_onplace_timer(struct skill_unit *unit, struct block_list *bl, uns
 				skill_delunit(unit);
 		}
 		break;
-
 		case UNT_SANCTUARY:
 			if( battle_check_undead(tstatus->race, tstatus->def_ele) || tstatus->race==RC_DEMON )
 			{ //Only damage enemies with offensive Sanctuary. [Skotlex]
@@ -13920,6 +14062,28 @@ int skill_unit_onplace_timer(struct skill_unit *unit, struct block_list *bl, uns
 				skill_attack(skill_get_type(sg->skill_id),ss,&unit->bl,bl,sg->skill_id,sg->skill_lv,tick,SD_ANIMATION|SD_SPLASH),
 				1,sg->skill_id,sg->skill_lv,6);
 			break;
+
+		case UNT_SV_ROOTTWIST:
+			if (status_get_mode(bl)&MD_BOSS)
+				break;
+			if (tsc) {
+				if (!sg->val2) {
+					int sec = skill_get_time(sg->skill_id, sg->skill_lv);
+
+					if (sc_start2(ss, bl, type, 100, sg->skill_lv, sg->group_id, sec)) {
+						const struct TimerData* td = tsc->data[type]?get_timer(tsc->data[type]->timer):NULL;
+
+						if(td)
+							sec = DIFF_TICK(td->tick, tick);
+						clif_fixpos(bl);
+						sg->val2 = bl->id;
+					} else // Couldn't trap it?
+						sec = 7000;
+					sg->limit = DIFF_TICK(tick, sg->tick) + sec;
+				} else if (tsc->data[type] && bl->id == sg->val2)
+					skill_attack(skill_get_type(SU_SV_ROOTTWIST_ATK), ss, &unit->bl, bl, SU_SV_ROOTTWIST_ATK, sg->skill_lv, tick, SD_LEVEL|SD_ANIMATION);
+			}
+			break;
 	}
 
 	if (bl->type == BL_MOB && ss != bl)
@@ -20242,6 +20406,7 @@ int skill_disable_check(struct status_change *sc, uint16 skill_id)
 		case KO_YAMIKUMO:
 		case RA_WUGDASH:
 		case RA_CAMOUFLAGE:
+		case SU_HIDE:
 			if( sc->data[status_skill2sc(skill_id)] )
 				return 1;
 			break;

+ 28 - 0
src/map/skill.h

@@ -1736,6 +1736,31 @@ enum e_skill {
 	LG_KINGS_GRACE,
 	ALL_FULL_THROTTLE,
 
+	SU_BASIC_SKILL = 5018,
+	SU_BITE,
+	SU_HIDE,
+	SU_SCRATCH,
+	SU_STOOP,
+	SU_LOPE,
+	SU_SPRITEMABLE,
+	SU_POWEROFLAND,
+	SU_SV_STEMSPEAR,
+	SU_CN_POWDERING,
+	SU_CN_METEOR,
+	SU_SV_ROOTTWIST,
+	SU_SV_ROOTTWIST_ATK,
+	SU_POWEROFLIFE,
+	SU_SCAROFTAROU,
+	SU_PICKYPECK,
+	SU_PICKYPECK_DOUBLE_ATK,
+	SU_ARCLOUSEDASH,
+	SU_LUNATICCARROTBEAT,
+	SU_POWEROFSEA,
+	SU_TUNABELLY,
+	SU_TUNAPARTY,
+	SU_BUNCHOFSHRIMP,
+	SU_FRESHSHRIMP,
+
 	HLIF_HEAL = 8001,
 	HLIF_AVOID,
 	HLIF_BRAIN,
@@ -2006,6 +2031,9 @@ enum s_skill_unit_id {
 	UNT_B_TRAP,
 	UNT_FIRE_RAIN,
 
+	UNT_CATNIPPOWDER,
+	UNT_SV_ROOTTWIST,
+
 	/**
 	 * Guild Auras
 	 **/

+ 135 - 5
src/map/status.c

@@ -834,6 +834,22 @@ void initChangeTables(void)
 	set_sc_with_vfx_noskill( SC_STRANGELIGHTS	, SI_STRANGELIGHTS	, SCB_NONE );
 	set_sc_with_vfx_noskill( SC_DECORATION_OF_MUSIC		, SI_DECORATION_OF_MUSIC		, SCB_NONE );
 
+	/* Summoner */
+	set_sc( SU_HIDE					, SC_SUHIDE			, SI_SUHIDE			, SCB_NONE );
+	add_sc( SU_SCRATCH				, SC_BLEEDING );
+	set_sc( SU_STOOP				, SC_SU_STOOP		, SI_SU_STOOP		, SCB_NONE );
+	add_sc( SU_SV_STEMSPEAR			, SC_BLEEDING );
+	set_sc( SU_CN_POWDERING			, SC_CATNIPPOWDER	, SI_CATNIPPOWDER	, SCB_WATK|SCB_SPEED|SCB_REGEN );
+	add_sc( SU_CN_METEOR			, SC_CURSE );
+	set_sc_with_vfx( SU_SV_ROOTTWIST			, SC_SV_ROOTTWIST	, SI_SV_ROOTTWIST	, SCB_NONE );
+	//add_sc( SU_SCAROFTAROU			, SC_STUN );
+	set_sc( SU_SCAROFTAROU			, SC_BITESCAR		, SI_BITESCAR		, SCB_NONE );
+	set_sc( SU_ARCLOUSEDASH			, SC_ARCLOUSEDASH	, SI_ARCLOUSEDASH	, SCB_AGI|SCB_SPEED );
+	add_sc( SU_LUNATICCARROTBEAT	, SC_STUN );
+	set_sc( SU_TUNAPARTY			, SC_TUNAPARTY		, SI_TUNAPARTY		, SCB_NONE );
+	set_sc( SU_BUNCHOFSHRIMP		, SC_SHRIMP			, SI_SHRIMP			, SCB_BATK|SCB_MATK );
+	set_sc( SU_FRESHSHRIMP			, SC_FRESHSHRIMP	, SI_FRESHSHRIMP	, SCB_NONE );
+
 	/* Storing the target job rather than simply SC_SPIRIT simplifies code later on */
 	SkillStatusChangeTable[skill_get_index(SL_ALCHEMIST)]	= (sc_type)MAPID_ALCHEMIST,
 	SkillStatusChangeTable[skill_get_index(SL_MONK)]		= (sc_type)MAPID_MONK,
@@ -1027,6 +1043,9 @@ void initChangeTables(void)
 	StatusIconChangeTable[SC_MTF_PUMPKIN] = SI_MTF_PUMPKIN;
 	StatusIconChangeTable[SC_NORECOVER_STATE] = SI_HANDICAPSTATE_NORECOVER;
 
+	/* Summoners status icons */
+	StatusIconChangeTable[SC_SPRITEMABLE] = SI_SPRITEMABLE;
+
 	// Item Reuse Limits
 	StatusIconChangeTable[SC_REUSE_REFRESH] = SI_REUSE_REFRESH;
 	StatusIconChangeTable[SC_REUSE_LIMIT_A] = SI_REUSE_LIMIT_A;
@@ -1214,6 +1233,7 @@ void initChangeTables(void)
 	StatusDisplayType[SC_SUPER_STAR]	  = true;
 	StatusDisplayType[SC_STRANGELIGHTS]	  = true;
 	StatusDisplayType[SC_DECORATION_OF_MUSIC] = true;
+	StatusDisplayType[SC_SPRITEMABLE]     = true;
 
 	/* StatusChangeState (SCS_) NOMOVE */
 	StatusChangeStateTable[SC_ANKLE]				|= SCS_NOMOVE;
@@ -1246,6 +1266,8 @@ void initChangeTables(void)
 	StatusChangeStateTable[SC_PARALYSIS]			|= SCS_NOMOVE;
 	StatusChangeStateTable[SC_KINGS_GRACE]			|= SCS_NOMOVE;
 	StatusChangeStateTable[SC_VACUUM_EXTREME]		|= SCS_NOMOVE;
+	StatusChangeStateTable[SC_SUHIDE]				|= SCS_NOMOVE;
+	StatusChangeStateTable[SC_SV_ROOTTWIST]			|= SCS_NOMOVE;
 
 	/* StatusChangeState (SCS_) NOPICKUPITEMS */
 	StatusChangeStateTable[SC_HIDING]				|= SCS_NOPICKITEM;
@@ -1255,6 +1277,7 @@ void initChangeTables(void)
 	StatusChangeStateTable[SC_CLOAKINGEXCEED]		|= SCS_NOPICKITEM;
 	StatusChangeStateTable[SC__FEINTBOMB]			|= SCS_NOPICKITEM;
 	StatusChangeStateTable[SC_NOCHAT]				|= SCS_NOPICKITEM|SCS_NOPICKITEMCOND;
+	StatusChangeStateTable[SC_SUHIDE]				|= SCS_NOPICKITEM;
 
 	/* StatusChangeState (SCS_) NODROPITEMS */
 	StatusChangeStateTable[SC_AUTOCOUNTER]			|= SCS_NODROPITEM;
@@ -1522,6 +1545,7 @@ int status_damage(struct block_list *src,struct block_list *target,int64 dhp, in
 			status_change_end(target, SC_CHASEWALK, INVALID_TIMER);
 			status_change_end(target, SC_CAMOUFLAGE, INVALID_TIMER);
 			status_change_end(target, SC_DEEPSLEEP, INVALID_TIMER);
+			status_change_end(target, SC_SUHIDE, INVALID_TIMER);
 			if ((sce=sc->data[SC_ENDURE]) && !sce->val4) {
 				/** [Skotlex]
 				* Endure count is only reduced by non-players on non-gvg maps.
@@ -1960,6 +1984,7 @@ bool status_check_skilluse(struct block_list *src, struct block_list *target, ui
 			(sc->data[SC_TRICKDEAD] && skill_id != NV_TRICKDEAD)
 			|| (sc->data[SC_AUTOCOUNTER] && !flag && skill_id)
 			|| (sc->data[SC_GOSPEL] && sc->data[SC_GOSPEL]->val4 == BCT_SELF && skill_id != PA_GOSPEL)
+			|| (sc->data[SC_SUHIDE] && skill_id != SU_HIDE)
 		)
 			return false;
 
@@ -2079,7 +2104,7 @@ bool status_check_skilluse(struct block_list *src, struct block_list *target, ui
 						return false;
 					if (tsc->data[SC_CAMOUFLAGE] && !(is_boss || is_detect) && (!skill_id || (!flag && src)))
 						return false;
-					if (tsc->data[SC_STEALTHFIELD] && !(is_boss || is_detect))
+					if (( tsc->data[SC_STEALTHFIELD] || tsc->data[SC_SUHIDE]) && !(is_boss || is_detect))
 						return false;
 				}
 			}
@@ -2142,7 +2167,7 @@ int status_check_visibility(struct block_list *src, struct block_list *target)
 			case BL_PC: {
 					struct map_session_data *tsd = (TBL_PC*)target;
 
-					if (((tsc->option&(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK)) || tsc->data[SC_CAMOUFLAGE] || tsc->data[SC_STEALTHFIELD]) && !(status->mode&MD_BOSS) && (tsd->special_state.perfect_hiding || !(status->mode&MD_DETECTOR)))
+					if (((tsc->option&(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK)) || tsc->data[SC_CAMOUFLAGE] || tsc->data[SC_STEALTHFIELD] || tsc->data[SC_SUHIDE]) && !(status->mode&MD_BOSS) && (tsd->special_state.perfect_hiding || !(status->mode&MD_DETECTOR)))
 						return 0;
 					if (tsc->data[SC_CLOAKINGEXCEED] && !(status->mode&MD_BOSS) && ((tsd && tsd->special_state.perfect_hiding) || (status->mode&MD_DETECTOR)))
 						return 0;
@@ -2757,9 +2782,20 @@ static int status_get_hpbonus(struct block_list *bl, enum e_status_bonus type) {
 			bonus += sd->bonus.hp;
 			if ((i = pc_checkskill(sd,CR_TRUST)) > 0)
 				bonus += i * 200;
+			if ((i = pc_checkskill(sd,SU_SPRITEMABLE)) > 0)
+				bonus += 1000;
 #ifndef HP_SP_TABLES
 			if ((sd->class_&MAPID_UPPERMASK) == MAPID_SUPER_NOVICE && sd->status.base_level >= 99)
 				bonus += 2000; // Supernovice lvl99 hp bonus.
+
+			// Summoner starts with 60 HP and gains additional HP by base level calculations.
+			if ((sd->class_&MAPID_BASEMASK) == MAPID_SUMMONER) {
+					bonus += 18;
+					if (sd->status.base_level > 2)
+						bonus += sd->status.base_level - 2;
+					if (sd->status.base_level > 14)
+						bonus += (sd->status.base_level - 13) / 2;
+			}
 #endif
 		}
 
@@ -2876,6 +2912,14 @@ static int status_get_spbonus(struct block_list *bl, enum e_status_bonus type) {
 				bonus += 200 + 20 * i;
 			if ((i = pc_checkskill(sd,WM_LESSON)) > 0)
 				bonus += 30 * i;
+			if ((i = pc_checkskill(sd,SU_SPRITEMABLE)) > 0)
+				bonus += 100;
+
+			// Summoner starts at 8 SP and gain 2 SP per even base lv and 3 SP per odd base lv.
+			if ((sd->class_&MAPID_BASEMASK) == MAPID_SUMMONER) {
+				bonus -= 4;
+				bonus += (sd->status.base_level - 1) / 2;
+			}
 		}
 
 		//Bonus by SC
@@ -3089,7 +3133,7 @@ int status_calc_pc_(struct map_session_data* sd, enum e_status_calc_opt opt)
 	// Give them all modes except these (useful for clones)
 	base_status->mode = MD_MASK&~(MD_BOSS|MD_PLANT|MD_DETECTOR|MD_ANGRY|MD_TARGETWEAK);
 
-	base_status->size = (sd->class_&JOBL_BABY)?SZ_SMALL:SZ_MEDIUM;
+	base_status->size = (sd->class_&JOBL_BABY || (sd->class_&MAPID_BASEMASK) == MAPID_SUMMONER) ? SZ_SMALL : SZ_MEDIUM;
 	if (battle_config.character_size && pc_isriding(sd)) { // [Lupus]
 		if (sd->class_&JOBL_BABY) {
 			if (battle_config.character_size&SZ_BIG)
@@ -3100,7 +3144,7 @@ int status_calc_pc_(struct map_session_data* sd, enum e_status_calc_opt opt)
 	}
 	base_status->aspd_rate = 1000;
 	base_status->ele_lv = 1;
-	base_status->race = RC_PLAYER;
+	base_status->race = ((sd->class_&MAPID_BASEMASK) == MAPID_SUMMONER) ? RC_BRUTE : RC_PLAYER;
 	base_status->class_ = CLASS_NORMAL;
 
 	// Zero up structures...
@@ -3418,6 +3462,8 @@ int status_calc_pc_(struct map_session_data* sd, enum e_status_calc_opt opt)
 		base_status->dex += skill;
 	if((skill = pc_checkskill(sd,RA_RESEARCHTRAP))>0)
 		base_status->int_ += skill;
+	if (pc_checkskill(sd, SU_POWEROFLAND) > 0)
+		base_status->int_ += 20;
 
 	// Bonuses from cards and equipment as well as base stat, remember to avoid overflows.
 	i = base_status->str + sd->status.str + sd->param_bonus[0] + sd->param_equip[0];
@@ -3522,6 +3568,8 @@ int status_calc_pc_(struct map_session_data* sd, enum e_status_calc_opt opt)
 		sd->critical_rate = 0;
 	if(sd->critical_rate != 100)
 		base_status->cri = cap_value(base_status->cri * sd->critical_rate/100,SHRT_MIN,SHRT_MAX);
+	if (pc_checkskill(sd, SU_POWEROFLIFE) > 0)
+		base_status->cri += 20;
 
 	if(sd->flee2_rate < 0)
 		sd->flee2_rate = 0;
@@ -3554,7 +3602,8 @@ int status_calc_pc_(struct map_session_data* sd, enum e_status_calc_opt opt)
 		base_status->hit += skill * 3;
 	if((sd->status.weapon == W_MACE || sd->status.weapon == W_2HMACE) && (skill = pc_checkskill(sd,NC_TRAININGAXE)) > 0)
 		base_status->hit += skill * 2;
-
+	if (pc_checkskill(sd, SU_POWEROFLIFE) > 0)
+		base_status->hit += 20;
 
 // ----- FLEE CALCULATION -----
 
@@ -3563,6 +3612,8 @@ int status_calc_pc_(struct map_session_data* sd, enum e_status_calc_opt opt)
 		base_status->flee += skill*(sd->class_&JOBL_2 && (sd->class_&MAPID_BASEMASK) == MAPID_THIEF? 4 : 3);
 	if((skill=pc_checkskill(sd,MO_DODGE))>0)
 		base_status->flee += (skill*3)>>1;
+	if (pc_checkskill(sd, SU_POWEROFLIFE) > 0)
+		base_status->flee += 20;
 
 // ----- EQUIPMENT-DEF CALCULATION -----
 
@@ -3803,6 +3854,10 @@ int status_calc_pc_(struct map_session_data* sd, enum e_status_calc_opt opt)
 		clif_updatestatus(sd,SP_CARTINFO);
 	}
 
+	// If the skill is learned, the status is infinite.
+	if( (skill = pc_checkskill(sd,SU_SPRITEMABLE)) > 0 )
+		sc_start(&sd->bl, &sd->bl, SC_SPRITEMABLE, 100, 1, -1);
+
 	calculating = 0;
 
 	return 0;
@@ -4222,6 +4277,10 @@ void status_calc_regen_rate(struct block_list *bl, struct regen_data *regen, str
 		regen->rate.hp += (unsigned short)(regen->rate.hp * sc->data[SC_EXTRACT_WHITE_POTION_Z]->val1 / 100.);
 	if (sc->data[SC_VITATA_500])
 		regen->rate.sp += (unsigned short)(regen->rate.sp * sc->data[SC_VITATA_500]->val1 / 100.);
+	if (sc->data[SC_CATNIPPOWDER]) {
+		regen->rate.hp *= 2;
+		regen->rate.sp *= 2;
+	}
 }
 
 /**
@@ -4615,6 +4674,10 @@ void status_calc_bl_main(struct block_list *bl, /*enum scb_flag*/int flag)
 				// Any +MATK you get from skills and cards, including cards in weapon, is added here.
 				if (sd->bonus.ematk > 0)
 					status->matk_min += sd->bonus.ematk;
+				if (sd && pc_checkskill(sd, SU_POWEROFLAND) > 0) {
+					if (pc_checkskill(sd, SU_SV_STEMSPEAR) == 5 && pc_checkskill(sd, SU_CN_POWDERING) == 5 && pc_checkskill(sd, SU_CN_METEOR) == 5 && pc_checkskill(sd, SU_SV_ROOTTWIST) == 5)
+						status->matk_min += status->matk_min * 20 / 100;
+				}
 
 				status->matk_min = status_calc_ematk(bl, sc, status->matk_min);
 				status->matk_max = status->matk_min;
@@ -4644,6 +4707,9 @@ void status_calc_bl_main(struct block_list *bl, /*enum scb_flag*/int flag)
 					variance += status->lhw.matk * status->lhw.wlv / 10;
 				}
 
+				if (sc && sc->data[SC_CATNIPPOWDER])
+					wMatk -= wMatk * sc->data[SC_CATNIPPOWDER]->val2 / 100;
+
 				status->matk_min += wMatk - variance;
 				status->matk_max += wMatk + variance;
 				}
@@ -5085,6 +5151,8 @@ static unsigned short status_calc_agi(struct block_list *bl, struct status_chang
 		agi -= sc->data[SC_KYOUGAKU]->val2;
 	if(sc->data[SC_FULL_THROTTLE])
 		agi += agi * sc->data[SC_FULL_THROTTLE]->val3 / 100;
+	if (sc->data[SC_ARCLOUSEDASH])
+		agi += sc->data[SC_ARCLOUSEDASH]->val2;
 
 	return (unsigned short)cap_value(agi,0,USHRT_MAX);
 }
@@ -5423,6 +5491,8 @@ static unsigned short status_calc_batk(struct block_list *bl, struct status_chan
 		batk += sc->data[SC_QUEST_BUFF2]->val1;
 	if(sc->data[SC_QUEST_BUFF3])
 		batk += sc->data[SC_QUEST_BUFF3]->val1;
+	if (sc->data[SC_SHRIMP])
+		batk += batk * sc->data[SC_SHRIMP]->val2 / 100;
 
 	return (unsigned short)cap_value(batk,0,USHRT_MAX);
 }
@@ -5517,6 +5587,8 @@ static unsigned short status_calc_watk(struct block_list *bl, struct status_chan
 		watk += 40 + 30 * sc->data[SC_ODINS_POWER]->val1;
 	if (sc->data[SC_FLASHCOMBO])
 		watk += sc->data[SC_FLASHCOMBO]->val2;
+	if (sc->data[SC_CATNIPPOWDER])
+		watk -= watk * sc->data[SC_CATNIPPOWDER]->val2 / 100;
 
 	return (unsigned short)cap_value(watk,0,USHRT_MAX);
 }
@@ -5627,6 +5699,8 @@ static unsigned short status_calc_matk(struct block_list *bl, struct status_chan
 		matk += matk * sc->data[SC_MTF_MATK]->val1 / 100;
 	if(sc->data[SC_2011RWC_SCROLL])
 		matk += 30;
+	if (sc->data[SC_SHRIMP])
+		matk += matk * sc->data[SC_SHRIMP]->val2 / 100;
 
 	return (unsigned short)cap_value(matk,0,USHRT_MAX);
 }
@@ -6206,6 +6280,8 @@ static unsigned short status_calc_speed(struct block_list *bl, struct status_cha
 				val = max( val, 25 );
 			if( sc->data[SC_B_TRAP] )
 				val = max( val, sc->data[SC_B_TRAP]->val3 );
+			if (sc->data[SC_CATNIPPOWDER])
+				val = max(val, sc->data[SC_CATNIPPOWDER]->val3);
 
 			if( sd && sd->bonus.speed_rate + sd->bonus.speed_add_rate > 0 ) // Permanent item-based speedup
 				val = max( val, sd->bonus.speed_rate + sd->bonus.speed_add_rate );
@@ -6249,6 +6325,8 @@ static unsigned short status_calc_speed(struct block_list *bl, struct status_cha
 			val = max( val, sc->data[SC_WIND_STEP_OPTION]->val2 );
 		if( sc->data[SC_FULL_THROTTLE] )
 			val = max( val, 25 );
+		if (sc->data[SC_ARCLOUSEDASH])
+			val = max(val, sc->data[SC_ARCLOUSEDASH]->val3);
 
 		// !FIXME: official items use a single bonus for this [ultramage]
 		if( sc->data[SC_SPEEDUP0] ) // Temporary item-based speedup
@@ -7927,6 +8005,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 			return 0;
 	break;
 	case SC_KYRIE:
+	case SC_TUNAPARTY:
 		if (bl->type == BL_MOB)
 			return 0;
 	break;
@@ -8230,6 +8309,9 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 			case SC_MAGNETICFIELD:
 			case SC_NETHERWORLD:
 			case SC_VACUUM_EXTREME:
+			case SC_SV_ROOTTWIST:
+			case SC_BITESCAR:
+			case SC_FRESHSHRIMP:
 				return 0;
 		}
 	}
@@ -8712,6 +8794,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 		case SC_READYTURN:
 		case SC_DODGE:
 		case SC_PUSH_CART:
+		case SC_SPRITEMABLE:
 			tick = -1;
 			break;
 
@@ -10309,6 +10392,34 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 			if (bl->type != BL_PC)
 				val2 /= 5; //(custom) //kRO update 2012-02-12, reduce the rate for Non-Player target [Cydh]
 			break;
+		case SC_CATNIPPOWDER:
+			val2 = 50; // WATK%, MATK%
+			val3 = 25 * val1; // Move speed reduction
+			break;
+		case SC_BITESCAR:
+			val2 = 2 * val1; // MHP% damage
+			val4 = tick / 1000;
+			tick_time = 1000;
+			break;
+		case SC_ARCLOUSEDASH:
+			val2 = 15 + 5 * val1; // AGI
+			val3 = 25; // Move speed increase
+			if (sd && (sd->class_&MAPID_BASEMASK) == MAPID_SUMMONER)
+				val4 = 10; // Ranged ATK increase
+			break;
+		case SC_SHRIMP:
+			val2 = 10; // BATK%, MATK%
+			break;
+		case SC_FRESHSHRIMP:
+			val4 = tick / (10000 - ((val1 - 1) * 1000));
+			tick_time = 10000 - ((val1 - 1) * 1000);
+			if (val4 <= 0) // Prevents a negeative value from happening
+				val4 = 0;
+			break;
+		case SC_TUNAPARTY:
+			val2 = (status->max_hp * (val1 * 10) / 100); // %Max HP to absorb
+			//val3 = 6 + val1; // Hits !TODO: Does it have hits too?
+			break;
 
 		default:
 			if( calc_flag == SCB_NONE && StatusSkillChangeTable[type] == -1 && StatusIconChangeTable[type] == SI_BLANK ) {
@@ -10460,6 +10571,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 		case SC_KYOUGAKU:
 		case SC_PARALYSIS:
 		//case SC__CHAOS:
+		case SC_SV_ROOTTWIST:
 			unit_stop_walking(bl,1);
 			break;
 		case SC_CURSEDCIRCLE_TARGET:
@@ -10498,6 +10610,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 		case SC_SUMMER:
 		case SC_HANBOK:
 		case SC_OKTOBERFEST:
+		case SC_SUHIDE:
 			unit_stop_attack(bl);
 			break;
 		case SC_SILENCE:
@@ -10944,6 +11057,7 @@ int status_change_clear(struct block_list* bl, int type)
 			case SC_REUSE_CRUSHSTRIKE:
 			case SC_REUSE_STORMBLAST:
 			case SC_ALL_RIDING_REUSE_LIMIT:
+			case SC_SPRITEMABLE:
 				continue;
 			}
 		}
@@ -11381,6 +11495,7 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const
 			break;
 		case SC_NEUTRALBARRIER_MASTER:
 		case SC_STEALTHFIELD_MASTER:
+		case SC_SV_ROOTTWIST:
 			if( sce->val2 ) {
 				struct skill_unit_group* group = skill_id2group(sce->val2);
 				sce->val2 = 0;
@@ -12591,6 +12706,19 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data)
 			sce->val4 = 0;
 		}
 		break;
+	case SC_BITESCAR:
+		if (--(sce->val4) >= 0) {
+			status_percent_damage(bl, bl, -(sce->val2), 0, 0);
+			sc_timer_next(1000 + tick, status_change_timer, bl->id, data);
+			return 0;
+		}
+		break;
+	case SC_FRESHSHRIMP:
+		if (--(sce->val4) >= 0) {
+			status_heal(bl, status->max_hp / 100, 0, 2);
+			sc_timer_next((10000 - ((sce->val1 - 1) * 1000)) + tick, status_change_timer, bl->id, data);
+		}
+		break;
 	}
 
 	// If status has an interval and there is at least 100ms remaining time, wait for next interval
@@ -12823,6 +12951,8 @@ void status_change_clear_buffs (struct block_list* bl, int type)
 			case SC_REUSE_CRUSHSTRIKE:
 			case SC_REUSE_STORMBLAST:
 			case SC_ALL_RIDING_REUSE_LIMIT:
+			case SC_SPRITEMABLE:
+			case SC_BITESCAR:
 				continue;
 
 			// Debuffs that can be removed.

+ 31 - 0
src/map/status.h

@@ -740,6 +740,20 @@ typedef enum sc_type {
 	SC_ENERGY_DRINK_RESERCH,
 	SC_NORECOVER_STATE,
 
+	/**
+	 * Summoner
+	 */
+	SC_SUHIDE,
+	SC_SU_STOOP,
+	SC_SPRITEMABLE,
+	SC_CATNIPPOWDER,
+	SC_SV_ROOTTWIST,
+	SC_BITESCAR,
+	SC_ARCLOUSEDASH,
+	SC_TUNAPARTY,
+	SC_SHRIMP,
+	SC_FRESHSHRIMP,
+
 #ifdef RENEWAL
 	SC_EXTREMITYFIST2, //! NOTE: This SC should be right before SC_MAX, so it doesn't disturb if RENEWAL is disabled
 #endif
@@ -1606,6 +1620,7 @@ enum si_type {
 	SI_LIMIT_POWER_BOOSTER = 867,
 	SI_TIME_ACCESSORY = 872,
 	SI_EP16_DEF = 873,
+	SI_NORMAL_ATKED_SP = 874,
 	SI_BODYSTATE_STONECURSE = 875,
 	SI_BODYSTATE_FREEZING = 876,
 	SI_BODYSTATE_STUN = 877,
@@ -1623,6 +1638,10 @@ enum si_type {
 	SI_HEALTHSTATE_BLOODING = 889,
 	SI_HEALTHSTATE_HEAVYPOISON = 890,
 	SI_HEALTHSTATE_FEAR = 891,
+	SI_CHERRY_BLOSSOM_CAKE = 892,
+	SI_SU_STOOP = 893,
+	SI_CATNIPPOWDER = 894,
+	SI_SV_ROOTTWIST = 896,
 	SI_ATTACK_PROPERTY_NOTHING = 897,
 	SI_ATTACK_PROPERTY_WATER = 898,
 	SI_ATTACK_PROPERTY_GROUND = 899,
@@ -1643,6 +1662,14 @@ enum si_type {
 	SI_RESIST_PROPERTY_DARKNESS = 914,
 	SI_RESIST_PROPERTY_TELEKINESIS = 915,
 	SI_RESIST_PROPERTY_UNDEAD = 916,
+	SI_BITESCAR = 917,
+	SI_ARCLOUSEDASH = 918,
+	SI_TUNAPARTY = 919,
+	SI_SHRIMP = 920,
+	SI_FRESHSHRIMP = 921,
+	SI_PERIOD_RECEIVEITEM = 922,
+	SI_PERIOD_PLUSEXP = 923,
+	SI_PERIOD_PLUSJOBEXP = 924,
 	SI_RUNEHELM = 925,
 	SI_HELM_VERKANA = 926,
 	SI_HELM_RHYDO = 927,
@@ -1651,6 +1678,10 @@ enum si_type {
 	SI_HELM_ISIA = 930,
 	SI_HELM_ASIR = 931,
 	SI_HELM_URJ = 932,
+	SI_SUHIDE = 933,
+	SI_DORAM_BUF_01 = 935,
+	SI_DORAM_BUF_02 = 936,
+	SI_SPRITEMABLE = 937,
 	SI_MAX,
 };
 

+ 2 - 1
src/map/unit.c

@@ -1783,7 +1783,7 @@ int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill_id, ui
 		break;
 #endif
 		case GD_EMERGENCYCALL: // Emergency Call double cast when the user has learned Leap [Daegaladh]
-			if( sd && pc_checkskill(sd,TK_HIGHJUMP) )
+			if (sd && (pc_checkskill(sd,TK_HIGHJUMP) || pc_checkskill(sd,SU_LOPE) >= 3))
 				casttime *= 2;
 			break;
 		case RA_WUGDASH:
@@ -2881,6 +2881,7 @@ int unit_remove_map_(struct block_list *bl, clr_type clrtype, const char* file,
 		status_change_end(bl, SC__MANHOLE, INVALID_TIMER);
 		status_change_end(bl, SC_VACUUM_EXTREME, INVALID_TIMER);
 		status_change_end(bl, SC_CURSEDCIRCLE_ATKER, INVALID_TIMER); // callme before warp
+		status_change_end(bl, SC_SUHIDE, INVALID_TIMER);
 	}
 
 	if (bl->type&(BL_CHAR|BL_PET)) {

部分文件因为文件数量过多而无法显示