Sfoglia il codice sorgente

Skill Changes:
* Wizard/Warlock Skill
* Moved Sightrasher (WZ_SIGHTRASHER) requirement to check Sight (SC_SIGHT) is active or not to skill_check_condition_castend section.
* Fixed Sightrasher (WZ_SIGHTRASHER) splash area to 3x3. (bugreport:9298)
* Now Comet (WL_COMET) cannot hits Hiding target (The mistake is not at flag 0x10000 in skill_db.txt, the flash should be added by SD_ANIMATION). (bugreport:8909).
* Now Reading Spell Book (WL_READING_SB) checking the number of available spell books in Spell Book DB first to prevent infinite loop.
* Sage Skill
* Now Abracadabra (SA_ABRACADABRA) checking the number of available skills in Abra DB first to prevent infinite loop.
* Reduced MAX_SKILL_ABRA_DB from 350 to 160.
* Shadow Chaser Skill
* Fixed Chaos Panic (SC_CHAOSPANIC) effect. (bugreport:9321).
* Genetic Skill
* Now Wall of Thorn (GN_WALLOFTHORN) can be knocked back but not a whole skill group and durability (HP & max hit) for each skill unit.
* Guillotine Cross Skill
* Now Magic Mushroom (SC_MAGICMUSHROOM) effect checks the number of available skills in Magic Mushroom DB first to prevent infinite loop.
* Changed 'RemoveFlag' in db/magicmushroom_db.txt value to 1 to remove skill by importing. (bugreport:9322).
* Wanderer/Minstrel Skill
* Now Randomize Spell (WM_RANDOMIZESPELL) checks the number of available skills in Improvise DB first to prevent infinite loop.
* Reduced MAX_SKILL_IMPROVISE_DB from 50 to 30.
* Rebellion Skill
* Cleaned up, added, corrected some (missing) sequences & DB values.
* Fixed Hammer of God (RL_HAMMER_OF_GOD) splash damage.
* Fixed Shaterred Strom (RL_S_STORM) push back & force to sit effect (for player, or stun for monsters) (first implementation leftover).
* Fixed Slug Shot (RL_SLUGSHOT) hitrate-distance penalty (first implementation leftover).
* Fixed Howling Mine (RL_H_MINE) damage ratios (first implementation leftover).
* Now Bind Trap (RL_B_TRAP) only can be placed 1 at same time.
* Fixed Bind Trap (RL_B_TRAP) damage calculation by using Caster's DEX, Target's Current HP, & Skill Level. FIXME: Exact formula still unknown (refers to idAthena formula).
* Now Dragon Tail (RL_D_TAIL) doesn't split damage among targets anymore.
* Now Crimson Marker (RL_C_MARKER) will fails to cast if no slot available.
* Implemented official packet `ZC_C_MARKERINFO` of Crimson Marker (RL_C_MARKER) mini-map marker (first implementation leftover). !TODO: Confirm the packet for older or newer clients (idAthena partial merge r1497)
* References: http://forums.irowiki.org/showpost.php?p=1387992&postcount=968, follow up 507f047, dd67f9d

Misc:
* Fixed some skills that should work only in shoot range (map_foreachinshootange, by default), and added check for respecting *skill_wall_check* (map_foreachinrange).
* Fixed item stackable check for `/item` command, follow up 9b4d922.
* Fixed npc source file isn't removed properly by @unloadnpcfile. (bugreport:9311).
* Added constantan for status_change_start() and sc_start() scripts as well
* SCSTART_NONE = 0x0
* SCSTART_NOAVOID = 0x1
* SCSTART_NOTICKDEF = 0x2
* SCSTART_LOADED = 0x4
* SCSTART_NORATEDEF = 0x8
* SCSTART_NOICON = 0x10
* Moved and changed itemdb_unique_id() to pc_generate_unique_id().
* Seperated check for skill SC requirement to skill_check_condition_sc_required().
* Added skill unit flag `UF_KNOCKBACK_GROUP`, just an option to make skill unit can be knocked back a whole group.
* Typos and other minor changes!

Signed-off-by: Cydh Ramdh <house.bad@gmail.com>

Cydh Ramdh 10 anni fa
parent
commit
ce090ce916

+ 1 - 1
db/import-tmpl/magicmushroom_db.txt

@@ -4,5 +4,5 @@
 // Structure of Database:
 // SkillID{,RemoveFlag}
 //
-// - To remove entry by importing, put any value on 'RemoveFlag'
+// - To remove entry by importing, put 1 value on 'RemoveFlag'
 

+ 1 - 1
db/magicmushroom_db.txt

@@ -4,7 +4,7 @@
 // Structure of Database:
 // SkillID{,RemoveFlag}
 //
-// - To remove entry by importing, put any value on 'RemoveFlag'
+// - To remove entry by importing, put 1 value on 'RemoveFlag'
 
 7	//SM_MAGNUM
 8	//SM_ENDURE

+ 5 - 3
db/packet_db.txt

@@ -2244,6 +2244,7 @@ packet_ver: 45
 0x023B,26,friendslistadd,2
 0x0361,5,hommenu,2:4
 0x0887,36,storagepassword,2:4:20
+0x09C1,10,ZC_C_MARKERINFO,2:6:8
 
 //2013-12-23Ragexe
 packet_ver: 46
@@ -2277,13 +2278,14 @@ packet_ver: 46
 0x0361,5,hommenu,2:4
 0x08A4,36,storagepassword,2:4:20
 //New Packets
-0x09D4,2,dull,0 //npcshopclosed
+//0x097E,12 //ZC_UPDATE_RANKING_POINT
+0x09B4,6,dull,0 //Cash Shop - Special Tab
 0x09CE,102,itemmonster,2
+0x09D4,2,dull,0 //npcshopclosed
 //NPC Market
-0x09D8,2,dull,0 //npcmarketclosed
 0x09D6,-1,dull,0 //npcmarketpurchase
+0x09D8,2,dull,0 //npcmarketclosed
 0x09DF,7
-0x09B4,6,dull,0 // Cash Shop - Special Tab
 
 //Add new packets here
 //packet_ver: 47

+ 19 - 18
db/pre-re/skill_unit_db.txt

@@ -6,22 +6,23 @@
 // layout = -1:special, 0:1*1, 1:3*3, 2:5*5, up to 5:11*11
 // target = friend (party +guildmates +neutral players) / party / guild
 //          ally (party +guildmates) / all / sameguild (guild but no allies) / enemy
-// flag 0x0001(UF_DEFNOTENEMY)		If 'defunit_not_enemy' is set, the target is changed to 'friend'
-//      0x0002(UF_NOREITERRATION)	Spell cannot be stacked
-//      0x0004(UF_NOFOOTSET)		Spell cannot be cast near/on targets
-//      0x0008(UF_NOOVERLAP)		Spell effects do not overlap
-//      0x0010(UF_PATHCHECK)		Only cells with a shootable path will be placed
-//      0x0020(UF_NOPC)				Spell cannot affect players.
-//      0x0040(UF_NOMOB)			Spell cannot affect mobs.
-//      0x0080(UF_SKILL)			Spell CAN affect skills.
-//      0x0100(UF_DANCE)			Dance skill
-//      0x0200(UF_ENSEMBLE)			Ensemble skill
-//      0x0400(UF_SONG)				Song skill
-//      0x0800(UF_DUALMODE)			Spell has effects both at an interval and when you step in/out
-//      0x1000(UF_NOKNOCKBACK)		Cannot be knocked back (only unit that can be damaged)
-//      0x2000(UF_RANGEDSINGLEUNIT)	Layout hack, use layout range propriety but only display center.
-//      0x4000(UF_REM_CRAZYWEED)	Removed if be overlapped by GN_CRAZYWEED
-//      0x8000(UF_REM_FIRERAIN)		Removed if be overlapped by RL_FIRE_RAIN
+// flag 0x00001(UF_DEFNOTENEMY)			If 'defunit_not_enemy' is set, the target is changed to 'friend'
+//      0x00002(UF_NOREITERRATION)		Spell cannot be stacked
+//      0x00004(UF_NOFOOTSET)			Spell cannot be cast near/on targets
+//      0x00008(UF_NOOVERLAP)			Spell effects do not overlap
+//      0x00010(UF_PATHCHECK)			Only cells with a shootable path will be placed
+//      0x00020(UF_NOPC)				Spell cannot affect players.
+//      0x00040(UF_NOMOB)				Spell cannot affect mobs.
+//      0x00080(UF_SKILL)				Spell CAN affect skills.
+//      0x00100(UF_DANCE)				Dance skill
+//      0x00200(UF_ENSEMBLE)			Ensemble skill
+//      0x00400(UF_SONG)				Song skill
+//      0x00800(UF_DUALMODE)			Spell has effects both at an interval and when you step in/out
+//      0x01000(UF_NOKNOCKBACK)			Cannot be knocked back (only unit that can be damaged)
+//      0x02000(UF_RANGEDSINGLEUNIT)	Layout hack, use layout range propriety but only display center.
+//      0x04000(UF_REM_CRAZYWEED)		Removed if be overlapped by GN_CRAZYWEED
+//      0x08000(UF_REM_FIRERAIN)		Removed if be overlapped by RL_FIRE_RAIN
+//      0x10000(UF_KNOCKBACK_GROUP) 	Knock back a whole skill group (by default, skill unit is knocked back each unit)
 // 	Example: 0x006 = 0x002+0x004 -> Cannot be stacked nor cast near targets
 //
 // Notes:
@@ -126,7 +127,7 @@
 
 2299,0xcc,    ,  0, 1,1000,all,   0xC006 //SC_MANHOLE
 2300,0xcd,    ,  0, 0,1000,all,   0xC006 //SC_DIMENSIONDOOR
-2301,0xce,    ,  2, 0,  -1,all,   0xE00E //SC_CHAOSPANIC
+2301,0xce,    ,  2, 0,1000,all,   0xE00E //SC_CHAOSPANIC
 2302,0xcf,    ,  2, 0,  -1,all,   0xE002 //SC_MAELSTROM
 2303,0xd0,    ,  3, 0,  -1,all,   0xE058 //SC_BLOODYLUST
 2304,0xd1,    ,  0, 2, 500,enemy, 0x018  //SC_FEINTBOMB
@@ -151,7 +152,7 @@
 2468,0xf4,    ,  0, 1,1000,all,   0x010	//SO_EARTH_INSIGNIA
 
 2479,0xe5,    ,  0, 1,1000,enemy, 0xC006	//GN_THORNS_TRAP
-2482,0xe6,0x7f, -1, 1, 300,enemy, 0xD000	//GN_WALLOFTHORN
+2482,0xe6,0x7f, -1, 1, 300,enemy, 0xC000	//GN_WALLOFTHORN
 2484,0x86,    ,  0, 1, 100,enemy, 0x080	//GN_CRAZYWEED_ATK
 2485,0xe7,    ,  0, 2,2000,enemy, 0x8098	//GN_DEMONIC_FIRE
 2487,0xe8,    ,  2, 0,  -1,enemy, 0x2000	//GN_FIRE_EXPANSION_SMOKE_POWDER

+ 9 - 9
db/re/skill_cast_db.txt

@@ -1643,11 +1643,11 @@
 //-- RL_RICHS_COIN
 2552,0,1000,0,600000,0,0,-1
 //-- RL_MASS_SPIRAL
-2553,0,1000,0,0,30000,1000,-1
+2553,2000,1000,0,0,30000,1000,-1
 //-- RL_BANISHING_BUSTER
 2554,3000:2500:2000:1500:1000,1000,0,0,0,1500,-1
 //-- RL_B_TRAP
-2555,0,0,0,10000:11000:12000:13000:14000,0,2000,-1
+2555,0,0,0,4000,6000:7000:8000:9000:10000,2000,-1
 //-- RL_FLICKER
 2556,0,500,0,0,0,2000,-1
 //-- RL_S_STORM
@@ -1659,27 +1659,27 @@
 //-- RL_C_MARKER
 2560,0,0,0,30000,0,1000,-1
 //-- RL_FIREDANCE
-2561,0,1500,0,0,0,5000,-1
+2561,1600:1500:1400:1200:1000,1500,0,0,0,5000,-1
 //-- RL_H_MINE
-2562,0,1500,0,30000,15000,2000,-1
+2562,2000,1500,0,30000,15000,5000:4500:4000:3500:3000,-1
 //-- RL_P_ALTER
-2563,0,1000,0,60000,0,5000,-1
+2563,0,1000,0,30000:45000:60000:75000:90000,0,5000,-1
 //-- RL_FALLEN_ANGEL
 2564,0,1500,0,0,0,4500:4000:3500:2500:2000,-1
 //-- RL_R_TRIP
 2565,0,1500,0,0,0,3000,-1
 //-- RL_D_TAIL
-2566,0,1500,0,0,0,5000,-1
+2566,2000,1500,0,0,0,5000,-1
 //-- RL_FIRE_RAIN
 2567,0,1500,0,100,0,5000,-1
 //-- RL_HEAT_BARREL
 2568,0,1000,0,60000,10000,10000,-1
 //-- RL_AM_BLAST
-2569,2000,1500,0,0,6000:7000:8000:9000:10000,1000,-1
+2569,2000,1500,0,0,6000:7000:8000:9000:10000,1000,1000
 //-- RL_SLUGSHOT
-2570,5000:6000:7000:8000:9000,1000,0,0,10000,1500,1000
+2570,5000:6000:7000:8000:9000,1000,0,2000,0,1500,1000
 //-- RL_HAMMER_OF_GOD
-2571,0,1000,0,0,3000:3000:4000:4000:5000,3000,-1
+2571,3000,1000,0,0,3000:3000:4000:4000:5000,3000,-1
 //-- RL_R_TRIP_PLUSATK
 //2572,0,0,0,0,0,0,-1
 //-- RL_B_FLICKER_ATK

+ 15 - 15
db/re/skill_db.txt

@@ -864,7 +864,7 @@
 1003,0,0,0,0,0,0,1,0,no,0,0x1,0,weapon,0,0x0,	AS_SONICACCEL,Sonic Acceleration
 1004,9,8,1,0,0x8,0,1,1,no,0,0x1,0,weapon,0,0x0,	AS_VENOMKNIFE,Throw Venom Knife
 1005,1,6,1,0,0x1,0,1,1,no,0,0x1,0,weapon,0,0x0,	RG_CLOSECONFINE,Close Confine
-1006,0,6,4,3,0,2,1,1,yes,0,0x1,0,magic,3,0x20,	WZ_SIGHTBLASTER,Sight Blaster
+1006,0,6,4,3,0,1,1,1,yes,0,0x1,0,magic,3,0x20,	WZ_SIGHTBLASTER,Sight Blaster
 1007,0,6,4,0,0x1,0,1,0,no,0,0x1,0,none,0,0x0,	SA_CREATECON,Create Elemental Converter
 1008,9,6,1,1,0x1,0,1,1,yes,0,0x1,0,magic,0,0x0,	SA_ELEMENTWATER,Elemental Change Water
 1009,-9,6,1,0,0,0,1,1,no,0,0x1,0,weapon,3,0x0,	HT_PHANTASMIC,Phantasmic Arrow
@@ -1235,25 +1235,25 @@
 // Rebellion
 //2551,0,0,0,0,0,0,10,0,no,0,0,0,none,0,0,	RL_GLITTERING_GREED,Flip The Coin Greed
 2552,0,6,4,0,0x1,0,1,1,no,0,0,0,none,0,0x0,	RL_RICHS_COIN,Rich's Coin
-2553,15,6,1,-1,0,0,5,1,no,0,0,0,weapon,0,0x0,	RL_MASS_SPIRAL,Mass Spiral
-2554,9,6,1,-1,0x2,2,5,1,no,0,0,0,weapon,0,0x0,	RL_BANISHING_BUSTER,Banishing Buster
-2555,3,6,2,0,0x1,1,5,1,no,0,0,3,misc,0,0x0,	RL_B_TRAP,Bind Trap
+2553,-9,6,1,-1,0,0,5,1,no,0,0,0,weapon,0,0x0,	RL_MASS_SPIRAL,Mass Spiral
+2554,-9,6,1,-1,0x2,2,5,1,no,0,0,0,weapon,0,0x0,	RL_BANISHING_BUSTER,Banishing Buster
+2555,3:4:4:5:5,6,2,0,0x1,1,5,1,no,0,0,1,misc,0,0x0,	RL_B_TRAP,Bind Trap
 2556,0,6,4,0,0x3,-1,1,1,no,0,0,0,none,0,0x0,	RL_FLICKER,Flicker
-2557,9,6,1,-1,0x2,2,5,1,no,0,0,0,weapon,0,0x0,	RL_S_STORM,Shatter Storm
+2557,-9,6,1,-1,0x2,2,5,1,no,0,0,0,weapon,0,0x0,	RL_S_STORM,Shatter Storm
 2558,0,6,4,0,0x1,0,10,1,no,0,0,0,none,0,0x0,	RL_E_CHAIN,Eternal Chain
-2559,-9,6,4,-1,0x3,21,1,1,no,0,0x0,0,weapon,0,0x0,	RL_QD_SHOT,Quick Draw Shot
-2560,11,6,1,0,0x1,0,1,1,no,0,0,3,none,0,0x0,	RL_C_MARKER,Crimson Marker
-2561,0,6,4,-1,0x2,2,5,1,no,0,0,0,weapon,0,0x0,	RL_FIREDANCE,Fire Dance
-2562,7:8:9:10:11,6,1,-1,0x2,2,5,1,no,0,0,0,weapon,0,0x0,	RL_H_MINE,Howling Mine
+2559,-9,6,4,-1,0x0,10,1,1,no,0,0x0,0,weapon,0,0x0,	RL_QD_SHOT,Quick Draw Shot
+2560,-9,6,1,0,0x1,0,1,1,no,0,0,3,none,0,0x0,	RL_C_MARKER,Crimson Marker
+2561,0,6,4,-1,0x2,3,5,1,no,0,0,0,weapon,0,0x0,	RL_FIREDANCE,Fire Dance
+2562,-9,6,1,-1,0x0,2,5,1,no,0,0,0,weapon,0,0x0,	RL_H_MINE,Howling Mine
 2563,0,6,4,0,0x1,0,5,1,no,0,0,0,none,0,0x0,	RL_P_ALTER,Platinum Alter
-2564,9,6,2,0,0x1,0,5,1,no,0,0,0,none,0,0x0,	RL_FALLEN_ANGEL,Fallen Angel
+2564,-9,6,2,0,0x1,0,5,1,no,0,0,0,none,0,0x0,	RL_FALLEN_ANGEL,Fallen Angel
 2565,0,6,4,-1,0x2,3:3:4:5:6,5,1,no,0,0,0,weapon,3,0x0,	RL_R_TRIP,Round Trip
 2566,0,6,4,-1,0x3,-1,5,1,no,0,0,0,weapon,0,0x0,	RL_D_TAIL,Dragon Tail
-2567,9,6,2,-1,0x2,1,5,1,no,0,0,0,weapon,0,0,	RL_FIRE_RAIN,Fire Rain
+2567,-9,6,2,-1,0x2,1,5,1,no,0,0,0,weapon,0,0,	RL_FIRE_RAIN,Fire Rain
 2568,0,6,4,0,0x1,0,5,1,no,0,0,0,none,0,0x0,	RL_HEAT_BARREL,Heat Barrel
-2569,9,6,1,-1,0,0,5,1,no,0,0,0,weapon,0,0x0,	RL_AM_BLAST,Anti-Material Blast
-2570,9,6,1,-1,0,0,5,1,no,0,0,0,weapon,0,0x0,	RL_SLUGSHOT,Slug Shot
-2571,7:8:9:10:11,6,2,-1,0x2,2,5,1,no,0,0,0,weapon,0,0x0,	RL_HAMMER_OF_GOD,Hammer of God
+2569,-9,6,1,-1,0,0,5,1,no,0,0,0,weapon,0,0x0,	RL_AM_BLAST,Anti-Material Blast
+2570,-9,6,1,-1,0,0,5,1,no,0,0,0,weapon,6,0x0,	RL_SLUGSHOT,Slug Shot
+2571,-9,6,2,-1,0x2,2,5,1,no,0,0,0,weapon,0,0x0,	RL_HAMMER_OF_GOD,Hammer of God
 2572,0,6,1,-1,0x40,0,5,1,no,0,0,0,weapon,0,0,	RL_R_TRIP_PLUSATK,Round Trip Plus Attack
 //2573,0,6,1,-1,0,0,5,1,no,0,0,0,weapon,0,0,	RL_B_FLICKER_ATK,Bind Flicker Attack
 //2574,0,6,1,-1,0,0,10,1,no,0,0,0,weapon,0,0,	RL_GLITTERING_GREED_ATK,Flip The Coin Greed Attack
@@ -1266,7 +1266,7 @@
 3004,3:4:5:6:7,8,1,-1,0,0,5,-2,no,0,0,0,weapon,0,0x0,	KO_JYUMONJIKIRI,Cross Strike
 3005,2,6,1,-1,0,0,5,1,no,0,0,0,weapon,0,0x0,		KO_SETSUDAN,Soul Sever
 3006,7:8:9:10:11,6,2,-1,0x42,2,5,1,no,0,0,0,weapon,0,0x0,	KO_BAKURETSU,Bakuretsu Kunai
-3007,5,6,4,-1,0x42,4:4:4:4:5,5,1,no,0,0,0,weapon,0,0x0,	KO_HAPPOKUNAI,Happo Kunai
+3007,0,6,4,-1,0x42,4:4:4:4:5,5,1,no,0,0,0,weapon,0,0x0,	KO_HAPPOKUNAI,Happo Kunai
 3008,11,8,2,0,0x56,1:1:1:1:1:1:1:1:1:2,10,-10,no,0,0,0,misc,0,0x0,	KO_MUCHANAGE,Mucha Nage
 3009,9:10:11:12:13,8,2,-1,0x2,3,5,2,no,0,0,0,weapon,0,0x0,	KO_HUUMARANKA,Huuma Shuriken Ranka 
 3010,3,6,4,0,0x52,0,5,1,no,0,0x80,0,weapon,0,0x10,	KO_MAKIBISHI,Makibishi

+ 1 - 1
db/re/skill_require_db.txt

@@ -896,7 +896,7 @@
 2554,0,0,55:60:65:70:75,0,0,0,20,3,1,none,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0					//RL_BANISHING_BUSTER
 2555,0,0,30:32:34:36:38,0,0,0,17:18:19:20:21,0,0,none,0,1,7940,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0	//RL_B_TRAP
 2556,0,0,2,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								//RL_FLICKER
-2557,0,0,55:60:65:70:75,0,0,0,20,3,1,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0					//RL_S_STORM
+2557,0,0,55:60:65:70:75,0,0,0,20,3,1,none,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0					//RL_S_STORM
 2558,0,0,45,0,0,0,17:18:19:20:21,0,0,none,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0				//RL_E_CHAIN
 2559,0,0,5,0,0,0,17:18:19:20:21,3:4:5,1,none,SC_QD_SHOT_READY,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0	//RL_QD_SHOT
 2560,0,0,10,0,0,0,17:18:19:20:21,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					//RL_C_MARKER

+ 20 - 19
db/re/skill_unit_db.txt

@@ -6,22 +6,23 @@
 // layout = -1:special, 0:1*1, 1:3*3, 2:5*5, up to 5:11*11
 // target = friend (party +guildmates +neutral players) / party / guild
 //          ally (party +guildmates) / all / sameguild (guild but no allies) / enemy
-// flag 0x0001(UF_DEFNOTENEMY)		If 'defunit_not_enemy' is set, the target is changed to 'friend'
-//      0x0002(UF_NOREITERRATION)	Spell cannot be stacked
-//      0x0004(UF_NOFOOTSET)		Spell cannot be cast near/on targets
-//      0x0008(UF_NOOVERLAP)		Spell effects do not overlap
-//      0x0010(UF_PATHCHECK)		Only cells with a shootable path will be placed
-//      0x0020(UF_NOPC)				Spell cannot affect players.
-//      0x0040(UF_NOMOB)			Spell cannot affect mobs.
-//      0x0080(UF_SKILL)			Spell CAN affect skills.
-//      0x0100(UF_DANCE)			Dance skill
-//      0x0200(UF_ENSEMBLE)			Ensemble skill
-//      0x0400(UF_SONG)				Song skill
-//      0x0800(UF_DUALMODE)			Spell has effects both at an interval and when you step in/out
-//      0x1000(UF_NOKNOCKBACK)		Cannot be knocked back (only unit that can be damaged)
-//      0x2000(UF_RANGEDSINGLEUNIT)	Layout hack, use layout range propriety but only display center.
-//      0x4000(UF_REM_CRAZYWEED)	Removed if be overlapped by GN_CRAZYWEED
-//      0x8000(UF_REM_FIRERAIN)		Removed if be overlapped by RL_FIRE_RAIN
+// flag 0x00001(UF_DEFNOTENEMY)			If 'defunit_not_enemy' is set, the target is changed to 'friend'
+//      0x00002(UF_NOREITERRATION)		Spell cannot be stacked
+//      0x00004(UF_NOFOOTSET)			Spell cannot be cast near/on targets
+//      0x00008(UF_NOOVERLAP)			Spell effects do not overlap
+//      0x00010(UF_PATHCHECK)			Only cells with a shootable path will be placed
+//      0x00020(UF_NOPC)				Spell cannot affect players.
+//      0x00040(UF_NOMOB)				Spell cannot affect mobs.
+//      0x00080(UF_SKILL)				Spell CAN affect skills.
+//      0x00100(UF_DANCE)				Dance skill
+//      0x00200(UF_ENSEMBLE)			Ensemble skill
+//      0x00400(UF_SONG)				Song skill
+//      0x00800(UF_DUALMODE)			Spell has effects both at an interval and when you step in/out
+//      0x01000(UF_NOKNOCKBACK)			Cannot be knocked back (only unit that can be damaged)
+//      0x02000(UF_RANGEDSINGLEUNIT)	Layout hack, use layout range propriety but only display center.
+//      0x04000(UF_REM_CRAZYWEED)		Removed if be overlapped by GN_CRAZYWEED
+//      0x08000(UF_REM_FIRERAIN)		Removed if be overlapped by RL_FIRE_RAIN
+//      0x10000(UF_KNOCKBACK_GROUP) 	Knock back a whole skill group (by default, skill unit is knocked back each unit)
 // 	Example: 0x006 = 0x002+0x004 -> Cannot be stacked nor cast near targets
 //
 // Notes:
@@ -128,8 +129,8 @@
 
 2299,0xcc,    ,  0, 1,1000,all,   0xC006 //SC_MANHOLE
 2300,0xcd,    ,  0, 0,1000,all,   0xC006 //SC_DIMENSIONDOOR
-2301,0xce,    ,  2, 0,  -1,all,   0xC00E //SC_CHAOSPANIC
-2302,0xcf,    ,  2, 0,  -1,all,   0xC002 //SC_MAELSTROM
+2301,0xce,    ,  2, 0,1000,all,   0xE00E //SC_CHAOSPANIC
+2302,0xcf,    ,  2, 0,  -1,all,   0xE002 //SC_MAELSTROM
 2303,0xd0,    ,  3, 0,  -1,all,   0xE058 //SC_BLOODYLUST
 2304,0xd1,    ,  0, 2, 500,enemy, 0x018  //SC_FEINTBOMB
 
@@ -153,7 +154,7 @@
 2468,0xf4,    ,  0, 1,1000,all,   0x010	//SO_EARTH_INSIGNIA
 
 2479,0xe5,    ,  0, 1,1000,enemy, 0xC006	//GN_THORNS_TRAP
-2482,0xe6,0x7f, -1, 1, 300,enemy, 0xD000	//GN_WALLOFTHORN
+2482,0xe6,0x7f, -1, 1, 300,enemy, 0xC000	//GN_WALLOFTHORN
 2484,0x86,    ,  0, 1, 100,enemy, 0x080	//GN_CRAZYWEED_ATK
 2485,0xe7,    ,  0, 2,2000,enemy, 0x8098	//GN_DEMONIC_FIRE
 2487,0xe8,    ,  2, 0,  -1,enemy, 0x2000	//GN_FIRE_EXPANSION_SMOKE_POWDER

+ 2 - 2
src/config/const.h

@@ -100,8 +100,8 @@
 // Renewal variable cast time reduction
 #ifdef RENEWAL_CAST
 	#define VARCAST_REDUCTION(val){ \
-		if( (varcast_r += val) != 0 && varcast_r >= 0 ) \
-			time = time * (1 - (float)min(val, 100) / 100); \
+		if( (varcast_r += (val)) != 0 && varcast_r >= 0 ) \
+			time = time * (1 - (float)min((val), 100) / 100); \
 	}
 #endif
 /**

+ 1 - 1
src/map/atcommand.c

@@ -5775,7 +5775,7 @@ ACMD_FUNC(autotrade) {
 
 	if( battle_config.at_timeout ) {
 		int timeout = atoi(message);
-		status_change_start(NULL,&sd->bl, SC_AUTOTRADE, 10000, 0, 0, 0, 0, ((timeout > 0) ? min(timeout,battle_config.at_timeout) : battle_config.at_timeout) * 60000, 0);
+		status_change_start(NULL,&sd->bl, SC_AUTOTRADE, 10000, 0, 0, 0, 0, ((timeout > 0) ? min(timeout,battle_config.at_timeout) : battle_config.at_timeout) * 60000, SCSTART_NONE);
 	}
 
 	channel_pcquit(sd,0xF); //leave all chan

+ 29 - 18
src/map/battle.c

@@ -347,16 +347,16 @@ int64 battle_attr_fix(struct block_list *src, struct block_list *target, int64 d
 	if (sc && sc->count) { //increase dmg by src status
 		switch(atk_elem){
 			case ELE_FIRE:
-				if(sc->data[SC_VOLCANO]) ratio += enchant_eff[sc->data[SC_VOLCANO]->val1-1];
+				if (sc->data[SC_VOLCANO]) ratio += sc->data[SC_VOLCANO]->val3;
 				break;
 			case ELE_WIND:
-				if(sc->data[SC_VIOLENTGALE]) ratio += enchant_eff[sc->data[SC_VIOLENTGALE]->val1-1];
+				if (sc->data[SC_VIOLENTGALE]) ratio += sc->data[SC_VIOLENTGALE]->val3;
 				break;
 			case ELE_WATER:
-				if(sc->data[SC_DELUGE]) ratio += enchant_eff[sc->data[SC_DELUGE]->val1-1];
+				if (sc->data[SC_DELUGE]) ratio += sc->data[SC_DELUGE]->val3;
 				break;
 			case ELE_GHOST:
-				if(sc->data[SC_TELEKINESIS_INTENSE]) ratio += (sc->data[SC_TELEKINESIS_INTENSE]->val3);
+				if (sc->data[SC_TELEKINESIS_INTENSE]) ratio += (sc->data[SC_TELEKINESIS_INTENSE]->val3);
 				break;
 		}
 	}
@@ -886,7 +886,7 @@ int64 battle_calc_damage(struct block_list *src,struct block_list *bl,struct Dam
 					else
 						sce->val3 = 1000; // Next shield
 				}
-				status_change_start(src,bl,SC_STUN,10000,0,0,0,0,1000,2);
+				status_change_start(src,bl,SC_STUN,10000,0,0,0,0,1000,SCSTART_NOTICKDEF);
 			}
 			return 0;
 		}
@@ -2247,8 +2247,15 @@ static bool is_attack_hitting(struct Damage wd, struct block_list *src, struct b
 				hitrate -= 35 - 5 * skill_lv;
 				break;
 			case RL_SLUGSHOT:
-				if (distance_bl(src,target) > 3)
-					hitrate -= (10 - (skill_lv - 1));
+				{
+					int8 dist = distance_bl(src, target);
+					if (dist > 3) {
+						// Reduce n hitrate for each cell after initial 3 cells. Different each level
+						// -10:-9:-8:-7:-6
+						dist -= 3;
+						hitrate -= ((11 - skill_lv) * dist);
+					}
+				}
 				break;
 		}
 	} else if (sd && wd.type&DMG_MULTI_HIT && wd.div_ == 2) // +1 hit per level of Double Attack on a successful double attack (making sure other multi attack skills do not trigger this) [helvetica]
@@ -2422,7 +2429,7 @@ static int battle_get_weapon_element(struct Damage wd, struct block_list *src, s
 				element = ELE_HOLY;
 			break;
 		case RL_H_MINE:
-			if (sd && sd->skill_id_old == RL_FLICKER) //Force RL_H_MINE deals fire damage if activated by RL_FLICKER
+			if (sd && sd->flicker) //Force RL_H_MINE deals fire damage if activated by RL_FLICKER
 				element = ELE_FIRE;
 			break;
 	}
@@ -3034,9 +3041,10 @@ static int battle_calc_attack_skill_ratio(struct Damage wd, struct block_list *s
 			skillratio += -100 + sc->data[SC_EXEEDBREAK]->val1;
 			status_change_end(src,SC_EXEEDBREAK,INVALID_TIMER);
 		}
-		if(sc->data[SC_HEAT_BARREL])
+		//!TODO: Verify this placement & skills that affected by these effects [Cydh]
+		if (sc->data[SC_HEAT_BARREL])
 			skillratio += 200;
-		if(sc->data[SC_P_ALTER])
+		if (sc->data[SC_P_ALTER])
 			skillratio += sc->data[SC_P_ALTER]->val2;
 	}
 
@@ -3858,9 +3866,11 @@ static int battle_calc_attack_skill_ratio(struct Damage wd, struct block_list *s
 		 * Rebellion
 		 **/
 		case RL_MASS_SPIRAL:
+			// 200%:400%:600%:800%:1000%
 			skillratio += -100 + (200 * skill_lv);
 			break;
 		case RL_FIREDANCE:
+			// 100%:200%:300%:400%:500% (+Level ??)
 			skillratio += -100 + (100 * skill_lv);
 			skillratio += (skillratio * status_get_lv(src)) / 300; //(custom)
 			break;
@@ -3873,7 +3883,7 @@ static int battle_calc_attack_skill_ratio(struct Damage wd, struct block_list *s
 		case RL_SLUGSHOT:
 			{
 				uint16 w = 50;
-				int16 idx = 0;
+				int16 idx = -1;
 				if (sd && (idx = sd->equip_index[EQI_AMMO]) >= 0 && sd->inventory_data[idx])
 					w = sd->inventory_data[idx]->weight;
 				w /= 10;
@@ -3881,9 +3891,8 @@ static int battle_calc_attack_skill_ratio(struct Damage wd, struct block_list *s
 			}
 			break;
 		case RL_D_TAIL:
+			// 3000%:3500%:4000%:4500%:5000%
 			skillratio += -100 + (2500 + 500 * skill_lv );
-			//if (sd && &sd->c_marker)
-			//	skillratio /= max(sd->c_marker.count,1);
 			break;
 		case RL_R_TRIP:
 			skillratio += -100 + (150 * skill_lv); //(custom)
@@ -3892,10 +3901,11 @@ static int battle_calc_attack_skill_ratio(struct Damage wd, struct block_list *s
 			skillratio += -100 + (50 * skill_lv); //(custom)
 			break;
 		case RL_H_MINE:
-			skillratio += 100 + (200 * skill_lv);
-			//If damaged by Flicker
-			if (sd && sd->skill_id_old == RL_FLICKER && tsc && tsc->data[SC_H_MINE] && tsc->data[SC_H_MINE]->val2 == src->id)
-				skillratio += 400 + (300 * skill_lv);
+			// 400%:600%:800%:1000%:1200%
+			skillratio += -100 + (200 + 200 * skill_lv);
+			//If damaged by Flicker, explosion damage (800%:1100%:1400%:1700%:2000%)
+			if (sd && sd->flicker)
+				skillratio += 300 + (100 * skill_lv);
 			break;
 		case RL_HAMMER_OF_GOD:
 			//! TODO: Please check the right formula. [Cydh]
@@ -6156,7 +6166,8 @@ struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list *
 		md.damage = ( skill_lv * status_get_lv(src) * 10 ) + ( status_get_int(src) * 7 / 2 ) * ( 18 + (sd?sd->status.job_level:0) / 4 ) * ( 5 / (10 - ((sd) ? pc_checkskill(sd,AM_CANNIBALIZE) : skill_get_max(AM_CANNIBALIZE))) );
 		break;
 	case RL_B_TRAP:
-		md.damage = (200 + status_get_int(src) + status_get_dex(src)) * skill_lv * 10; //(custom)
+		// kRO 2014-02-12: Damage: Caster's DEX, Target's current HP, Skill Level
+		md.damage = ((200 + status_get_dex(src)) * skill_lv * 10) + sstatus->hp; // (custom)
 		break;
 	}
 

+ 1 - 1
src/map/chrif.c

@@ -1375,7 +1375,7 @@ int chrif_load_scdata(int fd) {
 	for (i = 0; i < count; i++) {
 		struct status_change_data *data = (struct status_change_data*)RFIFOP(fd,14 + i*sizeof(struct status_change_data));
 
-		status_change_start(NULL,&sd->bl, (sc_type)data->type, 10000, data->val1, data->val2, data->val3, data->val4, data->tick, 1|2|4|8);
+		status_change_start(NULL,&sd->bl, (sc_type)data->type, 10000, data->val1, data->val2, data->val3, data->val4, data->tick, SCSTART_NOAVOID|SCSTART_NOTICKDEF|SCSTART_LOADED|SCSTART_NORATEDEF);
 	}
 
 	pc_scdata_received(sd);

+ 59 - 41
src/map/clif.c

@@ -753,22 +753,22 @@ void clif_dropflooritem(struct flooritem_data* fitem)
 
 	nullpo_retv(fitem);
 
-	if (fitem->item_data.nameid == 0)
+	if (fitem->item.nameid == 0)
 		return;
 
 	WBUFW(buf, offset+0) = header;
 	WBUFL(buf, offset+2) = fitem->bl.id;
-	WBUFW(buf, offset+6) = ((view = itemdb_viewid(fitem->item_data.nameid)) > 0) ? view : fitem->item_data.nameid;
+	WBUFW(buf, offset+6) = ((view = itemdb_viewid(fitem->item.nameid)) > 0) ? view : fitem->item.nameid;
 #if PACKETVER >= 20130000
-	WBUFW(buf, offset+8) = itemtype(fitem->item_data.nameid);
+	WBUFW(buf, offset+8) = itemtype(fitem->item.nameid);
 	offset +=2;
 #endif
-	WBUFB(buf, offset+8) = fitem->item_data.identify;
+	WBUFB(buf, offset+8) = fitem->item.identify;
 	WBUFW(buf, offset+9) = fitem->bl.x;
 	WBUFW(buf, offset+11) = fitem->bl.y;
 	WBUFB(buf, offset+13) = fitem->subx;
 	WBUFB(buf, offset+14) = fitem->suby;
-	WBUFW(buf, offset+15) = fitem->item_data.amount;
+	WBUFW(buf, offset+15) = fitem->item.amount;
 
 	clif_send(buf, packet_len(header), &fitem->bl, AREA);
 }
@@ -4498,14 +4498,14 @@ void clif_getareachar_item(struct map_session_data* sd,struct flooritem_data* fi
 	WFIFOHEAD(fd,packet_len(0x9d));
 	WFIFOW(fd,0)=0x9d;
 	WFIFOL(fd,2)=fitem->bl.id;
-	if((view = itemdb_viewid(fitem->item_data.nameid)) > 0)
+	if((view = itemdb_viewid(fitem->item.nameid)) > 0)
 		WFIFOW(fd,6)=view;
 	else
-		WFIFOW(fd,6)=fitem->item_data.nameid;
-	WFIFOB(fd,8)=fitem->item_data.identify;
+		WFIFOW(fd,6)=fitem->item.nameid;
+	WFIFOB(fd,8)=fitem->item.identify;
 	WFIFOW(fd,9)=fitem->bl.x;
 	WFIFOW(fd,11)=fitem->bl.y;
-	WFIFOW(fd,13)=fitem->item_data.amount;
+	WFIFOW(fd,13)=fitem->item.amount;
 	WFIFOB(fd,15)=fitem->subx;
 	WFIFOB(fd,16)=fitem->suby;
 	WFIFOSET(fd,packet_len(0x9d));
@@ -13173,7 +13173,7 @@ void clif_parse_GM_Item_Monster(int fd, struct map_session_data *sd)
 	// Item
 	if( (id = itemdb_searchname(str)) ) {
 		StringBuf_Init(&command);
-		if( id->type == IT_WEAPON || id->type == IT_ARMOR ) //Nonstackable
+		if( !itemdb_isstackable2(id) ) //Nonstackable
 			StringBuf_Printf(&command, "%citem2 %d 1 0 0 0 0 0 0 0", atcommand_symbol, id->nameid);
 		else
 			StringBuf_Printf(&command, "%citem %d 20", atcommand_symbol, id->nameid);
@@ -17340,21 +17340,36 @@ void clif_parse_GMFullStrip(int fd, struct map_session_data *sd) {
 
 /**
 * Marks Crimson Marker target on mini-map to the caster
-* TODO: Please, check the proper packet for Crimson Marker [Cydh]
+* 09C1 <id>.L <x>.W <y>.W (ZC_C_MARKERINFO)
 * @param fd
 * @param bl Crimson Marker target
-* @param remove True remove the marker from map, false therwise
 **/
-void clif_crimson_marker(int fd, struct block_list *bl, bool remove) {
-	WFIFOHEAD(fd,packet_len(0x107));
-	WFIFOW(fd,0) = 0x107;
-	WFIFOL(fd,2) = bl->id;
-	WFIFOW(fd,6) = (remove) ? -1 : bl->x;
-	WFIFOW(fd,8) = (remove) ? -1 : bl->y;
-	WFIFOSET(fd,packet_len(0x107));
+void clif_crimson_marker(struct map_session_data *sd, struct block_list *bl, bool remove) {
+	struct s_packet_db* info;
+	int cmd = 0;
+	int16 len;
+	unsigned char buf[11];
+
+	nullpo_retv(sd);
+
+	cmd = packet_db_ack[sd->packet_ver][ZC_C_MARKERINFO];
+	if (!cmd)
+		cmd = 0x09C1; //default
+	info = &packet_db[sd->packet_ver][cmd];
+	if (!(len = info->len))
+		return;
+
+	WBUFW(buf, 0) = cmd;
+	WBUFL(buf, info->pos[0]) = bl->id;
+	WBUFW(buf, info->pos[1]) = (remove ? -1 : bl->x);
+	WBUFW(buf, info->pos[2]) = (remove ? -1 : bl->y);
+	clif_send(buf, len, &sd->bl, SELF);
 }
 
-///TODO: Special item that obtained, must be broadcasted by this packet
+/**
+* !TODO: Special item that obtained, must be broadcasted by this packet
+* 07fd ?? (ZC_BROADCASTING_SPECIAL_ITEM_OBTAIN)
+*/
 //void clif_broadcast_obtain_special_item() {}
 
 #ifdef DUMP_UNKNOWN_PACKET
@@ -17531,7 +17546,7 @@ void packetdb_readdb(void)
 	int max_cmd=-1;
 	bool skip_ver = false;
 	int warned = 0;
-	char *str[64],*p,*str2[64],*p2,w1[256],w2[256];
+	int packet_ver = MAX_PACKET_VER;	// read into packet_db's version by default
 	int packet_len_table[MAX_PACKET_DB] = {
 	   10,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
 	    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
@@ -18012,6 +18027,7 @@ void packetdb_readdb(void)
 		{ "ZC_PERSONAL_INFOMATION", ZC_PERSONAL_INFOMATION},
 		{ "ZC_PERSONAL_INFOMATION_CHN", ZC_PERSONAL_INFOMATION_CHN},
 		{ "ZC_CLEAR_DIALOG", ZC_CLEAR_DIALOG},
+		{ "ZC_C_MARKERINFO", ZC_C_MARKERINFO},
 	};
 	const char *filename[] = { "packet_db.txt", DBIMPORT"/packet_db.txt"};
 	int f;
@@ -18022,14 +18038,14 @@ void packetdb_readdb(void)
 		packet_len(i) = packet_len_table[i];
 
 	clif_config.packet_db_ver = MAX_PACKET_VER;
-	for(f = 0; f<ARRAYLENGTH(filename); f++){
+	for(f = 0; f < ARRAYLENGTH(filename); f++){
 		int ln=0;
 		int entries = 0;
-		int packet_ver = MAX_PACKET_VER;	// read into packet_db's version by default
-		
-		sprintf(line, "%s/%s", db_path,filename[f]);
-		if( (fp=fopen(line,"r"))==NULL ){
-			if(f==0) {
+		char *str[64],*p,*str2[64],*p2;
+
+		sprintf(line, "%s/%s", db_path, filename[f]);
+		if( (fp = fopen(line,"r")) == NULL ){
+			if (f == 0) {
 				ShowFatalError("Can't read %s\n", line);
 				exit(EXIT_FAILURE);
 			}
@@ -18037,12 +18053,12 @@ void packetdb_readdb(void)
 		}
 		
 		while( fgets(line, sizeof(line), fp) ) {
+			char w1[256],w2[256];
 			ln++;
 			if(line[0]=='/' && line[1]=='/')
 				continue;
-			if (sscanf(line,"%255[^:]: %255[^\r\n]",w1,w2) == 2)
-			{
-				if(strcmpi(w1,"packet_ver")==0) {
+			if (sscanf(line,"%255[^:]: %255[^\r\n]",w1,w2) == 2) {
+				if (strcmpi(w1,"packet_ver") == 0) {
 					int prev_ver = packet_ver;
 					skip_ver = false;
 					packet_ver = atoi(w2);
@@ -18080,7 +18096,7 @@ void packetdb_readdb(void)
 					memcpy(&packet_db_ack[packet_ver], &packet_db_ack[prev_ver], sizeof(packet_db_ack[0]));
 					continue;
 				} else if(strcmpi(w1,"packet_db_ver")==0) {
-					if(strcmpi(w2,"default")==0) //This is the preferred version.
+					if (strcmpi(w2,"default") == 0) //This is the preferred version.
 						clif_config.packet_db_ver = MAX_PACKET_VER;
 					else // to manually set the packet DB version
 						clif_config.packet_db_ver = cap_value(atoi(w2), 0, MAX_PACKET_VER);
@@ -18092,14 +18108,15 @@ void packetdb_readdb(void)
 				continue; // Skipping current packet version
 
 			memset(str,0,sizeof(str));
-			for(j=0,p=line;j<4 && p; ++j) {
-				str[j]=p;
-				p=strchr(p,',');
-				if(p) *p++=0;
+			for (j = 0, p = line; j < 4 && p; ++j) {
+				str[j] = p;
+				p = strchr(p,',');
+				if (p)
+					*p++=0;
 			}
-			if(str[0]==NULL)
+			if (str[0] == NULL)
 				continue;
-			cmd=strtol(str[0],(char **)NULL,0);
+			cmd = strtol(str[0],(char **)NULL,0);
 
 			if(max_cmd < cmd)
 				max_cmd = cmd;
@@ -18139,11 +18156,12 @@ void packetdb_readdb(void)
 				ShowError("packet_db: packet error\n");
 				exit(EXIT_FAILURE);
 			}
-			for(j=0,p2=str[3];p2;j++){
+			for(j = 0, p2 = str[3]; p2; j++){
 				short k;
-				str2[j]=p2;
-				p2=strchr(p2,':');
-				if(p2) *p2++=0;
+				str2[j] = p2;
+				p2 = strchr(p2,':');
+				if(p2)
+					*p2++=0;
 				k = atoi(str2[j]);
 				// if (packet_db[packet_ver][cmd].pos[j] != k && clif_config.prefer_packet_db)	// not used for now
 

+ 2 - 2
src/map/clif.h

@@ -46,6 +46,7 @@ enum e_packet_ack {
 	ZC_PERSONAL_INFOMATION,
 	ZC_PERSONAL_INFOMATION_CHN,
 	ZC_CLEAR_DIALOG,
+	ZC_C_MARKERINFO,
 	//add other here
 	MAX_ACK_FUNC //auto upd len
 };
@@ -380,7 +381,6 @@ enum clif_messages {
 	NEED_REINS_OF_MOUNT = 0x78c,
 };
 
-
 enum e_personalinfo {
 	PINFO_BASIC = 0,
 	PINFO_PREMIUM,
@@ -881,7 +881,7 @@ void clif_channel_msg(struct Channel *channel, struct map_session_data *sd, char
 void clif_ranklist(struct map_session_data *sd, int16 rankingType);
 void clif_update_rankingpoint(struct map_session_data *sd, int rankingtype, int point);
 
-void clif_crimson_marker(int fd, struct block_list *bl, bool remove);
+void clif_crimson_marker(struct map_session_data *sd, struct block_list *bl, bool remove);
 
 //void clif_broadcast_obtain_special_item(); ///TODO!
 

+ 2 - 11
src/map/itemdb.c

@@ -1430,15 +1430,6 @@ static int itemdb_read_sqldb(void) {
 	return 0;
 }
 
-/**
- * Unique item ID function
- * @param sd : Player
- * @return unique_id
- */
-uint64 itemdb_unique_id(struct map_session_data *sd) {
-	return ((uint64)sd->status.char_id << 32) | sd->status.uniqueitem_counter++;
-}
-
 /** Check if the item is restricted by item_noequip.txt
 * @param id Item that will be checked
 * @param m Map ID
@@ -1465,10 +1456,10 @@ bool itemdb_isNoEquip(struct item_data *id, uint16 m) {
 */
 bool itemdb_is_spellbook2(unsigned short nameid) {
 	unsigned char i;
-	if (!nameid || !itemdb_exists(nameid))
+	if (!nameid || !itemdb_exists(nameid) || !skill_spellbook_count)
 		return false;
 	ARR_FIND(0, MAX_SKILL_SPELLBOOK_DB, i, skill_spellbook_db[i].nameid == nameid);
-	if (i >= MAX_SKILL_SPELLBOOK_DB)
+	if (i == MAX_SKILL_SPELLBOOK_DB)
 		return false;
 	return true;
 }

+ 0 - 1
src/map/itemdb.h

@@ -480,7 +480,6 @@ bool itemdb_isequip2(struct item_data *id);
 char itemdb_isidentified(unsigned short nameid);
 bool itemdb_isstackable2(struct item_data *id);
 #define itemdb_isstackable(nameid) itemdb_isstackable2(itemdb_search(nameid))
-uint64 itemdb_unique_id(struct map_session_data *sd); // Unique Item ID
 bool itemdb_isNoEquip(struct item_data *id, uint16 m);
 
 struct item_combo *itemdb_combo_exists(unsigned short combo_id);

+ 7 - 7
src/map/map.c

@@ -1289,8 +1289,8 @@ int map_clearflooritem_timer(int tid, unsigned int tick, int id, intptr_t data)
 	}
 
 
-	if (search_petDB_index(fitem->item_data.nameid, PET_EGG) >= 0)
-		intif_delete_petdata(MakeDWord(fitem->item_data.card[1], fitem->item_data.card[2]));
+	if (search_petDB_index(fitem->item.nameid, PET_EGG) >= 0)
+		intif_delete_petdata(MakeDWord(fitem->item.card[1], fitem->item.card[2]));
 
 	clif_clearflooritem(fitem, 0);
 	map_deliddb(&fitem->bl);
@@ -1442,14 +1442,14 @@ int map_search_freecell(struct block_list *src, int16 m, int16 *x,int16 *y, int1
  * @param flag: &1 MVP item. &2 do stacking check. &4 bypass droppable check.
  * @return 0:failure, x:item_gid [MIN_FLOORITEM;MAX_FLOORITEM]==[2;START_ACCOUNT_NUM]
  *------------------------------------------*/
-int map_addflooritem(struct item *item_data,int amount,int16 m,int16 x,int16 y,int first_charid,int second_charid,int third_charid,int flags)
+int map_addflooritem(struct item *item,int amount,int16 m,int16 x,int16 y,int first_charid,int second_charid,int third_charid,int flags)
 {
 	int r;
 	struct flooritem_data *fitem=NULL;
 
-	nullpo_ret(item_data);
+	nullpo_ret(item);
 
-	if(!(flags&4) && battle_config.item_onfloor && (itemdb_traderight(item_data->nameid)&1) )
+	if(!(flags&4) && battle_config.item_onfloor && (itemdb_traderight(item->nameid)&1) )
 		return 0; //can't be dropped
 
 	if(!map_searchrandfreecell(m,&x,&y,flags&2?1:0))
@@ -1475,8 +1475,8 @@ int map_addflooritem(struct item *item_data,int amount,int16 m,int16 x,int16 y,i
 	fitem->third_get_charid = third_charid;
 	fitem->third_get_tick = fitem->second_get_tick + (flags&1 ? battle_config.mvp_item_third_get_time : battle_config.item_third_get_time);
 
-	memcpy(&fitem->item_data,item_data,sizeof(*item_data));
-	fitem->item_data.amount=amount;
+	memcpy(&fitem->item,item,sizeof(*item));
+	fitem->item.amount=amount;
 	fitem->subx=(r&3)*3+3;
 	fitem->suby=((r>>2)&3)*3+3;
 	fitem->cleartimer=add_timer(gettick()+battle_config.flooritem_lifetime,map_clearflooritem_timer,fitem->bl.id,0);

+ 2 - 2
src/map/map.h

@@ -425,7 +425,7 @@ struct flooritem_data {
 	int cleartimer;
 	int first_get_charid,second_get_charid,third_get_charid;
 	unsigned int first_get_tick,second_get_tick,third_get_tick;
-	struct item item_data;
+	struct item item;
 };
 
 enum _sp {
@@ -795,7 +795,7 @@ bool map_addnpc(int16 m,struct npc_data *);
 int map_clearflooritem_timer(int tid, unsigned int tick, int id, intptr_t data);
 int map_removemobs_timer(int tid, unsigned int tick, int id, intptr_t data);
 void map_clearflooritem(struct block_list* bl);
-int map_addflooritem(struct item *item_data,int amount,int16 m,int16 x,int16 y,int first_charid,int second_charid,int third_charid,int flags);
+int map_addflooritem(struct item *item,int amount,int16 m,int16 x,int16 y,int first_charid,int second_charid,int third_charid,int flags);
 
 // instances
 int map_addinstancemap(const char*,int);

+ 4 - 4
src/map/mob.c

@@ -417,7 +417,7 @@ bool mob_ksprotected (struct block_list *src, struct block_list *target)
 		return true;
 	} while(0);
 
-	status_change_start(src, target, SC_KSPROTECTED, 10000, sd->bl.id, sd->state.noks, sd->status.party_id, sd->status.guild_id, battle_config.ksprotection, 0);
+	status_change_start(src, target, SC_KSPROTECTED, 10000, sd->bl.id, sd->state.noks, sd->status.party_id, sd->status.guild_id, battle_config.ksprotection, SCSTART_NOAVOID);
 
 	return false;
 }
@@ -1603,15 +1603,15 @@ static bool mob_ai_sub_hard(struct mob_data *md, unsigned int tick)
 
 		fitem = (struct flooritem_data *)tbl;
 		//Logs items, taken by (L)ooter Mobs [Lupus]
-		log_pick_mob(md, LOG_TYPE_LOOT, fitem->item_data.amount, &fitem->item_data);
+		log_pick_mob(md, LOG_TYPE_LOOT, fitem->item.amount, &fitem->item);
 
 		if (md->lootitem_count < LOOTITEM_SIZE) {
-			memcpy (&md->lootitem[md->lootitem_count++], &fitem->item_data, sizeof(md->lootitem[0]));
+			memcpy (&md->lootitem[md->lootitem_count++], &fitem->item, sizeof(md->lootitem[0]));
 		} else {	//Destroy first looted item...
 			if (md->lootitem[0].card[0] == CARD0_PET)
 				intif_delete_petdata( MakeDWord(md->lootitem[0].card[1],md->lootitem[0].card[2]) );
 			memmove(&md->lootitem[0], &md->lootitem[1], (LOOTITEM_SIZE-1)*sizeof(md->lootitem[0]));
-			memcpy (&md->lootitem[LOOTITEM_SIZE-1], &fitem->item_data, sizeof(md->lootitem[0]));
+			memcpy (&md->lootitem[LOOTITEM_SIZE-1], &fitem->item, sizeof(md->lootitem[0]));
 		}
 		if (pcdb_checkid(md->vd->class_))
 		{	//Give them walk act/delay to properly mimic players. [Skotlex]

+ 2 - 0
src/map/npc.c

@@ -4175,6 +4175,8 @@ bool npc_unloadfile( const char* path ) {
 	if( found ) /* refresh event cache */
 		npc_read_event_script();
 
+	npc_delsrcfile(path);
+
 	return found;
 }
 

+ 18 - 10
src/map/pc.c

@@ -4311,7 +4311,7 @@ char pc_additem(struct map_session_data *sd,struct item *item,int amount,e_log_p
 		clif_additem(sd,i,amount,0);
 	}
 	if( !itemdb_isstackable2(id) && !item->unique_id )
-		sd->status.inventory[i].unique_id = itemdb_unique_id(sd);
+		sd->status.inventory[i].unique_id = pc_generate_unique_id(sd);
 	log_pick_pc(sd, log_type, amount, &sd->status.inventory[i]);
 
 	sd->weight += w;
@@ -4471,7 +4471,7 @@ bool pc_takeitem(struct map_session_data *sd,struct flooritem_data *fitem)
 	}
 
 	//This function takes care of giving the item to whoever should have it, considering party-share options.
-	if ((flag = party_share_loot(p,sd,&fitem->item_data, fitem->first_get_charid))) {
+	if ((flag = party_share_loot(p,sd,&fitem->item, fitem->first_get_charid))) {
 		clif_additem(sd,0,0,flag);
 		return true;
 	}
@@ -9546,7 +9546,7 @@ void pc_check_available_item(struct map_session_data *sd) {
 				continue;
 			}
 			if (!sd->status.inventory[i].unique_id && !itemdb_isstackable(it))
-				sd->status.inventory[i].unique_id = itemdb_unique_id(sd);
+				sd->status.inventory[i].unique_id = pc_generate_unique_id(sd);
 		}
 	}
 
@@ -9564,7 +9564,7 @@ void pc_check_available_item(struct map_session_data *sd) {
 				continue;
 			}
 			if (!sd->status.cart[i].unique_id && !itemdb_isstackable(it))
-				sd->status.cart[i].unique_id = itemdb_unique_id(sd);
+				sd->status.cart[i].unique_id = pc_generate_unique_id(sd);
 		}
 	}
 
@@ -9582,7 +9582,7 @@ void pc_check_available_item(struct map_session_data *sd) {
 				continue;
 			}
 			if (!sd->status.storage.items[i].unique_id && !itemdb_isstackable(it))
-				sd->status.storage.items[i].unique_id = itemdb_unique_id(sd);
+				sd->status.storage.items[i].unique_id = pc_generate_unique_id(sd);
  		}
 	}
 }
@@ -10964,22 +10964,21 @@ enum e_BANKING_WITHDRAW_ACK pc_bank_withdraw(struct map_session_data *sd, int mo
 }
 
 /**
-* Clear Cirmson Marker data from caster
+* Clear Crimson Marker data from caster
 * @param sd: Player
 **/
 void pc_crimson_marker_clear(struct map_session_data *sd) {
 	uint8 i;
 
-	if (!sd || !(&sd->c_marker) || !sd->c_marker.target)
+	if (!sd)
 		return;
 
 	for (i = 0; i < MAX_SKILL_CRIMSON_MARKER; i++) {
 		struct block_list *bl = NULL;
-		if (sd->c_marker.target[i] && (bl = map_id2bl(sd->c_marker.target[i])))
+		if (sd->c_marker[i] && (bl = map_id2bl(sd->c_marker[i])))
 			status_change_end(bl,SC_C_MARKER,INVALID_TIMER);
-		sd->c_marker.target[i] = 0;
+		sd->c_marker[i] = 0;
 	}
-	sd->c_marker.count = 0;
 }
 
 /**
@@ -11233,6 +11232,15 @@ bool pc_is_same_equip_index(enum equip_index eqi, short *equip_index, short inde
 	return false;
 }
 
+/**
+ * Generate Unique item ID for player
+ * @param sd : Player
+ * @return A generated Unique item ID
+ */
+uint64 pc_generate_unique_id(struct map_session_data *sd) {
+	return ((uint64)sd->status.char_id << 32) | sd->status.uniqueitem_counter++;
+}
+
 /*==========================================
  * pc Init/Terminate
  *------------------------------------------*/

+ 4 - 5
src/map/pc.h

@@ -591,11 +591,8 @@ struct map_session_data {
 
 	uint16 dmglog[DAMAGELOG_SIZE_PC]; ///target ids
 
-	struct s_crimson_marker { ///Store target that marked by Crimson Marker [Cydh]
-		int target[MAX_SKILL_CRIMSON_MARKER]; //Target id storage
-		uint8 count; //Count of target for skill used (i.e. RL_D_TAIL).
-	} c_marker;
-	bool flicker; ///Is Flicker Skill skill as player's last action? [Cydh]
+	int c_marker[MAX_SKILL_CRIMSON_MARKER]; /// Store target that marked by Crimson Marker [Cydh]
+	bool flicker; /// Check RL_FLICKER usage status [Cydh]
 
 	int storage_size; /// Holds player storage size (VIP system).
 #ifdef VIP_ENABLE
@@ -879,6 +876,8 @@ char pc_additem(struct map_session_data *sd, struct item *item, int amount, e_lo
 char pc_getzeny(struct map_session_data *sd, int zeny, enum e_log_pick_type type, struct map_session_data *tsd);
 char pc_delitem(struct map_session_data *sd, int n, int amount, int type, short reason, e_log_pick_type log_type);
 
+uint64 pc_generate_unique_id(struct map_session_data *sd);
+
 //Bound items
 int pc_bound_chk(TBL_PC *sd,enum bound_type type,int *idxlist);
 

+ 2 - 2
src/map/pet.c

@@ -946,8 +946,8 @@ static int pet_ai_sub_hard(struct pet_data *pd, struct map_session_data *sd, uns
 		} else{
 			struct flooritem_data *fitem = (struct flooritem_data *)target;
 			if(pd->loot->count < pd->loot->max){
-				memcpy(&pd->loot->item[pd->loot->count++],&fitem->item_data,sizeof(pd->loot->item[0]));
-				pd->loot->weight += itemdb_weight(fitem->item_data.nameid)*fitem->item_data.amount;
+				memcpy(&pd->loot->item[pd->loot->count++],&fitem->item,sizeof(pd->loot->item[0]));
+				pd->loot->weight += itemdb_weight(fitem->item.nameid)*fitem->item.amount;
 				map_clearflooritem(target);
 			}
 			//Target is unlocked regardless of whether it was picked or not.

+ 43 - 12
src/map/script.c

@@ -2369,6 +2369,14 @@ void script_hardcoded_constants(void) {
 	script_set_constant("BSF_REM_DEBUFF",BSF_REM_DEBUFF,false);
 	script_set_constant("BSF_ALL",BSF_ALL,false);
 	script_set_constant("BSF_CLEARALL",BSF_CLEARALL,false);
+
+	/* sc_start flags */
+	script_set_constant("SCSTART_NONE",SCSTART_NONE,false);
+	script_set_constant("SCSTART_NOAVOID",SCSTART_NOAVOID,false);
+	script_set_constant("SCSTART_NOTICKDEF",SCSTART_NOTICKDEF,false);
+	script_set_constant("SCSTART_LOADED",SCSTART_LOADED,false);
+	script_set_constant("SCSTART_NORATEDEF",SCSTART_NORATEDEF,false);
+	script_set_constant("SCSTART_NOICON",SCSTART_NOICON,false);
 }
 
 /*==========================================
@@ -7753,8 +7761,31 @@ BUILDIN_FUNC(strnpcinfo)
 }
 
 
-// aegis->athena slot position conversion table
-static unsigned int equip[] = {EQP_HEAD_TOP,EQP_ARMOR,EQP_HAND_L,EQP_HAND_R,EQP_GARMENT,EQP_SHOES,EQP_ACC_L,EQP_ACC_R,EQP_HEAD_MID,EQP_HEAD_LOW,EQP_COSTUME_HEAD_LOW,EQP_COSTUME_HEAD_MID,EQP_COSTUME_HEAD_TOP,EQP_COSTUME_GARMENT,EQP_AMMO,EQP_SHADOW_ARMOR,EQP_SHADOW_WEAPON,EQP_SHADOW_SHIELD,EQP_SHADOW_SHOES,EQP_SHADOW_ACC_R,EQP_SHADOW_ACC_L};
+/// aegis->athena slot position conversion table
+/// Index is used by EQI_ in db/const.txt
+static unsigned int equip[] = {
+	EQP_HEAD_TOP,
+	EQP_ARMOR,
+	EQP_HAND_L,
+	EQP_HAND_R,
+	EQP_GARMENT,
+	EQP_SHOES,
+	EQP_ACC_L,
+	EQP_ACC_R,
+	EQP_HEAD_MID,
+	EQP_HEAD_LOW,
+	EQP_COSTUME_HEAD_LOW,
+	EQP_COSTUME_HEAD_MID,
+	EQP_COSTUME_HEAD_TOP,
+	EQP_COSTUME_GARMENT,
+	EQP_AMMO,
+	EQP_SHADOW_ARMOR,
+	EQP_SHADOW_WEAPON,
+	EQP_SHADOW_SHIELD,
+	EQP_SHADOW_SHOES,
+	EQP_SHADOW_ACC_R,
+	EQP_SHADOW_ACC_L
+};
 
 /*==========================================
  * GetEquipID(Pos);     Pos: 1-14
@@ -10267,12 +10298,12 @@ BUILDIN_FUNC(getareausers)
  *------------------------------------------*/
 static int buildin_getareadropitem_sub(struct block_list *bl,va_list ap)
 {
-	int item=va_arg(ap,int);
+	int nameid=va_arg(ap,int);
 	int *amount=va_arg(ap,int *);
 	struct flooritem_data *drop=(struct flooritem_data *)bl;
 
-	if(drop->item_data.nameid==item)
-		(*amount)+=drop->item_data.amount;
+	if(drop->item.nameid==nameid)
+		(*amount)+=drop->item.amount;
 
 	return 0;
 }
@@ -10280,7 +10311,7 @@ BUILDIN_FUNC(getareadropitem)
 {
 	const char *str;
 	int16 m,x0,y0,x1,y1;
-	int item,amount=0;
+	int nameid,amount=0;
 	struct script_data *data;
 
 	str=script_getstr(st,2);
@@ -10294,18 +10325,18 @@ BUILDIN_FUNC(getareadropitem)
 	if( data_isstring(data) ){
 		const char *name=conv_str(st,data);
 		struct item_data *item_data = itemdb_searchname(name);
-		item=UNKNOWN_ITEM_ID;
+		nameid=UNKNOWN_ITEM_ID;
 		if( item_data )
-			item=item_data->nameid;
+			nameid=item_data->nameid;
 	}else
-		item=conv_num(st,data);
+		nameid=conv_num(st,data);
 
 	if( (m=map_mapname2mapid(str))< 0){
 		script_pushint(st,-1);
 		return 0;
 	}
 	map_foreachinarea(buildin_getareadropitem_sub,
-		m,x0,y0,x1,y1,BL_ITEM,item,&amount);
+		m,x0,y0,x1,y1,BL_ITEM,nameid,&amount);
 	script_pushint(st,amount);
 	return SCRIPT_CMD_SUCCESS;
 }
@@ -10492,7 +10523,7 @@ BUILDIN_FUNC(getscrate)
 		bl = map_id2bl(st->rid);
 
 	if (bl)
-		rate = status_get_sc_def(NULL,bl, (sc_type)type, 10000, 10000, 0);
+		rate = status_get_sc_def(NULL,bl, (sc_type)type, 10000, 10000, SCSTART_NONE);
 
 	script_pushint(st,rate);
 	return SCRIPT_CMD_SUCCESS;
@@ -16674,7 +16705,7 @@ BUILDIN_FUNC(mercenary_sc_start)
 	tick = script_getnum(st,3);
 	val1 = script_getnum(st,4);
 
-	status_change_start(NULL, &sd->md->bl, type, 10000, val1, 0, 0, 0, tick, 2);
+	status_change_start(NULL, &sd->md->bl, type, 10000, val1, 0, 0, 0, tick, SCSTART_NOTICKDEF);
 	return SCRIPT_CMD_SUCCESS;
 }
 

File diff suppressed because it is too large
+ 304 - 209
src/map/skill.c


+ 27 - 25
src/map/skill.h

@@ -18,10 +18,10 @@ struct status_change_entry;
 #define MAX_PRODUCE_RESOURCE	12 /// Max Produce requirements
 #define MAX_SKILL_ARROW_DB		150 /// Max Arrow Creation DB
 #define MAX_ARROW_RESULT		5 /// Max Arrow results/created
-#define MAX_SKILL_ABRA_DB		350 /// Max Skill list of Abracadabra DB
-#define MAX_SKILL_IMPROVISE_DB 50 /// Max Skill for Improvise
+#define MAX_SKILL_ABRA_DB		160 /// Max Skill list of Abracadabra DB
+#define MAX_SKILL_IMPROVISE_DB 30 /// Max Skill for Improvise
 #define MAX_SKILL_LEVEL 100 /// Max Skill Level
-#define MAX_SKILL_CRIMSON_MARKER 3 /// Max Crimson Marker targets
+#define MAX_SKILL_CRIMSON_MARKER 3 /// Max Crimson Marker targets (RL_C_MARKER)
 #define SKILL_NAME_LENGTH 31 /// Max Skill Name length
 #define SKILL_DESC_LENGTH 31 /// Max Skill Desc length
 
@@ -101,7 +101,7 @@ enum e_skill_inf3 {
 /// Flags passed to skill_attack/skill_area_sub
 enum e_skill_display {
 	SD_LEVEL     = 0x1000, // skill_attack will send -1 instead of skill level (affects display of some skills)
-	SD_ANIMATION = 0x2000, // skill_attack will use '5' instead of the skill's 'type' (this makes skills show an animation)
+	SD_ANIMATION = 0x2000, // skill_attack will use '5' instead of the skill's 'type' (this makes skills show an animation). Also being used in skill_attack for splash skill (NK_SPLASH) to check status_check_skilluse
 	SD_SPLASH    = 0x4000, // skill_area_sub will count targets in skill_area_temp[2]
 	SD_PREAMBLE  = 0x8000, // skill_area_sub will transmit a 'magic' damage packet (-30000 dmg) for the first target selected
 };
@@ -259,22 +259,23 @@ struct skill_unit_group_tickset {
 
 
 enum {
-	UF_DEFNOTENEMY      = 0x0001,	// If 'defunit_not_enemy' is set, the target is changed to 'friend'
-	UF_NOREITERATION    = 0x0002,	// Spell cannot be stacked
-	UF_NOFOOTSET        = 0x0004,	// Spell cannot be cast near/on targets
-	UF_NOOVERLAP        = 0x0008,	// Spell effects do not overlap
-	UF_PATHCHECK        = 0x0010,	// Only cells with a shootable path will be placed
-	UF_NOPC             = 0x0020,	// May not target players
-	UF_NOMOB            = 0x0040,	// May not target mobs
-	UF_SKILL            = 0x0080,	// May target skills
-	UF_DANCE            = 0x0100,	// Dance
-	UF_ENSEMBLE         = 0x0200,	// Duet
-	UF_SONG             = 0x0400,	// Song
-	UF_DUALMODE         = 0x0800,	// Spells should trigger both ontimer and onplace/onout/onleft effects.
-	UF_NOKNOCKBACK      = 0x1000,	// Skill unit cannot be knocked back
-	UF_RANGEDSINGLEUNIT = 0x2000,	// hack for ranged layout, only display center
-	UF_REM_CRAZYWEED    = 0x4000,	// removed by Crazyweed
-	UF_REM_FIRERAIN     = 0x8000,	// removed by Fire Rain
+	UF_DEFNOTENEMY      = 0x00001,	// If 'defunit_not_enemy' is set, the target is changed to 'friend'
+	UF_NOREITERATION    = 0x00002,	// Spell cannot be stacked
+	UF_NOFOOTSET        = 0x00004,	// Spell cannot be cast near/on targets
+	UF_NOOVERLAP        = 0x00008,	// Spell effects do not overlap
+	UF_PATHCHECK        = 0x00010,	// Only cells with a shootable path will be placed
+	UF_NOPC             = 0x00020,	// May not target players
+	UF_NOMOB            = 0x00040,	// May not target mobs
+	UF_SKILL            = 0x00080,	// May target skills
+	UF_DANCE            = 0x00100,	// Dance
+	UF_ENSEMBLE         = 0x00200,	// Duet
+	UF_SONG             = 0x00400,	// Song
+	UF_DUALMODE         = 0x00800,	// Spells should trigger both ontimer and onplace/onout/onleft effects.
+	UF_NOKNOCKBACK      = 0x01000,	// Skill unit cannot be knocked back
+	UF_RANGEDSINGLEUNIT = 0x02000,	// hack for ranged layout, only display center
+	UF_REM_CRAZYWEED    = 0x04000,	// removed by Crazyweed
+	UF_REM_FIRERAIN     = 0x08000,	// removed by Fire Rain
+	UF_KNOCKBACK_GROUP  = 0x10000,	// knockback skill unit with its group instead of single unit
 };
 
 /// Create Database item
@@ -303,9 +304,7 @@ struct s_skill_abra_db {
 	int per[MAX_SKILL_LEVEL]; /// Probability summoned
 };
 extern struct s_skill_abra_db skill_abra_db[MAX_SKILL_ABRA_DB];
-
-extern int enchant_eff[5];
-extern int deluge_eff[5];
+extern unsigned short skill_abra_count;
 
 void do_init_skill(void);
 void do_final_skill(void);
@@ -414,6 +413,7 @@ int skill_check_unit_cell(uint16 skill_id,int16 m,int16 x,int16 y,int unit_id);
 int skill_unit_out_all( struct block_list *bl,unsigned int tick,int range);
 int skill_unit_move(struct block_list *bl,unsigned int tick,int flag);
 void skill_unit_move_unit_group( struct skill_unit_group *group, int16 m,int16 dx,int16 dy);
+void skill_unit_move_unit(struct block_list *bl, int dx, int dy);
 
 struct skill_unit_group *skill_check_dancing( struct block_list *src );
 
@@ -1984,17 +1984,19 @@ struct s_skill_spellbook_db {
 	unsigned short point;
 };
 extern struct s_skill_spellbook_db skill_spellbook_db[MAX_SKILL_SPELLBOOK_DB];
-int skill_spellbook (struct map_session_data *sd, unsigned short nameid);
+extern unsigned short skill_spellbook_count;
+void skill_spellbook (struct map_session_data *sd, unsigned short nameid);
 int skill_block_check(struct block_list *bl, enum sc_type type, uint16 skill_id);
 
 /**
  * Guilottine Cross
  **/
-#define MAX_SKILL_MAGICMUSHROOM_DB 23
+#define MAX_SKILL_MAGICMUSHROOM_DB 25
 struct s_skill_magicmushroom_db {
 	uint16 skill_id;
 };
 extern struct s_skill_magicmushroom_db skill_magicmushroom_db[MAX_SKILL_MAGICMUSHROOM_DB];
+extern unsigned short skill_magicmushroom_count;
 int skill_maelstrom_suction(struct block_list *bl, va_list ap);
 bool skill_check_shadowform(struct block_list *bl, int64 damage, int hit);
 

+ 150 - 132
src/map/status.c

@@ -689,7 +689,7 @@ void initChangeTables(void)
 	set_sc( SC_WEAKNESS		, SC__WEAKNESS		, SI_WEAKNESS		, SCB_MAXHP );
 	set_sc( SC_STRIPACCESSARY	, SC__STRIPACCESSORY	, SI_STRIPACCESSARY	, SCB_DEX|SCB_INT|SCB_LUK );
 	set_sc_with_vfx( SC_MANHOLE	, SC__MANHOLE		, SI_MANHOLE		, SCB_NONE );
-	add_sc( SC_CHAOSPANIC		, SC__CHAOS			);
+	add_sc( SC_CHAOSPANIC		, SC_CONFUSION		);
 	add_sc( SC_BLOODYLUST		, SC_BERSERK		);
 	add_sc( SC_FEINTBOMB		, SC__FEINTBOMB		);
 
@@ -801,6 +801,7 @@ void initChangeTables(void)
 	/* Rebellion */
 	add_sc( RL_MASS_SPIRAL		, SC_BLEEDING );
 	add_sc( RL_HAMMER_OF_GOD	, SC_STUN );
+	set_sc( RL_H_MINE		, SC_H_MINE		, SI_H_MINE		, SCB_NONE);
 	set_sc( RL_B_TRAP		, SC_B_TRAP		, SI_B_TRAP		, SCB_SPEED );
 	set_sc( RL_E_CHAIN		, SC_E_CHAIN	, SI_E_CHAIN	, SCB_NONE );
 	set_sc( RL_P_ALTER		, SC_P_ALTER	, SI_P_ALTER	, SCB_NONE );
@@ -981,7 +982,6 @@ void initChangeTables(void)
 	StatusIconChangeTable[SC_MTF_CRIDAMAGE] = SI_MTF_CRIDAMAGE;
 	StatusIconChangeTable[SC_MOONSTAR] = SI_MOONSTAR;
 	StatusIconChangeTable[SC_SUPER_STAR] = SI_SUPER_STAR;
-	StatusIconChangeTable[SC_H_MINE] = SI_H_MINE;
 	StatusIconChangeTable[SC_QD_SHOT_READY] = SI_E_QD_SHOT_READY;
 	StatusIconChangeTable[SC_HEAT_BARREL_AFTER] = SI_HEAT_BARREL_AFTER;
 	StatusIconChangeTable[SC_STRANGELIGHTS] = SI_STRANGELIGHTS;
@@ -1918,9 +1918,8 @@ bool status_check_skilluse(struct block_list *src, struct block_list *target, ui
 			return false;
 		if(skill_id == PR_LEXAETERNA && (tsc->data[SC_FREEZE] || (tsc->data[SC_STONE] && tsc->opt1 == OPT1_STONE)))
 			return false;
-		if (tsc->data[SC__MANHOLE])
-			if (!(skill_get_inf3(skill_id)&INF3_USABLE_MANHOLE))
-				return false;
+		if (tsc->data[SC__MANHOLE] && !(skill_get_inf3(skill_id)&INF3_USABLE_MANHOLE))
+			return false;
 	}
 
 	// If targetting, cloak+hide protect you, otherwise only hiding does.
@@ -5491,6 +5490,7 @@ static signed short status_calc_flee(struct block_list *bl, struct status_change
 	if(sc->data[SC_TINDER_BREAKER] || sc->data[SC_TINDER_BREAKER2])
 		return 1; // 1 = min flee
 
+	// Fixed value
 	if(sc->data[SC_INCFLEE])
 		flee += sc->data[SC_INCFLEE]->val1;
 	if(sc->data[SC_FLEEFOOD])
@@ -5521,11 +5521,14 @@ static signed short status_calc_flee(struct block_list *bl, struct status_change
 		flee += sc->data[SC_HALLUCINATIONWALK]->val2;
 	if( sc->data[SC_WATER_BARRIER] )
 		flee -= sc->data[SC_WATER_BARRIER]->val3;
+	if( sc->data[SC_C_MARKER] )
+		flee -= sc->data[SC_C_MARKER]->val3;
 #ifdef RENEWAL
 	if( sc->data[SC_SPEARQUICKEN] )
 		flee += 2 * sc->data[SC_SPEARQUICKEN]->val1;
 #endif
 
+	// Rate value
 	if(sc->data[SC_INCFLEERATE])
 		flee += flee * sc->data[SC_INCFLEERATE]->val1/100;
 	if(sc->data[SC_SPIDERWEB] && sc->data[SC_SPIDERWEB]->val1)
@@ -5558,8 +5561,8 @@ static signed short status_calc_flee(struct block_list *bl, struct status_change
 		flee += flee * 20 / 100;
 	if (sc->data[SC_TEARGAS])
 		flee -= flee * 50 / 100;
-	if( sc->data[SC_C_MARKER] )
-		flee -= (flee * sc->data[SC_C_MARKER]->val3) / 100;
+	//if( sc->data[SC_C_MARKER] )
+	//	flee -= (flee * sc->data[SC_C_MARKER]->val3) / 100;
 	if(sc->data[SC_HEAT_BARREL])
 		flee -= sc->data[SC_HEAT_BARREL]->val4;
 
@@ -7043,14 +7046,10 @@ void status_change_init(struct block_list *bl)
 * @param type: Status change (SC_*)
 * @param rate: Initial percentage rate of affecting bl
 * @param tick: Initial duration that the status change affects bl
-* @param flag: Value which determines what parts to calculate
-*	&1: Cannot be avoided (it has to start)
-*	&2: Tick should not be reduced (by vit, luk, lv, etc)
-*	&4: sc_data loaded, no value has to be altered.
-*	&8: rate should not be reduced
+* @param flag: Value which determines what parts to calculate. See e_status_change_start_flags
 * @return adjusted duration based on flag values
 **/
-int status_get_sc_def(struct block_list *src, struct block_list *bl, enum sc_type type, int rate, int tick, int flag)
+int status_get_sc_def(struct block_list *src, struct block_list *bl, enum sc_type type, int rate, int tick, unsigned char flag)
 {
 	/// Resistance rate: 10000 = 100%
 	/// Example:	50% (5000) -> sc_def = 5000 -> 25%;
@@ -7269,6 +7268,9 @@ int status_get_sc_def(struct block_list *src, struct block_list *bl, enum sc_typ
 		case SC_VOICEOFSIREN:
 			tick_def2 = (status_get_lv(bl) * 100) + ((bl->type == BL_PC)?((TBL_PC*)bl)->status.job_level * 200 : 0);
 			break;
+		case SC_B_TRAP:
+			tick_def = b_status->str * 50; // (custom)
+			break;
 		default:
 			// Effect that cannot be reduced? Likely a buff.
 			if (!(rnd()%10000 < rate))
@@ -7320,7 +7322,7 @@ int status_get_sc_def(struct block_list *src, struct block_list *bl, enum sc_typ
 		tick_def = sc_def;
 
 	// Natural resistance
-	if (!(flag&8)) {
+	if (!(flag&SCSTART_NORATEDEF)) {
 		rate -= rate*sc_def/10000;
 		rate -= sc_def2;
 
@@ -7347,10 +7349,11 @@ int status_get_sc_def(struct block_list *src, struct block_list *bl, enum sc_typ
 		return 0;
 
 	// Even if a status change doesn't have a duration, it should still trigger
-	if (tick < 1) return 1;
+	if (tick < 1)
+		return 1;
 
-	// Rate reduction
-	if (flag&2)
+	// Duration cannot be reduced
+	if (flag&SCSTART_NOTICKDEF)
 		return tick;
 
 	tick -= tick*tick_def/10000;
@@ -7458,16 +7461,10 @@ void status_display_remove(struct map_session_data *sd, enum sc_type type) {
 * @param rate: Initial percentage rate of affecting bl (0~10000)
 * @param val1~4: Depends on type of status change
 * @param tick: Initial duration that the status change affects bl
-* @param flag: Value which determines what parts to calculate
-*	&1 : Cannot be avoided (it has to start)
-*	&2 : Tick should not be reduced (by vit, luk, lv, etc)
-*	&4 : sc_data loaded, no value has to be altered.
-*	&8 : rate should not be reduced
-*	&16: don't send SI
+* @param flag: Value which determines what parts to calculate. See e_status_change_start_flags
 * @return adjusted duration based on flag values
 **/
-int status_change_start(struct block_list* src, struct block_list* bl,enum sc_type type,int rate,int val1,int val2,int val3,int val4,int tick,int flag)
-{
+int status_change_start(struct block_list* src, struct block_list* bl,enum sc_type type,int rate,int val1,int val2,int val3,int val4,int tick,unsigned char flag) {
 	struct map_session_data *sd = NULL;
 	struct status_change* sc;
 	struct status_change_entry* sce;
@@ -7565,11 +7562,14 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 	sd = BL_CAST(BL_PC, bl);
 
 	// Adjust tick according to status resistances
-	if( !(flag&(1|4)) ) {
+	if( !(flag&(SCSTART_NOAVOID|SCSTART_LOADED)) ) {
 		tick = status_get_sc_def(src, bl, type, rate, tick, flag);
-		if( !tick ) return 0;
+		if( !tick )
+			return 0;
 	}
 
+	vd = status_get_viewdata(bl);
+
 	undead_flag = battle_check_undead(status->race,status->def_ele);
 	// Check for immunities / sc fails
 	switch (type) {
@@ -7595,7 +7595,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 			return 0;
 	case SC_FREEZE:
 		// Undead are immune to Freeze/Stone
-		if (undead_flag && !(flag&1))
+		if (undead_flag && !(flag&SCSTART_NOAVOID))
 			return 0;
 	case SC_DEEPSLEEP:
 	case SC_SLEEP:
@@ -7724,7 +7724,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 	break;
 	// Strip skills, need to divest something or it fails.
 	case SC_STRIPWEAPON:
-		if (sd && !(flag&4)) { // Apply sc anyway if loading saved sc_data
+		if (sd && !(flag&SCSTART_LOADED)) { // Apply sc anyway if loading saved sc_data
 			short i;
 			opt_flag = 0; // Reuse to check success condition.
 			if(sd->bonus.unstripable_equip&EQP_WEAPON)
@@ -7747,7 +7747,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 	case SC_STRIPSHIELD:
 		if( val2 == 1 ) val2 = 0; // GX effect. Do not take shield off..
 		else
-		if (sd && !(flag&4)) {
+		if (sd && !(flag&SCSTART_LOADED)) {
 			short i;
 			if(sd->bonus.unstripable_equip&EQP_SHIELD)
 				return 0;
@@ -7759,7 +7759,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 		if (tick == 1) return 1; // Minimal duration: Only strip without causing the SC
 	break;
 	case SC_STRIPARMOR:
-		if (sd && !(flag&4)) {
+		if (sd && !(flag&SCSTART_LOADED)) {
 			short i;
 			if(sd->bonus.unstripable_equip&EQP_ARMOR)
 				return 0;
@@ -7771,7 +7771,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 		if (tick == 1) return 1; // Minimal duration: Only strip without causing the SC
 	break;
 	case SC_STRIPHELM:
-		if (sd && !(flag&4)) {
+		if (sd && !(flag&SCSTART_LOADED)) {
 			short i;
 			if(sd->bonus.unstripable_equip&EQP_HELM)
 				return 0;
@@ -7896,20 +7896,19 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 		if (sc->data[SC_P_ALTER] || sc->data[SC_HEAT_BARREL])
 			return 0;
 		break;
-	case SC_C_MARKER:
-		if (src == bl)
+
+	case SC_WEDDING:
+	case SC_XMAS:
+	case SC_SUMMER:
+	case SC_HANBOK:
+	case SC_OKTOBERFEST:
+		if (!vd)
 			return 0;
-		else {
-			struct status_change *tsc = status_get_sc(bl);
-			// Failed if the target is already marked and the new marker that isn't same marker
-			if (tsc && tsc->data[type] && tsc->data[type]->val2 != src->id)
-				return 0;
-		}
 		break;
 	}
 
 	// Check for BOSS resistances
-	if(status->mode&MD_BOSS && !(flag&1)) {
+	if(status->mode&MD_BOSS && !(flag&SCSTART_NOAVOID)) {
 		if (type>=SC_COMMON_MIN && type <= SC_COMMON_MAX)
 			return 0;
 		switch (type) {
@@ -7953,7 +7952,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 		}
 	}
 	// Check for mvp resistance // atm only those who OS
-	if(status->mode&MD_MVP && !(flag&1)) {
+	if(status->mode&MD_MVP && !(flag&SCSTART_NOAVOID)) {
 		 switch (type) {
 		 case SC_COMA:
 		// continue list...
@@ -8274,7 +8273,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 			case SC__LAZINESS:
 			case SC__WEAKNESS:
 			case SC__UNLUCKY:
-			case SC__CHAOS:
+			//case SC__CHAOS:
 				return 0;
 			case SC_COMBO:
 			case SC_DANCING:
@@ -8337,11 +8336,26 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 		}
 	}
 
-	vd = status_get_viewdata(bl);
 	calc_flag = StatusChangeFlagTable[type];
-	if(!(flag&4)) // &4 - Do not parse val settings when loading SCs
+	if(!(flag&SCSTART_LOADED)) // &4 - Do not parse val settings when loading SCs
 	switch(type)
 	{
+		/* Permanent effects */
+		case SC_AETERNA:
+		case SC_MODECHANGE:
+		case SC_WEIGHT50:
+		case SC_WEIGHT90:
+		case SC_BROKENWEAPON:
+		case SC_BROKENARMOR:
+		case SC_READYSTORM:
+		case SC_READYDOWN:
+		case SC_READYCOUNTER:
+		case SC_READYTURN:
+		case SC_DODGE:
+		case SC_PUSH_CART:
+			tick = -1;
+			break;
+
 		case SC_DECREASEAGI:
 		case SC_INCREASEAGI:
 		case SC_ADORAMUS:
@@ -8351,17 +8365,17 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 			break;
 		case SC_ENDURE:
 			val2 = 7; // Hit-count [Celest]
-			if( !(flag&1) && (bl->type&(BL_PC|BL_MER)) && !map_flag_gvg(bl->m) && !map[bl->m].flag.battleground && !val4 ) {
+			if( !(flag&SCSTART_NOAVOID) && (bl->type&(BL_PC|BL_MER)) && !map_flag_gvg(bl->m) && !map[bl->m].flag.battleground && !val4 ) {
 				struct map_session_data *tsd;
 				if( sd ) {
 					int i;
 					for( i = 0; i < MAX_DEVOTION; i++ ) {
 						if( sd->devotion[i] && (tsd = map_id2sd(sd->devotion[i])) )
-							status_change_start(src,&tsd->bl, type, 10000, val1, val2, val3, val4, tick, 1|16);
+							status_change_start(src,&tsd->bl, type, 10000, val1, val2, val3, val4, tick, SCSTART_NOAVOID|SCSTART_NOICON);
 					}
 				}
 				else if( bl->type == BL_MER && ((TBL_MER*)bl)->devotion_flag && (tsd = ((TBL_MER*)bl)->master) )
-					status_change_start(src,&tsd->bl, type, 10000, val1, val2, val3, val4, tick, 1);
+					status_change_start(src,&tsd->bl, type, 10000, val1, val2, val3, val4, tick, SCSTART_NOAVOID|SCSTART_NOICON);
 			}
 			// val4 signals infinite endure (if val4 == 2 it is infinite endure from Berserk)
 			if( val4 )
@@ -8445,17 +8459,17 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 		case SC_REFLECTSHIELD:
 			val2 = 10+val1*3; // %Dmg reflected
 			// val4 used to mark if reflect shield is an inheritance bonus from Devotion
-			if( !(flag&1) && (bl->type&(BL_PC|BL_MER)) ) {
+			if( !(flag&SCSTART_NOAVOID) && (bl->type&(BL_PC|BL_MER)) ) {
 				struct map_session_data *tsd;
 				if( sd ) {
 					int i;
 					for( i = 0; i < MAX_DEVOTION; i++ ) {
 						if( sd->devotion[i] && (tsd = map_id2sd(sd->devotion[i])) )
-							status_change_start(src,&tsd->bl, type, 10000, val1, val2, 0, 1, tick, 1|16);
+							status_change_start(src,&tsd->bl, type, 10000, val1, val2, 0, 1, tick, SCSTART_NOAVOID|SCSTART_NOICON);
 					}
 				}
 				else if( bl->type == BL_MER && ((TBL_MER*)bl)->devotion_flag && (tsd = ((TBL_MER*)bl)->master) )
-					status_change_start(src,&tsd->bl, type, 10000, val1, val2, 0, 1, tick, 1);
+					status_change_start(src,&tsd->bl, type, 10000, val1, val2, 0, 1, tick, SCSTART_NOAVOID|SCSTART_NOICON);
 			}
 			break;
 		case SC_STRIPWEAPON:
@@ -8481,25 +8495,44 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 			val4 = 5 + val1*2; // Chance of casting
 			break;
 		case SC_VOLCANO:
-			val2 = val1*10; // Watk increase
+			{
+				int8 enchant_eff[] = { 10, 14, 17, 19, 20 }; // Enchant addition
+				uint8 i = max((val1-1)%5, 0);
+
+				val2 = val1*10; // Watk increase
 #ifndef RENEWAL
-			if (status->def_ele != ELE_FIRE)
-				val2 = 0;
+				if (status->def_ele != ELE_FIRE)
+					val2 = 0;
 #endif
+				val3 = enchant_eff[i];
+			}
 			break;
 		case SC_VIOLENTGALE:
-			val2 = val1*3; // Flee increase
+			{
+				int8 enchant_eff[] = { 10, 14, 17, 19, 20 }; // Enchant addition
+				uint8 i = max((val1-1)%5, 0);
+
+				val2 = val1*3; // Flee increase
 #ifndef RENEWAL
-			if (status->def_ele != ELE_WIND)
-				val2 = 0;
+				if (status->def_ele != ELE_WIND)
+					val2 = 0;
 #endif
+				val3 = enchant_eff[i];
+			}
 			break;
 		case SC_DELUGE:
-			val2 = deluge_eff[val1-1]; // HP increase
+			{
+				int8 deluge_eff[]  = {  5,  9, 12, 14, 15 }; // HP addition rate n/100
+				int8 enchant_eff[] = { 10, 14, 17, 19, 20 }; // Enchant addition
+				uint8 i = max((val1-1)%5, 0);
+
+				val2 = deluge_eff[i]; // HP increase
 #ifndef RENEWAL
-			if(status->def_ele != ELE_WATER)
-				val2 = 0;
+				if (status->def_ele != ELE_WATER)
+					val2 = 0;
 #endif
+				val3 = enchant_eff[i];
+			}
 			break;
 		case SC_SUITON:
 			if (!val2 || (sd && (sd->class_&MAPID_BASEMASK) == MAPID_NINJA)) {
@@ -8551,15 +8584,6 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 			val2 = 50*(2+type-SC_ASPDPOTION0);
 			break;
 
-		case SC_WEDDING:
-		case SC_XMAS:
-		case SC_SUMMER:
-		case SC_HANBOK:
-		case SC_OKTOBERFEST:
-			if (!vd) return 0;
-			// Store previous values as they could be removed.
-			unit_stop_attack(bl);
-			break;
 		case SC_NOCHAT:
 			// A hardcoded interval of 60 seconds is expected, as the time that SC_NOCHAT uses is defined by
 			// mmocharstatus.manner, each negative point results in 1 minute with this status activated.
@@ -8607,7 +8631,8 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 			break;
 
 		case SC_CONFUSION:
-			clif_emotion(bl,E_WHAT);
+			if (!val4)
+				clif_emotion(bl,E_WHAT);
 			break;
 		case SC_BLEEDING:
 			val4 = tick/10000;
@@ -8674,24 +8699,8 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 			tick_time = 10; // [GodLesZ] tick time
 			break;
 
-		/* Permanent effects */
-		case SC_AETERNA:
-		case SC_MODECHANGE:
-		case SC_WEIGHT50:
-		case SC_WEIGHT90:
-		case SC_BROKENWEAPON:
-		case SC_BROKENARMOR:
-		case SC_READYSTORM:
-		case SC_READYDOWN:
-		case SC_READYCOUNTER:
-		case SC_READYTURN:
-		case SC_DODGE:
-		case SC_PUSH_CART:
-			tick = -1;
-			break;
-
 		case SC_AUTOGUARD:
-			if( !(flag&1) ) {
+			if( !(flag&SCSTART_NOAVOID) ) {
 				struct map_session_data *tsd;
 				int i;
 				for( i = val2 = 0; i < val1; i++) {
@@ -8703,17 +8712,17 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 					if( sd ) {
 						for( i = 0; i < MAX_DEVOTION; i++ ) {
 							if( sd->devotion[i] && (tsd = map_id2sd(sd->devotion[i])) )
-								status_change_start(src,&tsd->bl, type, 10000, val1, val2, 0, 0, tick, 1|16);
+								status_change_start(src,&tsd->bl, type, 10000, val1, val2, 0, 0, tick, SCSTART_NOAVOID|SCSTART_NOICON);
 						}
 					}
 					else if( bl->type == BL_MER && ((TBL_MER*)bl)->devotion_flag && (tsd = ((TBL_MER*)bl)->master) )
-						status_change_start(src,&tsd->bl, type, 10000, val1, val2, 0, 0, tick, 1);
+						status_change_start(src,&tsd->bl, type, 10000, val1, val2, 0, 0, tick, SCSTART_NOAVOID|SCSTART_NOICON);
 				}
 			}
 			break;
 
 		case SC_DEFENDER:
-			if (!(flag&1)) {
+			if (!(flag&SCSTART_NOAVOID)) {
 				val2 = 5 + 15*val1; // Damage reduction
 				val3 = 0; // Unused, previously speed adjustment
 				val4 = 250 - 50*val1; // Aspd adjustment
@@ -8723,7 +8732,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 					int i;
 					for (i = 0; i < MAX_DEVOTION; i++) { // See if there are devoted characters, and pass the status to them. [Skotlex]
 						if (sd->devotion[i] && (tsd = map_id2sd(sd->devotion[i])))
-							status_change_start(src,&tsd->bl,type,10000,val1,5+val1*5,val3,val4,tick,1);
+							status_change_start(src,&tsd->bl,type,10000,val1,5+val1*5,val3,val4,tick,SCSTART_NOAVOID);
 					}
 				}
 			}
@@ -8848,7 +8857,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 				while( i >= 0 ) {
 					enum sc_type type2 = types[i];
 					if( d_sc->data[type2] )
-						status_change_start(d_bl, bl, type2, 10000, d_sc->data[type2]->val1, 0, 0, (type2 == SC_REFLECTSHIELD ? 1 : 0), skill_get_time(status_sc2skill(type2),d_sc->data[type2]->val1), (type2 == SC_DEFENDER) ? 1 : 1|16);
+						status_change_start(d_bl, bl, type2, 10000, d_sc->data[type2]->val1, 0, 0, (type2 == SC_REFLECTSHIELD ? 1 : 0), skill_get_time(status_sc2skill(type2),d_sc->data[type2]->val1), (type2 == SC_DEFENDER) ? 1 : SCSTART_NOAVOID|SCSTART_NOICON);
 					i--;
 				}
 			}
@@ -9239,7 +9248,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 			tick_time = 4000; // [GodLesZ] tick time
 			break;
 		case SC_PYREXIA:
-			status_change_start(src,bl,SC_BLIND,10000,val1,0,0,0,30000,11); // Blind status that last for 30 seconds
+			status_change_start(src,bl,SC_BLIND,10000,val1,0,0,0,30000,SCSTART_NOAVOID|SCSTART_NOTICKDEF|SCSTART_NORATEDEF); // Blind status that last for 30 seconds
 			val4 = tick / 3000;
 			tick_time = 3000; // [GodLesZ] tick time
 			break;
@@ -9355,14 +9364,14 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 			break;
 		case SC__UNLUCKY:
 		{
-			short rand_eff; 
+			sc_type rand_eff; 
 			switch(rand() % 3) {
 				case 1: rand_eff = SC_BLIND; break;
 				case 2: rand_eff = SC_SILENCE; break;
 				default: rand_eff = SC_POISON; break;
 			}
 			val2 = 10 * val1; // Crit and Flee2 Reduction
-			status_change_start(src,bl,rand_eff,10000,val1,0,0,0,tick,10);
+			status_change_start(src,bl,rand_eff,10000,val1,0,0,0,tick,SCSTART_NOTICKDEF|SCSTART_NORATEDEF);
 			break;
 		}
 		case SC__WEAKNESS:
@@ -9842,11 +9851,12 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 			val3 = val1 * 25; // -movespeed (custom)
 			break;
 		case SC_C_MARKER:
-			val2 = src->id;
-			val3 = 10; //-10% flee
+			// val1 = skill_lv
+			// val2 = src_id
+			val3 = 10; // -10 flee
 			//Start timer to send mark on mini map
 			val4 = tick/1000;
-			tick_time = 1000;
+			tick_time = 1000; // Sends every 1 seconds
 			break;
 		case SC_H_MINE:
 			val2 = src->id;
@@ -9854,8 +9864,9 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 		case SC_HEAT_BARREL:
 			//kRO Update 2014-02-26
 			{
-				short n = 10;
-				if (sd) n = sd->spiritball_old;
+				uint8 n = 10;
+				if (sd)
+					n = (uint8)sd->spiritball_old;
 				val2 = val1 * 5; // -fixed casttime (custom)
 				val3 = val1 * n / 5; // +aspd (custom)
 				val4 = 75 - val1 * 5; // -flee
@@ -9863,8 +9874,9 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 			break;
 		case SC_P_ALTER:
 			{
-				short n = 10;
-				if (sd) n = sd->spiritball_old;
+				uint8 n = 10;
+				if (sd)
+					n = (uint8)sd->spiritball_old;
 				val2 = val1 * n * 2; // +atk (custom)
 				val3 = val1 * 15; // +def (custom)
 			}
@@ -9872,7 +9884,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 		case SC_E_CHAIN:
 			val2 = 10;
 			if (sd)
-				val2 = (uint8)sd->spiritball_old;
+				val2 = sd->spiritball_old;
 			break;
 		case SC_ANTI_M_BLAST:
 			val2 = val1 * 10;
@@ -10007,7 +10019,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 		case SC_BITE:
 		case SC_THORNSTRAP:
 		case SC__MANHOLE:
-		case SC__CHAOS:
+		//case SC__CHAOS:
 		case SC_CRYSTALIZE:
 		case SC_CURSEDCIRCLE_ATKER:
 		case SC_FEAR:
@@ -10017,11 +10029,11 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 		case SC_PARALYSIS:
 		case SC_MAGNETICFIELD:
 			unit_stop_walking(bl,1);
-		break;
+			break;
 		case SC_ANKLE:
 			if( battle_config.skill_trap_type || !map_flag_gvg(bl->m) )
 				unit_stop_walking(bl,1);
-		break;
+			break;
 		case SC_HIDING:
 		case SC_CLOAKING:
 		case SC_CLOAKINGEXCEED:
@@ -10031,16 +10043,21 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 		case SC_CAMOUFLAGE:
 		case SC_VOICEOFSIREN:
 		case SC_HEAT_BARREL_AFTER:
+		case SC_WEDDING:
+		case SC_XMAS:
+		case SC_SUMMER:
+		case SC_HANBOK:
+		case SC_OKTOBERFEST:
 			unit_stop_attack(bl);
-		break;
+			break;
 		case SC_SILENCE:
 			if (battle_config.sc_castcancel&bl->type)
 				unit_skillcastcancel(bl, 0);
-		break;
+			break;
 		case SC_VACUUM_EXTREME:
 			if (!map_flag_gvg(bl->m))
 				unit_stop_walking(bl, 1);
-		break;
+			break;
 		case SC_ITEMSCRIPT: // Shows Buff Icons
 			if (sd && val2 != SI_BLANK)
 				clif_status_change(bl, (enum si_type)val2, 1, tick, 0, 0, 0);
@@ -10231,7 +10248,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 		calc_flag&=~SCB_DYE;
 	}
 
-	if(!(flag&16) && !(flag&4 && StatusDisplayType[type]))
+	if(!(flag&SCSTART_NOICON) && !(flag&SCSTART_LOADED && StatusDisplayType[type]))
 		clif_status_change(bl,StatusIconChangeTable[type],1,tick,(val_flag&1)?val1:1,(val_flag&2)?val2:0,(val_flag&4)?val3:0);
 
 	// Used as temporary storage for scs with interval ticks, so that the actual duration is sent to the client first.
@@ -10333,7 +10350,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 		case SC_C_MARKER:
 			//Send mini-map, don't wait for first timer triggered
 			if (src->type == BL_PC && (sd = map_id2sd(src->id)))
-				clif_crimson_marker(sd->fd,bl,false);
+				clif_crimson_marker(sd, bl, false);
 			break;
 	}
 
@@ -10495,7 +10512,7 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const
 	struct status_change_entry *sce;
 	struct status_data *status;
 	struct view_data *vd;
-	int opt_flag=0, calc_flag,temp_n = 0;
+	int opt_flag = 0, calc_flag;
 
 	nullpo_ret(bl);
 
@@ -10542,11 +10559,6 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const
 	if ( StatusChangeStateTable[type] )
 		status_calc_state(bl,sc,( enum scs_flag ) StatusChangeStateTable[type],false);
 
-	switch (type) {
-		case SC_H_MINE:		temp_n = sc->data[type]->val3;	break;	// If ended by RL_FLICKER, don't drop the trap
-		case SC_C_MARKER:	temp_n = sc->data[type]->val2;	break;	// Player who gave mark
-	}
-
 	sc->data[type] = NULL;
 
 	if (sd && StatusDisplayType[type])
@@ -10984,15 +10996,15 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const
 		case SC_C_MARKER:
 			{
 				// Remove mark data from caster
-				struct map_session_data *caster = map_id2sd(temp_n);
+				struct map_session_data *caster = map_id2sd(sce->val2);
 				uint8 i = 0;
 
-				if (!caster || !&caster->c_marker || !caster->c_marker.target)
+				if (!caster)
 					break;
-				ARR_FIND(0,MAX_SKILL_CRIMSON_MARKER,i,caster->c_marker.target[i] == bl->id);
+				ARR_FIND(0,MAX_SKILL_CRIMSON_MARKER,i,caster->c_marker[i] == bl->id);
 				if (i < MAX_SKILL_CRIMSON_MARKER) {
-					caster->c_marker.target[i] = 0;
-					clif_crimson_marker(caster->fd,bl,true);
+					caster->c_marker[i] = 0;
+					clif_crimson_marker(caster, bl, true);
 				}
 			}
 			break;
@@ -11000,15 +11012,17 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const
 			{
 				// Drop the material from target if expired
 				struct item it;
-				if (temp_n)
+				struct map_session_data *caster = NULL;
+
+				if (sce->val3 || status_isdead(bl) || !(caster = map_id2sd(sce->val2)))
 					break;
 				if (!itemdb_exists(skill_get_itemid(RL_H_MINE,0)))
 					break;
-				memset(&it,0,sizeof(it));
+				memset(&it, 0, sizeof(it));
 				it.nameid = skill_get_itemid(RL_H_MINE,0);
 				it.amount = max(skill_get_itemqty(RL_H_MINE,0),1);
 				it.identify = 1;
-				map_addflooritem(&it,it.amount,bl->m,bl->x,bl->y,0,0,0,4);
+				map_addflooritem(&it, it.amount, bl->m,bl->x, bl->y, caster->status.char_id, 0, 0, 4);
 			}
 			break;
 	}
@@ -11646,15 +11660,18 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data)
 			}
 
 			if( !flag ) { // Random Skill Cast
-				if (sd && !pc_issit(sd)) { // Can't cast if sit
-					int mushroom_skill_id = 0;
+				if (skill_magicmushroom_count && sd && !pc_issit(sd)) { // Can't cast if sit
+					int mushroom_skill_id = 0, checked = 0, checked_max = MAX_SKILL_MAGICMUSHROOM_DB * 3;
 					unit_stop_attack(bl);
 					unit_skillcastcancel(bl,1);
 					do {
 						int i = rnd() % MAX_SKILL_MAGICMUSHROOM_DB;
 						mushroom_skill_id = skill_magicmushroom_db[i].skill_id;
 					}
-					while( mushroom_skill_id == 0 );
+					while( checked++ < checked_max && mushroom_skill_id == 0 );
+
+					if (!skill_get_index(mushroom_skill_id))
+						break;
 
 					switch( skill_get_casttype(mushroom_skill_id) ) { // Magic Mushroom skills are buffs or area damage
 						case CAST_GROUND:
@@ -12114,17 +12131,18 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data)
 		break;
 	case SC_C_MARKER:
 		if( --(sce->val4) >= 0 ) {
-			TBL_PC *tsd = map_id2sd(sce->val2);
-			if (!tsd || tsd->bl.m != bl->m) //End the SC if caster isn't in same map
+			TBL_PC *caster = map_id2sd(sce->val2);
+			if (!caster || caster->bl.m != bl->m) //End the SC if caster isn't in same map
 				break;
 			sc_timer_next(1000 + tick, status_change_timer, bl->id, data);
-			clif_crimson_marker(tsd->fd,bl,false);
+			clif_crimson_marker(caster, bl, false);
 			return 0;
 		}
 		break;
 	}
 
 	// Default for all non-handled control paths is to end the status
+
 	return status_change_end( bl,type,tid );
 #undef sc_timer_next
 }
@@ -12474,7 +12492,7 @@ int status_change_spread( struct block_list *src, struct block_list *bl )
 			data.val2 = sc->data[i]->val2;
 			data.val3 = sc->data[i]->val3;
 			data.val4 = sc->data[i]->val4;
-			status_change_start(src,bl,(sc_type)i,10000,data.val1,data.val2,data.val3,data.val4,data.tick,1|2|8);
+			status_change_start(src,bl,(sc_type)i,10000,data.val1,data.val2,data.val3,data.val4,data.tick,SCSTART_NOAVOID|SCSTART_NOTICKDEF|SCSTART_NORATEDEF);
 			flag = 1;
 		}
 	}

+ 15 - 5
src/map/status.h

@@ -1732,6 +1732,16 @@ enum e_status_calc_opt {
 	SCO_FORCE = 0x2, /* Only relevant to BL_PC types, ensures call bypasses the queue caused by delayed damage */
 };
 
+/// Flags for status_change_start and status_get_sc_def
+enum e_status_change_start_flags {
+	SCSTART_NONE       = 0x00,
+	SCSTART_NOAVOID    = 0x01, /// Cannot be avoided (it has to start)
+	SCSTART_NOTICKDEF  = 0x02, /// Tick should not be reduced (by statuses or bonuses)
+	SCSTART_LOADED     = 0x04, /// When sc_data loaded (fetched from table), no values (val1 ~ val4) have to be altered/recalculate
+	SCSTART_NORATEDEF  = 0x08, /// Rate should not be reduced (by statuses or bonuses)
+	SCSTART_NOICON     = 0x10, /// Status icon won't be sent to client
+};
+
 ///Enum for bonus_script's flag [Cydh]
 enum e_bonus_script_flags {
 	BSF_REM_ON_DEAD				= 0x001, ///Removed when dead
@@ -1995,13 +2005,13 @@ struct status_change *status_get_sc(struct block_list *bl);
 int status_isdead(struct block_list *bl);
 int status_isimmune(struct block_list *bl);
 
-int status_get_sc_def(struct block_list *src,struct block_list *bl, enum sc_type type, int rate, int tick, int flag);
+int status_get_sc_def(struct block_list *src,struct block_list *bl, enum sc_type type, int rate, int tick, unsigned char flag);
 //Short version, receives rate in 1->100 range, and does not uses a flag setting.
-#define sc_start(src, bl, type, rate, val1, tick) status_change_start(src,bl,type,100*(rate),val1,0,0,0,tick,0)
-#define sc_start2(src, bl, type, rate, val1, val2, tick) status_change_start(src,bl,type,100*(rate),val1,val2,0,0,tick,0)
-#define sc_start4(src, bl, type, rate, val1, val2, val3, val4, tick) status_change_start(src,bl,type,100*(rate),val1,val2,val3,val4,tick,0)
+#define sc_start(src, bl, type, rate, val1, tick) status_change_start(src,bl,type,100*(rate),val1,0,0,0,tick,SCSTART_NONE)
+#define sc_start2(src, bl, type, rate, val1, val2, tick) status_change_start(src,bl,type,100*(rate),val1,val2,0,0,tick,SCSTART_NONE)
+#define sc_start4(src, bl, type, rate, val1, val2, val3, val4, tick) status_change_start(src,bl,type,100*(rate),val1,val2,val3,val4,tick,SCSTART_NONE)
 
-int status_change_start(struct block_list* src, struct block_list* bl,enum sc_type type,int rate,int val1,int val2,int val3,int val4,int tick,int flag);
+int status_change_start(struct block_list* src, struct block_list* bl,enum sc_type type,int rate,int val1,int val2,int val3,int val4,int tick,unsigned char flag);
 int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const char* file, int line);
 #define status_change_end(bl,type,tid) status_change_end_(bl,type,tid,__FILE__,__LINE__)
 int kaahi_heal_timer(int tid, unsigned int tick, int id, intptr_t data);

+ 19 - 2
src/map/unit.c

@@ -934,8 +934,12 @@ int unit_blown(struct block_list* bl, int dx, int dy, int count, int flag)
 		if(dx || dy) {
 			map_foreachinmovearea(clif_outsight, bl, AREA_SIZE, dx, dy, bl->type == BL_PC ? BL_ALL : BL_PC, bl);
 
-			if(su)
-				skill_unit_move_unit_group(su->group, bl->m, dx, dy);
+			if(su) {
+				if (su->group && skill_get_unit_flag(su->group->skill_id)&UF_KNOCKBACK_GROUP)
+					skill_unit_move_unit_group(su->group, bl->m, dx, dy);
+				else
+					skill_unit_move_unit(bl, nx, ny);
+			}
 			else
 				map_moveblock(bl, nx, ny, gettick());
 
@@ -1424,6 +1428,19 @@ int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill_id, ui
 					}
 				}
 				break;
+			case RL_C_MARKER:
+				{
+					uint8 i = 0;
+					ARR_FIND(0, MAX_SKILL_CRIMSON_MARKER, i, sd->c_marker[i] == target_id);
+					if (i == MAX_SKILL_CRIMSON_MARKER) {
+						ARR_FIND(0, MAX_SKILL_CRIMSON_MARKER, i, sd->c_marker[i] == 0);
+						if (i == MAX_SKILL_CRIMSON_MARKER) { // No free slots, skill Fail
+							clif_skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0);
+							return 0;
+						}
+					}
+				}
+				break;
 		}
 		if (!skill_check_condition_castbegin(sd, skill_id, skill_lv))
 			return 0;

+ 9 - 9
tools/check-doc.pl

@@ -24,8 +24,8 @@ Main($sCmd,$sTarget);
 
 sub GetArgs {
     GetOptions(
-    'cmd=s' => \$sCmd,	 # wich command to run
-    'atcf=s' => \$sAtcf, #atc doc file
+    'cmd=s' => \$sCmd,	 # which command to run
+    'atcf=s' => \$sAtcf, #atcommand doc file
     'scriptf=s' => \$sSctf, #script doc file
     'inc_atcf=s' => \$sInc_atcf, #include script doc file (for customs doc)
     'inc_scrtf=s' => \$sInc_scrtf, #include script doc file (for customs doc)
@@ -35,7 +35,7 @@ sub GetArgs {
     ) or $sHelp=1; #display help if invalid option	
 	
     if( $sHelp ) {
-	print "Incorect option specified, available option are:\n"
+	print "Incorrect option specified, available options are:\n"
 	    ."\t --atcf filename => file (specify atcommand doc to use)\n"
 	    ."\t --inc_atcf filename => include file (specify atcommand doc to use)\n"
 	    ."\t --scriptf filename => file (specify script doc to use)\n"
@@ -46,12 +46,12 @@ sub GetArgs {
 	exit;
     }
     unless($sTarget =~ /$sValidTarget/i){
-    	print "Incorect target specified, available target are:\n"
+    	print "Incorrect target specified, available target is:\n"
 	    ."\t --target => target (specify wich check to run [(default)$sValidTarget])\n";
 		exit;
     }
     unless($sCmd =~ /$sValidCmd/i){
-    	print "Incorect command specified, available command are:\n"
+    	print "Incorrect command specified, available command is:\n"
 	    ."\t --cmd => cmd (specify wich command to run [(default)$sValidCmd])\n";
 		exit;
     }
@@ -65,14 +65,14 @@ sub Main { my ($sCmd,$sTarget) = @_;
 	if($sTarget=~/script/i){ #find which script commands are missing from doc/script_commands.txt
 		my $raSct_cmd = Script_GetCmd();
 		if($sCmd =~ /ls/i) {
-			print "The list of script-command found are = \n[ @$raSct_cmd ] \n\n";
+			print "The list of script-commands found are = \n[ @$raSct_cmd ] \n\n";
 		}
 		if($sCmd =~ /chk/i) { Script_Chk($raSct_cmd); }
 	}
 	if($sTarget=~/atc/i){ #find which atcommands are missing from doc/atcommands.txt
 		my $raAct_cmd = Atc_GetCmd();
 		if($sCmd =~ /ls/i) {
-			print "The list of atcommand found are = \n[ @$raAct_cmd ] \n\n";
+			print "The list of atcommands found are = \n[ @$raAct_cmd ] \n\n";
 		}
 		if($sCmd =~ /chk/i) { Atc_Chk($raAct_cmd); }
 	}
@@ -240,12 +240,12 @@ sub Atc_Chk {  my ($raDef_act) = @_;
 	if($sLeftOverChk){
 		my $raLeftover_sct = Chk(\@aDoc_act,$raDef_act); #we just inverse the chk for leftover
 		if(scalar(@$raLeftover_sct)){
-			print "Those atcommand command was found in doc but no source associated, leftover ? : {\n";
+			print "Those atcommands were found in doc but no source associated, leftover ? : {\n";
 			foreach(@$raLeftover_sct){
 				print "\t$_ \n";
 			}
 			print "}\n\n";
 		}
-		else { print "All atcommand in documentation match a source ATCMD, no leftover found\n"; }
+		else { print "All atcommands in documentation match a source ATCMD, no leftover found\n"; }
 	}
 }

Some files were not shown because too many files changed in this diff