Selaa lähdekoodia

Initial Release of Random Option System
* Added basic support for random option system
* Don't forget to import upgrade_20160814.sql and upgrade_20160814_log.sql to make your existing rAthena installation functional!

Jittapan Pluemsumran 8 vuotta sitten
vanhempi
commit
f296409ada

+ 194 - 0
db/const.txt

@@ -1637,6 +1637,200 @@ HAT_EF_WHITEBODY	49
 HAT_EF_WATER_BELOW2	50
 HAT_EF_FIREWORK  51
 
+RDMOPT_VAR_MAXHPAMOUNT	1
+RDMOPT_VAR_MAXSPAMOUNT	2
+RDMOPT_VAR_STRAMOUNT	3
+RDMOPT_VAR_AGIAMOUNT	4
+RDMOPT_VAR_VITAMOUNT	5
+RDMOPT_VAR_INTAMOUNT	6
+RDMOPT_VAR_DEXAMOUNT	7
+RDMOPT_VAR_LUKAMOUNT	8
+RDMOPT_VAR_MAXHPPERCENT	9
+RDMOPT_VAR_MAXSPPERCENT	10
+RDMOPT_VAR_HPACCELERATION	11
+RDMOPT_VAR_SPACCELERATION	12
+RDMOPT_VAR_ATKPERCENT	13
+RDMOPT_VAR_MAGICATKPERCENT	14
+RDMOPT_VAR_PLUSASPD	15
+RDMOPT_VAR_PLUSASPDPERCENT	16
+RDMOPT_VAR_ATTPOWER	17
+RDMOPT_VAR_HITSUCCESSVALUE	18
+RDMOPT_VAR_ATTMPOWER	19
+RDMOPT_VAR_ITEMDEFPOWER	20
+RDMOPT_VAR_MDEFPOWER	21
+RDMOPT_VAR_AVOIDSUCCESSVALUE	22
+RDMOPT_VAR_PLUSAVOIDSUCCESSVALUE	23
+RDMOPT_VAR_CRITICALSUCCESSVALUE	24
+RDMOPT_ATTR_TOLERACE_NOTHING	25
+RDMOPT_ATTR_TOLERACE_WATER	26
+RDMOPT_ATTR_TOLERACE_GROUND	27
+RDMOPT_ATTR_TOLERACE_FIRE	28
+RDMOPT_ATTR_TOLERACE_WIND	29
+RDMOPT_ATTR_TOLERACE_POISON	30
+RDMOPT_ATTR_TOLERACE_SAINT	31
+RDMOPT_ATTR_TOLERACE_DARKNESS	32
+RDMOPT_ATTR_TOLERACE_TELEKINESIS	33
+RDMOPT_ATTR_TOLERACE_UNDEAD	34
+RDMOPT_ATTR_TOLERACE_ALL	35
+RDMOPT_DAMAGE_PROPERTY_NOTHING_USER	36
+RDMOPT_DAMAGE_PROPERTY_NOTHING_TARGET	37
+RDMOPT_DAMAGE_PROPERTY_WATER_USER	38
+RDMOPT_DAMAGE_PROPERTY_WATER_TARGET	39
+RDMOPT_DAMAGE_PROPERTY_GROUND_USER	40
+RDMOPT_DAMAGE_PROPERTY_GROUND_TARGET	41
+RDMOPT_DAMAGE_PROPERTY_FIRE_USER	42
+RDMOPT_DAMAGE_PROPERTY_FIRE_TARGET	43
+RDMOPT_DAMAGE_PROPERTY_WIND_USER	44
+RDMOPT_DAMAGE_PROPERTY_WIND_TARGET	45
+RDMOPT_DAMAGE_PROPERTY_POISON_USER	46
+RDMOPT_DAMAGE_PROPERTY_POISON_TARGET	47
+RDMOPT_DAMAGE_PROPERTY_SAINT_USER	48
+RDMOPT_DAMAGE_PROPERTY_SAINT_TARGET	49
+RDMOPT_DAMAGE_PROPERTY_DARKNESS_USER	50
+RDMOPT_DAMAGE_PROPERTY_DARKNESS_TARGET	51
+RDMOPT_DAMAGE_PROPERTY_TELEKINESIS_USER	52
+RDMOPT_DAMAGE_PROPERTY_TELEKINESIS_TARGET	53
+RDMOPT_DAMAGE_PROPERTY_UNDEAD_USER	54
+RDMOPT_DAMAGE_PROPERTY_UNDEAD_TARGET	55
+RDMOPT_MDAMAGE_PROPERTY_NOTHING_USER	56
+RDMOPT_MDAMAGE_PROPERTY_NOTHING_TARGET	57
+RDMOPT_MDAMAGE_PROPERTY_WATER_USER	58
+RDMOPT_MDAMAGE_PROPERTY_WATER_TARGET	59
+RDMOPT_MDAMAGE_PROPERTY_GROUND_USER	60
+RDMOPT_MDAMAGE_PROPERTY_GROUND_TARGET	61
+RDMOPT_MDAMAGE_PROPERTY_FIRE_USER	62
+RDMOPT_MDAMAGE_PROPERTY_FIRE_TARGET	63
+RDMOPT_MDAMAGE_PROPERTY_WIND_USER	64
+RDMOPT_MDAMAGE_PROPERTY_WIND_TARGET	65
+RDMOPT_MDAMAGE_PROPERTY_POISON_USER	66
+RDMOPT_MDAMAGE_PROPERTY_POISON_TARGET	67
+RDMOPT_MDAMAGE_PROPERTY_SAINT_USER	68
+RDMOPT_MDAMAGE_PROPERTY_SAINT_TARGET	69
+RDMOPT_MDAMAGE_PROPERTY_DARKNESS_USER	70
+RDMOPT_MDAMAGE_PROPERTY_DARKNESS_TARGET	71
+RDMOPT_MDAMAGE_PROPERTY_TELEKINESIS_USER	72
+RDMOPT_MDAMAGE_PROPERTY_TELEKINESIS_TARGET	73
+RDMOPT_MDAMAGE_PROPERTY_UNDEAD_USER	74
+RDMOPT_MDAMAGE_PROPERTY_UNDEAD_TARGET	75
+RDMOPT_BODY_ATTR_NOTHING	76
+RDMOPT_BODY_ATTR_WATER	77
+RDMOPT_BODY_ATTR_GROUND	78
+RDMOPT_BODY_ATTR_FIRE	79
+RDMOPT_BODY_ATTR_WIND	80
+RDMOPT_BODY_ATTR_POISON	81
+RDMOPT_BODY_ATTR_SAINT	82
+RDMOPT_BODY_ATTR_DARKNESS	83
+RDMOPT_BODY_ATTR_TELEKINESIS	84
+RDMOPT_BODY_ATTR_UNDEAD	85
+RDMOPT_BODY_ATTR_ALL	86
+RDMOPT_RACE_TOLERACE_NOTHING	87
+RDMOPT_RACE_TOLERACE_UNDEAD	88
+RDMOPT_RACE_TOLERACE_ANIMAL	89
+RDMOPT_RACE_TOLERACE_PLANT	90
+RDMOPT_RACE_TOLERACE_INSECT	91
+RDMOPT_RACE_TOLERACE_FISHS	92
+RDMOPT_RACE_TOLERACE_DEVIL	93
+RDMOPT_RACE_TOLERACE_HUMAN	94
+RDMOPT_RACE_TOLERACE_ANGEL	95
+RDMOPT_RACE_TOLERACE_DRAGON	96
+RDMOPT_RACE_DAMAGE_NOTHING	97
+RDMOPT_RACE_DAMAGE_UNDEAD	98
+RDMOPT_RACE_DAMAGE_ANIMAL	99
+RDMOPT_RACE_DAMAGE_PLANT	100
+RDMOPT_RACE_DAMAGE_INSECT	101
+RDMOPT_RACE_DAMAGE_FISHS	102
+RDMOPT_RACE_DAMAGE_DEVIL	103
+RDMOPT_RACE_DAMAGE_HUMAN	104
+RDMOPT_RACE_DAMAGE_ANGEL	105
+RDMOPT_RACE_DAMAGE_DRAGON	106
+RDMOPT_RACE_MDAMAGE_NOTHING	107
+RDMOPT_RACE_MDAMAGE_UNDEAD	108
+RDMOPT_RACE_MDAMAGE_ANIMAL	109
+RDMOPT_RACE_MDAMAGE_PLANT	110
+RDMOPT_RACE_MDAMAGE_INSECT	111
+RDMOPT_RACE_MDAMAGE_FISHS	112
+RDMOPT_RACE_MDAMAGE_DEVIL	113
+RDMOPT_RACE_MDAMAGE_HUMAN	114
+RDMOPT_RACE_MDAMAGE_ANGEL	115
+RDMOPT_RACE_MDAMAGE_DRAGON	116
+RDMOPT_RACE_CRI_PERCENT_NOTHING	117
+RDMOPT_RACE_CRI_PERCENT_UNDEAD	118
+RDMOPT_RACE_CRI_PERCENT_ANIMAL	119
+RDMOPT_RACE_CRI_PERCENT_PLANT	120
+RDMOPT_RACE_CRI_PERCENT_INSECT	121
+RDMOPT_RACE_CRI_PERCENT_FISHS	122
+RDMOPT_RACE_CRI_PERCENT_DEVIL	123
+RDMOPT_RACE_CRI_PERCENT_HUMAN	124
+RDMOPT_RACE_CRI_PERCENT_ANGEL	125
+RDMOPT_RACE_CRI_PERCENT_DRAGON	126
+RDMOPT_RACE_IGNORE_DEF_PERCENT_NOTHING	127
+RDMOPT_RACE_IGNORE_DEF_PERCENT_UNDEAD	128
+RDMOPT_RACE_IGNORE_DEF_PERCENT_ANIMAL	129
+RDMOPT_RACE_IGNORE_DEF_PERCENT_PLANT	130
+RDMOPT_RACE_IGNORE_DEF_PERCENT_INSECT	131
+RDMOPT_RACE_IGNORE_DEF_PERCENT_FISHS	132
+RDMOPT_RACE_IGNORE_DEF_PERCENT_DEVIL	133
+RDMOPT_RACE_IGNORE_DEF_PERCENT_HUMAN	134
+RDMOPT_RACE_IGNORE_DEF_PERCENT_ANGEL	135
+RDMOPT_RACE_IGNORE_DEF_PERCENT_DRAGON	136
+RDMOPT_RACE_IGNORE_MDEF_PERCENT_NOTHING	137
+RDMOPT_RACE_IGNORE_MDEF_PERCENT_UNDEAD	138
+RDMOPT_RACE_IGNORE_MDEF_PERCENT_ANIMAL	139
+RDMOPT_RACE_IGNORE_MDEF_PERCENT_PLANT	140
+RDMOPT_RACE_IGNORE_MDEF_PERCENT_INSECT	141
+RDMOPT_RACE_IGNORE_MDEF_PERCENT_FISHS	142
+RDMOPT_RACE_IGNORE_MDEF_PERCENT_DEVIL	143
+RDMOPT_RACE_IGNORE_MDEF_PERCENT_HUMAN	144
+RDMOPT_RACE_IGNORE_MDEF_PERCENT_ANGEL	145
+RDMOPT_RACE_IGNORE_MDEF_PERCENT_DRAGON	146
+RDMOPT_CLASS_DAMAGE_NORMAL_TARGET	147
+RDMOPT_CLASS_DAMAGE_BOSS_TARGET	148
+RDMOPT_CLASS_DAMAGE_NORMAL_USER	149
+RDMOPT_CLASS_DAMAGE_BOSS_USER	150
+RDMOPT_CLASS_MDAMAGE_NORMAL	151
+RDMOPT_CLASS_MDAMAGE_BOSS	152
+RDMOPT_CLASS_IGNORE_DEF_PERCENT_NORMAL	153
+RDMOPT_CLASS_IGNORE_DEF_PERCENT_BOSS	154
+RDMOPT_CLASS_IGNORE_MDEF_PERCENT_NORMAL	155
+RDMOPT_CLASS_IGNORE_MDEF_PERCENT_BOSS	156
+RDMOPT_DAMAGE_SIZE_SMALL_TARGET	157
+RDMOPT_DAMAGE_SIZE_MIDIUM_TARGET	158
+RDMOPT_DAMAGE_SIZE_LARGE_TARGET	159
+RDMOPT_DAMAGE_SIZE_SMALL_USER	160
+RDMOPT_DAMAGE_SIZE_MIDIUM_USER	161
+RDMOPT_DAMAGE_SIZE_LARGE_USER	162
+RDMOPT_DAMAGE_SIZE_PERFECT	163
+RDMOPT_DAMAGE_CRI_TARGET	164
+RDMOPT_DAMAGE_CRI_USER	165
+RDMOPT_RANGE_ATTACK_DAMAGE_TARGET	166
+RDMOPT_RANGE_ATTACK_DAMAGE_USER	167
+RDMOPT_HEAL_VALUE	168
+RDMOPT_HEAL_MODIFY_PERCENT	169
+RDMOPT_DEC_SPELL_CAST_TIME	170
+RDMOPT_DEC_SPELL_DELAY_TIME	171
+RDMOPT_DEC_SP_CONSUMPTION	172
+RDMOPT_HP_DRAIN	173
+RDMOPT_SP_DRAIN	174
+RDMOPT_WEAPON_ATTR_NOTHING	175
+RDMOPT_WEAPON_ATTR_WATER	176
+RDMOPT_WEAPON_ATTR_GROUND	177
+RDMOPT_WEAPON_ATTR_FIRE	178
+RDMOPT_WEAPON_ATTR_WIND	179
+RDMOPT_WEAPON_ATTR_POISON	180
+RDMOPT_WEAPON_ATTR_SAINT	181
+RDMOPT_WEAPON_ATTR_DARKNESS	182
+RDMOPT_WEAPON_ATTR_TELEKINESIS	183
+RDMOPT_WEAPON_ATTR_UNDEAD	184
+RDMOPT_WEAPON_INDESTRUCTIBLE	185
+RDMOPT_BODY_INDESTRUCTIBLE	186
+RDMOPT_MDAMAGE_SIZE_SMALL_TARGET	187
+RDMOPT_MDAMAGE_SIZE_MIDIUM_TARGET	188
+RDMOPT_MDAMAGE_SIZE_LARGE_TARGET	189
+RDMOPT_MDAMAGE_SIZE_SMALL_USER	190
+RDMOPT_MDAMAGE_SIZE_MIDIUM_USER	191
+RDMOPT_MDAMAGE_SIZE_LARGE_USER	192
+//RDMOPT_ATTR_TOLERACE_ALL	193
+
 WARPNPC	45
 1_ETC_01	46
 1_M_01	47

+ 4 - 0
db/import-tmpl/item_randomopt_db.txt

@@ -0,0 +1,4 @@
+// Items Random Option Database	
+//
+// Structure of Database:
+// ID,{ Bonus Script }

+ 200 - 0
db/re/item_randomopt_db.txt

@@ -0,0 +1,200 @@
+// Items Random Option Database	
+//
+// Structure of Database:
+// ID,{ Bonus Script }
+RDMOPT_VAR_MAXHPAMOUNT,{ bonus bMaxHP,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_VAR_MAXSPAMOUNT,{ bonus bMaxSP,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_VAR_STRAMOUNT,{ bonus bStr,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_VAR_AGIAMOUNT,{ bonus bAgi,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_VAR_VITAMOUNT,{ bonus bVit,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_VAR_INTAMOUNT,{ bonus bInt,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_VAR_DEXAMOUNT,{ bonus bDex,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_VAR_LUKAMOUNT,{ bonus bLuk,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_VAR_MAXHPPERCENT,{ bonus bMaxHPrate,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_VAR_MAXSPPERCENT,{ bonus bMaxSPrate,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_VAR_HPACCELERATION,{ bonus bHPrecovRate,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_VAR_SPACCELERATION,{ bonus bSPrecovRate,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_VAR_ATKPERCENT,{ bonus bAtkRate,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_VAR_MAGICATKPERCENT,{ bonus bMatkRate,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_VAR_PLUSASPD,{ bonus bAspd,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_VAR_PLUSASPDPERCENT,{ bonus bAspdRate,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_VAR_ATTPOWER,{ bonus bAtk,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_VAR_HITSUCCESSVALUE,{ bonus bHit,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_VAR_ATTMPOWER,{ bonus bMatk,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_VAR_ITEMDEFPOWER,{ bonus bDef,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_VAR_MDEFPOWER,{ bonus bMdef,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_VAR_AVOIDSUCCESSVALUE,{ bonus bFlee,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_VAR_PLUSAVOIDSUCCESSVALUE,{ bonus bFlee2,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_VAR_CRITICALSUCCESSVALUE,{ bonus bCritical,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_ATTR_TOLERACE_NOTHING,{ bonus2 bSubEle,Ele_Neutral,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_ATTR_TOLERACE_WATER,{ bonus2 bSubEle,Ele_Water,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_ATTR_TOLERACE_GROUND,{ bonus2 bSubEle,Ele_Earth,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_ATTR_TOLERACE_FIRE,{ bonus2 bSubEle,Ele_Fire,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_ATTR_TOLERACE_WIND,{ bonus2 bSubEle,Ele_Wind,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_ATTR_TOLERACE_POISON,{ bonus2 bSubEle,Ele_Poison,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_ATTR_TOLERACE_SAINT,{ bonus2 bSubEle,Ele_Holy,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_ATTR_TOLERACE_DARKNESS,{ bonus2 bSubEle,Ele_Dark,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_ATTR_TOLERACE_TELEKINESIS,{ bonus2 bSubEle,Ele_Ghost,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_ATTR_TOLERACE_UNDEAD,{ bonus2 bSubEle,Ele_Undead,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_ATTR_TOLERACE_ALL,{ bonus2 bSubEle,Ele_All,getrandomoptinfo(ROA_VALUE); }
+// TODO: Confirm if damage reduction is implemented correctly.
+// kRO desc : <ELEMENT> 몬스터로부터 받는 물리 데미지 %d%% 감소.
+RDMOPT_DAMAGE_PROPERTY_NOTHING_USER,{ bonus3 bSubEle,Ele_Neutral,getrandomoptinfo(ROA_VALUE),BF_NORMAL; }
+RDMOPT_DAMAGE_PROPERTY_NOTHING_TARGET,{ bonus2 bAddEle,Ele_Neutral,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_DAMAGE_PROPERTY_WATER_USER,{ bonus3 bSubEle,Ele_Water,getrandomoptinfo(ROA_VALUE),BF_NORMAL; }
+RDMOPT_DAMAGE_PROPERTY_WATER_TARGET,{ bonus2 bAddEle,Ele_Water,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_DAMAGE_PROPERTY_GROUND_USER,{ bonus3 bSubEle,Ele_Earth,getrandomoptinfo(ROA_VALUE),BF_NORMAL; }
+RDMOPT_DAMAGE_PROPERTY_GROUND_TARGET,{ bonus2 bAddEle,Ele_Earth,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_DAMAGE_PROPERTY_FIRE_USER,{ bonus3 bSubEle,Ele_Fire,getrandomoptinfo(ROA_VALUE),BF_NORMAL; }
+RDMOPT_DAMAGE_PROPERTY_FIRE_TARGET,{ bonus2 bAddEle,Ele_Fire,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_DAMAGE_PROPERTY_WIND_USER,{ bonus3 bSubEle,Ele_Wind,getrandomoptinfo(ROA_VALUE),BF_NORMAL; }
+RDMOPT_DAMAGE_PROPERTY_WIND_TARGET,{ bonus2 bAddEle,Ele_Wind,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_DAMAGE_PROPERTY_POISON_USER,{ bonus3 bSubEle,Ele_Poison,getrandomoptinfo(ROA_VALUE),BF_NORMAL; }
+RDMOPT_DAMAGE_PROPERTY_POISON_TARGET,{ bonus2 bAddEle,Ele_Poison,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_DAMAGE_PROPERTY_SAINT_USER,{ bonus3 bSubEle,Ele_Holy,getrandomoptinfo(ROA_VALUE),BF_NORMAL; }
+RDMOPT_DAMAGE_PROPERTY_SAINT_TARGET,{ bonus2 bAddEle,Ele_Holy,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_DAMAGE_PROPERTY_DARKNESS_USER,{ bonus3 bSubEle,Ele_Dark,getrandomoptinfo(ROA_VALUE),BF_NORMAL; }
+RDMOPT_DAMAGE_PROPERTY_DARKNESS_TARGET,{ bonus2 bAddEle,Ele_Dark,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_DAMAGE_PROPERTY_TELEKINESIS_USER,{ bonus3 bSubEle,Ele_Ghost,getrandomoptinfo(ROA_VALUE),BF_NORMAL; }
+RDMOPT_DAMAGE_PROPERTY_TELEKINESIS_TARGET,{ bonus2 bAddEle,Ele_Ghost,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_DAMAGE_PROPERTY_UNDEAD_USER,{ bonus3 bSubEle,Ele_Undead,getrandomoptinfo(ROA_VALUE),BF_NORMAL; }
+RDMOPT_DAMAGE_PROPERTY_UNDEAD_TARGET,{ bonus2 bAddEle,Ele_Undead,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_MDAMAGE_PROPERTY_NOTHING_USER,{ bonus3 bSubEle,Ele_Neutral,getrandomoptinfo(ROA_VALUE),BF_MAGIC; }
+RDMOPT_MDAMAGE_PROPERTY_NOTHING_TARGET,{ bonus2 bMagicAddEle,Ele_Neutral,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_MDAMAGE_PROPERTY_WATER_USER,{ bonus3 bSubEle,Ele_Water,getrandomoptinfo(ROA_VALUE),BF_MAGIC; }
+RDMOPT_MDAMAGE_PROPERTY_WATER_TARGET,{ bonus2 bMagicAddEle,Ele_Water,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_MDAMAGE_PROPERTY_GROUND_USER,{ bonus3 bSubEle,Ele_Earth,getrandomoptinfo(ROA_VALUE),BF_MAGIC; }
+RDMOPT_MDAMAGE_PROPERTY_GROUND_TARGET,{ bonus2 bMagicAddEle,Ele_Earth,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_MDAMAGE_PROPERTY_FIRE_USER,{ bonus3 bSubEle,Ele_Fire,getrandomoptinfo(ROA_VALUE),BF_MAGIC; }
+RDMOPT_MDAMAGE_PROPERTY_FIRE_TARGET,{ bonus2 bMagicAddEle,Ele_Fire,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_MDAMAGE_PROPERTY_WIND_USER,{ bonus3 bSubEle,Ele_Wind,getrandomoptinfo(ROA_VALUE),BF_MAGIC; }
+RDMOPT_MDAMAGE_PROPERTY_WIND_TARGET,{ bonus2 bMagicAddEle,Ele_Wind,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_MDAMAGE_PROPERTY_POISON_USER,{ bonus3 bSubEle,Ele_Poison,getrandomoptinfo(ROA_VALUE),BF_MAGIC; }
+RDMOPT_MDAMAGE_PROPERTY_POISON_TARGET,{ bonus2 bMagicAddEle,Ele_Poison,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_MDAMAGE_PROPERTY_SAINT_USER,{ bonus3 bSubEle,Ele_Holy,getrandomoptinfo(ROA_VALUE),BF_MAGIC; }
+RDMOPT_MDAMAGE_PROPERTY_SAINT_TARGET,{ bonus2 bMagicAddEle,Ele_Holy,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_MDAMAGE_PROPERTY_DARKNESS_USER,{ bonus3 bSubEle,Ele_Dark,getrandomoptinfo(ROA_VALUE),BF_MAGIC; }
+RDMOPT_MDAMAGE_PROPERTY_DARKNESS_TARGET,{ bonus2 bMagicAddEle,Ele_Dark,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_MDAMAGE_PROPERTY_TELEKINESIS_USER,{ bonus3 bSubEle,Ele_Ghost,getrandomoptinfo(ROA_VALUE),BF_MAGIC; }
+RDMOPT_MDAMAGE_PROPERTY_TELEKINESIS_TARGET,{ bonus2 bMagicAddEle,Ele_Ghost,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_MDAMAGE_PROPERTY_UNDEAD_USER,{ bonus3 bSubEle,Ele_Undead,getrandomoptinfo(ROA_VALUE),BF_MAGIC; }
+RDMOPT_MDAMAGE_PROPERTY_UNDEAD_TARGET,{ bonus2 bMagicAddEle,Ele_Undead,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_BODY_ATTR_NOTHING,{ bonus bDefEle,Ele_Neutral; }
+RDMOPT_BODY_ATTR_WATER,{ bonus bDefEle,Ele_Water; }
+RDMOPT_BODY_ATTR_GROUND,{ bonus bDefEle,Ele_Earth; }
+RDMOPT_BODY_ATTR_FIRE,{ bonus bDefEle,Ele_Fire; }
+RDMOPT_BODY_ATTR_WIND,{ bonus bDefEle,Ele_Wind; }
+RDMOPT_BODY_ATTR_POISON,{ bonus bDefEle,Ele_Poison; }
+RDMOPT_BODY_ATTR_SAINT,{ bonus bDefEle,Ele_Holy; }
+RDMOPT_BODY_ATTR_DARKNESS,{ bonus bDefEle,Ele_Dark; }
+RDMOPT_BODY_ATTR_TELEKINESIS,{ bonus bDefEle,Ele_Ghost; }
+RDMOPT_BODY_ATTR_UNDEAD,{ bonus bDefEle,Ele_Undead; }
+//RDMOPT_BODY_ATTR_ALL,{ /* Needs more info */ }
+RDMOPT_RACE_TOLERACE_NOTHING,{ bonus2 bSubRace,RC_Formless,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_TOLERACE_UNDEAD,{ bonus2 bSubRace,RC_Undead,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_TOLERACE_ANIMAL,{ bonus2 bSubRace,RC_Brute,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_TOLERACE_PLANT,{ bonus2 bSubRace,RC_Plant,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_TOLERACE_INSECT,{ bonus2 bSubRace,RC_Insect,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_TOLERACE_FISHS,{ bonus2 bSubRace,RC_Fish,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_TOLERACE_DEVIL,{ bonus2 bSubRace,RC_Demon,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_TOLERACE_HUMAN,{ bonus2 bSubRace,RC_DemiHuman,getrandomoptinfo(ROA_VALUE); bonus2 bSubRace,RC_Player,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_TOLERACE_ANGEL,{ bonus2 bSubRace,RC_Angel,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_TOLERACE_DRAGON,{ bonus2 bSubRace,RC_Dragon,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_DAMAGE_NOTHING,{ bonus2 bAddRace,RC_Formless,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_DAMAGE_UNDEAD,{ bonus2 bAddRace,RC_Undead,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_DAMAGE_ANIMAL,{ bonus2 bAddRace,RC_Brute,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_DAMAGE_PLANT,{ bonus2 bAddRace,RC_Plant,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_DAMAGE_INSECT,{ bonus2 bAddRace,RC_Insect,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_DAMAGE_FISHS,{ bonus2 bAddRace,RC_Fish,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_DAMAGE_DEVIL,{ bonus2 bAddRace,RC_Demon,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_DAMAGE_HUMAN,{ bonus2 bAddRace,RC_DemiHuman,getrandomoptinfo(ROA_VALUE); bonus2 bAddRace,RC_Player,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_DAMAGE_ANGEL,{ bonus2 bAddRace,RC_Angel,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_DAMAGE_DRAGON,{ bonus2 bAddRace,RC_Dragon,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_MDAMAGE_NOTHING,{ bonus2 bMagicAddRace,RC_Formless,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_MDAMAGE_UNDEAD,{ bonus2 bMagicAddRace,RC_Undead,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_MDAMAGE_ANIMAL,{ bonus2 bMagicAddRace,RC_Brute,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_MDAMAGE_PLANT,{ bonus2 bMagicAddRace,RC_Plant,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_MDAMAGE_INSECT,{ bonus2 bMagicAddRace,RC_Insect,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_MDAMAGE_FISHS,{ bonus2 bMagicAddRace,RC_Fish,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_MDAMAGE_DEVIL,{ bonus2 bMagicAddRace,RC_Demon,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_MDAMAGE_HUMAN,{ bonus2 bMagicAddRace,RC_DemiHuman,getrandomoptinfo(ROA_VALUE); bonus2 bMagicAddRace,RC_Player,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_MDAMAGE_ANGEL,{ bonus2 bMagicAddRace,RC_Angel,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_MDAMAGE_DRAGON,{ bonus2 bMagicAddRace,RC_Dragon,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_CRI_PERCENT_NOTHING,{ bonus2 bCriticalAddRace,RC_Formless,getrandomoptinfo(ROA_VALUE)/10; }
+RDMOPT_RACE_CRI_PERCENT_UNDEAD,{ bonus2 bCriticalAddRace,RC_Undead,getrandomoptinfo(ROA_VALUE)/10; }
+RDMOPT_RACE_CRI_PERCENT_ANIMAL,{ bonus2 bCriticalAddRace,RC_Brute,getrandomoptinfo(ROA_VALUE)/10; }
+RDMOPT_RACE_CRI_PERCENT_PLANT,{ bonus2 bCriticalAddRace,RC_Plant,getrandomoptinfo(ROA_VALUE)/10; }
+RDMOPT_RACE_CRI_PERCENT_INSECT,{ bonus2 bCriticalAddRace,RC_Insect,getrandomoptinfo(ROA_VALUE)/10; }
+RDMOPT_RACE_CRI_PERCENT_FISHS,{ bonus2 bCriticalAddRace,RC_Fish,getrandomoptinfo(ROA_VALUE)/10; }
+RDMOPT_RACE_CRI_PERCENT_DEVIL,{ bonus2 bCriticalAddRace,RC_Demon,getrandomoptinfo(ROA_VALUE)/10; }
+RDMOPT_RACE_CRI_PERCENT_HUMAN,{ bonus2 bCriticalAddRace,RC_DemiHuman,getrandomoptinfo(ROA_VALUE)/10; bonus2 bCriticalAddRace,RC_Player,getrandomoptinfo(ROA_VALUE)/10; }
+RDMOPT_RACE_CRI_PERCENT_ANGEL,{ bonus2 bCriticalAddRace,RC_Angel,getrandomoptinfo(ROA_VALUE)/10; }
+RDMOPT_RACE_CRI_PERCENT_DRAGON,{ bonus2 bCriticalAddRace,RC_Dragon,getrandomoptinfo(ROA_VALUE)/10; }
+RDMOPT_RACE_IGNORE_DEF_PERCENT_NOTHING,{ bonus2 bIgnoreDefRaceRate,RC_Formless,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_IGNORE_DEF_PERCENT_UNDEAD,{ bonus2 bIgnoreDefRaceRate,RC_Undead,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_IGNORE_DEF_PERCENT_ANIMAL,{ bonus2 bIgnoreDefRaceRate,RC_Brute,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_IGNORE_DEF_PERCENT_PLANT,{ bonus2 bIgnoreDefRaceRate,RC_Plant,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_IGNORE_DEF_PERCENT_INSECT,{ bonus2 bIgnoreDefRaceRate,RC_Insect,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_IGNORE_DEF_PERCENT_FISHS,{ bonus2 bIgnoreDefRaceRate,RC_Fish,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_IGNORE_DEF_PERCENT_DEVIL,{ bonus2 bIgnoreDefRaceRate,RC_Demon,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_IGNORE_DEF_PERCENT_HUMAN,{ bonus2 bIgnoreDefRaceRate,RC_DemiHuman,getrandomoptinfo(ROA_VALUE); bonus2 bIgnoreDefRaceRate,RC_Player,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_IGNORE_DEF_PERCENT_ANGEL,{ bonus2 bIgnoreDefRaceRate,RC_Angel,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_IGNORE_DEF_PERCENT_DRAGON,{ bonus2 bIgnoreDefRaceRate,RC_Dragon,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_IGNORE_MDEF_PERCENT_NOTHING,{ bonus2 bIgnoreMdefRaceRate,RC_Formless,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_IGNORE_MDEF_PERCENT_UNDEAD,{ bonus2 bIgnoreMdefRaceRate,RC_Undead,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_IGNORE_MDEF_PERCENT_ANIMAL,{ bonus2 bIgnoreMdefRaceRate,RC_Brute,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_IGNORE_MDEF_PERCENT_PLANT,{ bonus2 bIgnoreMdefRaceRate,RC_Plant,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_IGNORE_MDEF_PERCENT_INSECT,{ bonus2 bIgnoreMdefRaceRate,RC_Insect,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_IGNORE_MDEF_PERCENT_FISHS,{ bonus2 bIgnoreMdefRaceRate,RC_Fish,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_IGNORE_MDEF_PERCENT_DEVIL,{ bonus2 bIgnoreMdefRaceRate,RC_Demon,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_IGNORE_MDEF_PERCENT_HUMAN,{ bonus2 bIgnoreMdefRaceRate,RC_DemiHuman,getrandomoptinfo(ROA_VALUE); bonus2 bIgnoreMdefRaceRate,RC_Player,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_IGNORE_MDEF_PERCENT_ANGEL,{ bonus2 bIgnoreMdefRaceRate,RC_Angel,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RACE_IGNORE_MDEF_PERCENT_DRAGON,{ bonus2 bIgnoreMdefRaceRate,RC_Dragon,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_CLASS_DAMAGE_NORMAL_TARGET,{ bonus2 bAddClass,Class_Normal,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_CLASS_DAMAGE_BOSS_TARGET,{ bonus2 bAddClass,Class_Boss,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_CLASS_DAMAGE_NORMAL_USER,{ bonus2 bSubClass,Class_Normal,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_CLASS_DAMAGE_BOSS_USER,{ bonus2 bSubClass,Class_Boss,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_CLASS_MDAMAGE_NORMAL,{ bonus2 bMagicAddClass,Class_Normal,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_CLASS_MDAMAGE_BOSS,{ bonus2 bMagicAddClass,Class_Boss,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_CLASS_IGNORE_DEF_PERCENT_NORMAL,{ bonus2 bIgnoreDefClassRate,Class_Normal,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_CLASS_IGNORE_DEF_PERCENT_BOSS,{ bonus2 bIgnoreDefClassRate,Class_Boss,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_CLASS_IGNORE_MDEF_PERCENT_NORMAL,{ bonus2 bIgnoreMdefClassRate,Class_Normal,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_CLASS_IGNORE_MDEF_PERCENT_BOSS,{ bonus2 bIgnoreMdefClassRate,Class_Boss,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_DAMAGE_SIZE_SMALL_TARGET,{ bonus2 bAddSize,Size_Small,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_DAMAGE_SIZE_MIDIUM_TARGET,{ bonus2 bAddSize,Size_Medium,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_DAMAGE_SIZE_LARGE_TARGET,{ bonus2 bAddSize,Size_Large,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_DAMAGE_SIZE_SMALL_USER,{ bonus2 bSubSize,Size_Small,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_DAMAGE_SIZE_MIDIUM_USER,{ bonus2 bSubSize,Size_Medium,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_DAMAGE_SIZE_LARGE_USER,{ bonus2 bSubSize,Size_Large,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_DAMAGE_SIZE_PERFECT,{ bonus bNoSizeFix,1; }
+RDMOPT_DAMAGE_CRI_TARGET,{ bonus bCritAtkRate,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_DAMAGE_CRI_USER,{ bonus bCriticalDef,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RANGE_ATTACK_DAMAGE_TARGET,{ bonus bLongAtkRate,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_RANGE_ATTACK_DAMAGE_USER,{ bonus bLongAtkDef,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_HEAL_VALUE,{ bonus bHealPower,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_HEAL_MODIFY_PERCENT,{ bonus bHealPower2,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_DEC_SPELL_CAST_TIME,{ bonus bVariableCastrate,-(getrandomoptinfo(ROA_VALUE));}
+RDMOPT_DEC_SPELL_DELAY_TIME,{ bonus bDelayrate,-(getrandomoptinfo(ROA_VALUE)); }
+RDMOPT_DEC_SP_CONSUMPTION,{ bonus bUseSPrate,-(getrandomoptinfo(ROA_VALUE)); }
+//RDMOPT_HP_DRAIN,{ /* Needs more info */ }
+//RDMOPT_SP_DRAIN,{ /* Needs more info */ }
+RDMOPT_WEAPON_ATTR_NOTHING,{ bonus bAtkEle,Ele_Neutral; }
+RDMOPT_WEAPON_ATTR_WATER,{ bonus bAtkEle,Ele_Water; }
+RDMOPT_WEAPON_ATTR_GROUND,{ bonus bAtkEle,Ele_Earth; }
+RDMOPT_WEAPON_ATTR_FIRE,{ bonus bAtkEle,Ele_Fire; }
+RDMOPT_WEAPON_ATTR_WIND,{ bonus bAtkEle,Ele_Wind; }
+RDMOPT_WEAPON_ATTR_POISON,{ bonus bAtkEle,Ele_Poison; }
+RDMOPT_WEAPON_ATTR_SAINT,{ bonus bAtkEle,Ele_Holy; }
+RDMOPT_WEAPON_ATTR_DARKNESS,{ bonus bAtkEle,Ele_Dark; }
+RDMOPT_WEAPON_ATTR_TELEKINESIS,{ bonus bAtkEle,Ele_Ghost; }
+RDMOPT_WEAPON_ATTR_UNDEAD,{ bonus bAtkEle,Ele_Undead; }
+RDMOPT_WEAPON_INDESTRUCTIBLE,{ bonus bUnbreakableWeapon,1; }
+RDMOPT_BODY_INDESTRUCTIBLE,{ bonus bUnbreakableArmor,1; }
+RDMOPT_MDAMAGE_SIZE_SMALL_TARGET,{ bonus2 bMagicAddSize,Size_Small,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_MDAMAGE_SIZE_MIDIUM_TARGET,{ bonus2 bMagicAddSize,Size_Medium,getrandomoptinfo(ROA_VALUE); }
+RDMOPT_MDAMAGE_SIZE_LARGE_TARGET,{ bonus2 bMagicAddSize,Size_Large,getrandomoptinfo(ROA_VALUE); }
+//RDMOPT_MDAMAGE_SIZE_SMALL_USER,{}
+//RDMOPT_MDAMAGE_SIZE_MIDIUM_USER,{}
+//RDMOPT_MDAMAGE_SIZE_LARGE_USER,{}
+//redefined?
+//RDMOPT_ATTR_TOLERACE_ALL,{}

+ 15 - 0
sql-files/logs.sql

@@ -173,6 +173,21 @@ CREATE TABLE IF NOT EXISTS `picklog` (
   `card1` smallint(5) unsigned NOT NULL default '0',
   `card2` smallint(5) unsigned NOT NULL default '0',
   `card3` smallint(5) unsigned NOT NULL default '0',
+  `option_id0` smallint(5) unsigned NOT NULL default '0',
+  `option_val0` smallint(5) unsigned NOT NULL default '0',
+  `option_parm0` tinyint(3) unsigned NOT NULL default '0',
+  `option_id1` smallint(5) unsigned NOT NULL default '0',
+  `option_val1` smallint(5) unsigned NOT NULL default '0',
+  `option_parm1` tinyint(3) unsigned NOT NULL default '0',
+  `option_id2` smallint(5) unsigned NOT NULL default '0',
+  `option_val2` smallint(5) unsigned NOT NULL default '0',
+  `option_parm2` tinyint(3) unsigned NOT NULL default '0',
+  `option_id3` smallint(5) unsigned NOT NULL default '0',
+  `option_val3` smallint(5) unsigned NOT NULL default '0',
+  `option_parm3` tinyint(3) unsigned NOT NULL default '0',
+  `option_id4` smallint(5) unsigned NOT NULL default '0',
+  `option_val4` smallint(5) unsigned NOT NULL default '0',
+  `option_parm4` tinyint(3) unsigned NOT NULL default '0',
   `unique_id` bigint(20) unsigned NOT NULL default '0',
   `map` varchar(11) NOT NULL default '',
   `bound` tinyint(1) unsigned NOT NULL default '0',

+ 90 - 0
sql-files/main.sql

@@ -47,6 +47,21 @@ CREATE TABLE IF NOT EXISTS `auction` (
   `card1` smallint(5) unsigned NOT NULL default '0',
   `card2` smallint(5) unsigned NOT NULL default '0',
   `card3` smallint(5) unsigned NOT NULL default '0',
+  `option_id0` smallint(5) unsigned NOT NULL default '0',
+  `option_val0` smallint(5) unsigned NOT NULL default '0',
+  `option_parm0` tinyint(3) unsigned NOT NULL default '0',
+  `option_id1` smallint(5) unsigned NOT NULL default '0',
+  `option_val1` smallint(5) unsigned NOT NULL default '0',
+  `option_parm1` tinyint(3) unsigned NOT NULL default '0',
+  `option_id2` smallint(5) unsigned NOT NULL default '0',
+  `option_val2` smallint(5) unsigned NOT NULL default '0',
+  `option_parm2` tinyint(3) unsigned NOT NULL default '0',
+  `option_id3` smallint(5) unsigned NOT NULL default '0',
+  `option_val3` smallint(5) unsigned NOT NULL default '0',
+  `option_parm3` tinyint(3) unsigned NOT NULL default '0',
+  `option_id4` smallint(5) unsigned NOT NULL default '0',
+  `option_val4` smallint(5) unsigned NOT NULL default '0',
+  `option_parm4` tinyint(3) unsigned NOT NULL default '0',
   `unique_id` bigint(20) unsigned NOT NULL default '0',
   PRIMARY KEY  (`auction_id`)
 ) ENGINE=MyISAM;
@@ -127,6 +142,21 @@ CREATE TABLE IF NOT EXISTS `cart_inventory` (
   `card1` smallint(5) unsigned NOT NULL default '0',
   `card2` smallint(5) unsigned NOT NULL default '0',
   `card3` smallint(5) unsigned NOT NULL default '0',
+  `option_id0` smallint(5) unsigned NOT NULL default '0',
+  `option_val0` smallint(5) unsigned NOT NULL default '0',
+  `option_parm0` tinyint(3) unsigned NOT NULL default '0',
+  `option_id1` smallint(5) unsigned NOT NULL default '0',
+  `option_val1` smallint(5) unsigned NOT NULL default '0',
+  `option_parm1` tinyint(3) unsigned NOT NULL default '0',
+  `option_id2` smallint(5) unsigned NOT NULL default '0',
+  `option_val2` smallint(5) unsigned NOT NULL default '0',
+  `option_parm2` tinyint(3) unsigned NOT NULL default '0',
+  `option_id3` smallint(5) unsigned NOT NULL default '0',
+  `option_val3` smallint(5) unsigned NOT NULL default '0',
+  `option_parm3` tinyint(3) unsigned NOT NULL default '0',
+  `option_id4` smallint(5) unsigned NOT NULL default '0',
+  `option_val4` smallint(5) unsigned NOT NULL default '0',
+  `option_parm4` tinyint(3) unsigned NOT NULL default '0',
   `expire_time` int(11) unsigned NOT NULL default '0',
   `bound` tinyint(3) unsigned NOT NULL default '0',
   `unique_id` bigint(20) unsigned NOT NULL default '0',
@@ -456,6 +486,21 @@ CREATE TABLE IF NOT EXISTS `guild_storage` (
   `card1` smallint(5) unsigned NOT NULL default '0',
   `card2` smallint(5) unsigned NOT NULL default '0',
   `card3` smallint(5) unsigned NOT NULL default '0',
+  `option_id0` smallint(5) unsigned NOT NULL default '0',
+  `option_val0` smallint(5) unsigned NOT NULL default '0',
+  `option_parm0` tinyint(3) unsigned NOT NULL default '0',
+  `option_id1` smallint(5) unsigned NOT NULL default '0',
+  `option_val1` smallint(5) unsigned NOT NULL default '0',
+  `option_parm1` tinyint(3) unsigned NOT NULL default '0',
+  `option_id2` smallint(5) unsigned NOT NULL default '0',
+  `option_val2` smallint(5) unsigned NOT NULL default '0',
+  `option_parm2` tinyint(3) unsigned NOT NULL default '0',
+  `option_id3` smallint(5) unsigned NOT NULL default '0',
+  `option_val3` smallint(5) unsigned NOT NULL default '0',
+  `option_parm3` tinyint(3) unsigned NOT NULL default '0',
+  `option_id4` smallint(5) unsigned NOT NULL default '0',
+  `option_val4` smallint(5) unsigned NOT NULL default '0',
+  `option_parm4` tinyint(3) unsigned NOT NULL default '0',
   `expire_time` int(11) unsigned NOT NULL default '0',
   `bound` tinyint(3) unsigned NOT NULL default '0',
   `unique_id` bigint(20) unsigned NOT NULL default '0',
@@ -543,6 +588,21 @@ CREATE TABLE IF NOT EXISTS `inventory` (
   `card1` smallint(5) unsigned NOT NULL default '0',
   `card2` smallint(5) unsigned NOT NULL default '0',
   `card3` smallint(5) unsigned NOT NULL default '0',
+  `option_id0` smallint(5) unsigned NOT NULL default '0',
+  `option_val0` smallint(5) unsigned NOT NULL default '0',
+  `option_parm0` tinyint(3) unsigned NOT NULL default '0',
+  `option_id1` smallint(5) unsigned NOT NULL default '0',
+  `option_val1` smallint(5) unsigned NOT NULL default '0',
+  `option_parm1` tinyint(3) unsigned NOT NULL default '0',
+  `option_id2` smallint(5) unsigned NOT NULL default '0',
+  `option_val2` smallint(5) unsigned NOT NULL default '0',
+  `option_parm2` tinyint(3) unsigned NOT NULL default '0',
+  `option_id3` smallint(5) unsigned NOT NULL default '0',
+  `option_val3` smallint(5) unsigned NOT NULL default '0',
+  `option_parm3` tinyint(3) unsigned NOT NULL default '0',
+  `option_id4` smallint(5) unsigned NOT NULL default '0',
+  `option_val4` smallint(5) unsigned NOT NULL default '0',
+  `option_parm4` tinyint(3) unsigned NOT NULL default '0',
   `expire_time` int(11) unsigned NOT NULL default '0',
   `favorite` tinyint(3) unsigned NOT NULL default '0',
   `bound` tinyint(3) unsigned NOT NULL default '0',
@@ -619,6 +679,21 @@ CREATE TABLE IF NOT EXISTS `mail` (
   `card1` smallint(5) unsigned NOT NULL default '0',
   `card2` smallint(5) unsigned NOT NULL default '0',
   `card3` smallint(5) unsigned NOT NULL default '0',
+  `option_id0` smallint(5) unsigned NOT NULL default '0',
+  `option_val0` smallint(5) unsigned NOT NULL default '0',
+  `option_parm0` tinyint(3) unsigned NOT NULL default '0',
+  `option_id1` smallint(5) unsigned NOT NULL default '0',
+  `option_val1` smallint(5) unsigned NOT NULL default '0',
+  `option_parm1` tinyint(3) unsigned NOT NULL default '0',
+  `option_id2` smallint(5) unsigned NOT NULL default '0',
+  `option_val2` smallint(5) unsigned NOT NULL default '0',
+  `option_parm2` tinyint(3) unsigned NOT NULL default '0',
+  `option_id3` smallint(5) unsigned NOT NULL default '0',
+  `option_val3` smallint(5) unsigned NOT NULL default '0',
+  `option_parm3` tinyint(3) unsigned NOT NULL default '0',
+  `option_id4` smallint(5) unsigned NOT NULL default '0',
+  `option_val4` smallint(5) unsigned NOT NULL default '0',
+  `option_parm4` tinyint(3) unsigned NOT NULL default '0',
   `unique_id` bigint(20) unsigned NOT NULL default '0',
   `bound` tinyint(1) unsigned NOT NULL default '0',
   PRIMARY KEY  (`id`)
@@ -834,6 +909,21 @@ CREATE TABLE IF NOT EXISTS `storage` (
   `card1` smallint(5) unsigned NOT NULL default '0',
   `card2` smallint(5) unsigned NOT NULL default '0',
   `card3` smallint(5) unsigned NOT NULL default '0',
+  `option_id0` smallint(5) unsigned NOT NULL default '0',
+  `option_val0` smallint(5) unsigned NOT NULL default '0',
+  `option_parm0` tinyint(3) unsigned NOT NULL default '0',
+  `option_id1` smallint(5) unsigned NOT NULL default '0',
+  `option_val1` smallint(5) unsigned NOT NULL default '0',
+  `option_parm1` tinyint(3) unsigned NOT NULL default '0',
+  `option_id2` smallint(5) unsigned NOT NULL default '0',
+  `option_val2` smallint(5) unsigned NOT NULL default '0',
+  `option_parm2` tinyint(3) unsigned NOT NULL default '0',
+  `option_id3` smallint(5) unsigned NOT NULL default '0',
+  `option_val3` smallint(5) unsigned NOT NULL default '0',
+  `option_parm3` tinyint(3) unsigned NOT NULL default '0',
+  `option_id4` smallint(5) unsigned NOT NULL default '0',
+  `option_val4` smallint(5) unsigned NOT NULL default '0',
+  `option_parm4` tinyint(3) unsigned NOT NULL default '0',
   `expire_time` int(11) unsigned NOT NULL default '0',
   `bound` tinyint(3) unsigned NOT NULL default '0',
   `unique_id` bigint(20) unsigned NOT NULL default '0',

+ 101 - 0
sql-files/upgrades/upgrade_20160814.sql

@@ -0,0 +1,101 @@
+ALTER TABLE `auction`
+	ADD COLUMN `option_id0` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `card3`,
+	ADD COLUMN `option_val0` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_id0`,
+	ADD COLUMN `option_parm0` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_val0`,
+	ADD COLUMN `option_id1` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_parm0`,
+	ADD COLUMN `option_val1` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_id1`,
+	ADD COLUMN `option_parm1` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_val1`,
+	ADD COLUMN `option_id2` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_parm1`,
+	ADD COLUMN `option_val2` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_id2`,
+	ADD COLUMN `option_parm2` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_val2`,
+	ADD COLUMN `option_id3` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_parm2`,
+	ADD COLUMN `option_val3` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_id3`,
+	ADD COLUMN `option_parm3` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_val3`,
+	ADD COLUMN `option_id4` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_parm3`,
+	ADD COLUMN `option_val4` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_id4`,
+	ADD COLUMN `option_parm4` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_val4`;
+
+ALTER TABLE `cart_inventory`
+	ADD COLUMN `option_id0` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `card3`,
+	ADD COLUMN `option_val0` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_id0`,
+	ADD COLUMN `option_parm0` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_val0`,
+	ADD COLUMN `option_id1` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_parm0`,
+	ADD COLUMN `option_val1` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_id1`,
+	ADD COLUMN `option_parm1` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_val1`,
+	ADD COLUMN `option_id2` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_parm1`,
+	ADD COLUMN `option_val2` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_id2`,
+	ADD COLUMN `option_parm2` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_val2`,
+	ADD COLUMN `option_id3` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_parm2`,
+	ADD COLUMN `option_val3` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_id3`,
+	ADD COLUMN `option_parm3` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_val3`,
+	ADD COLUMN `option_id4` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_parm3`,
+	ADD COLUMN `option_val4` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_id4`,
+	ADD COLUMN `option_parm4` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_val4`;
+
+ALTER TABLE `guild_storage`
+	ADD COLUMN `option_id0` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `card3`,
+	ADD COLUMN `option_val0` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_id0`,
+	ADD COLUMN `option_parm0` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_val0`,
+	ADD COLUMN `option_id1` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_parm0`,
+	ADD COLUMN `option_val1` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_id1`,
+	ADD COLUMN `option_parm1` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_val1`,
+	ADD COLUMN `option_id2` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_parm1`,
+	ADD COLUMN `option_val2` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_id2`,
+	ADD COLUMN `option_parm2` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_val2`,
+	ADD COLUMN `option_id3` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_parm2`,
+	ADD COLUMN `option_val3` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_id3`,
+	ADD COLUMN `option_parm3` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_val3`,
+	ADD COLUMN `option_id4` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_parm3`,
+	ADD COLUMN `option_val4` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_id4`,
+	ADD COLUMN `option_parm4` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_val4`;
+	
+ALTER TABLE `inventory`
+	ADD COLUMN `option_id0` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `card3`,
+	ADD COLUMN `option_val0` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_id0`,
+	ADD COLUMN `option_parm0` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_val0`,
+	ADD COLUMN `option_id1` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_parm0`,
+	ADD COLUMN `option_val1` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_id1`,
+	ADD COLUMN `option_parm1` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_val1`,
+	ADD COLUMN `option_id2` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_parm1`,
+	ADD COLUMN `option_val2` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_id2`,
+	ADD COLUMN `option_parm2` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_val2`,
+	ADD COLUMN `option_id3` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_parm2`,
+	ADD COLUMN `option_val3` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_id3`,
+	ADD COLUMN `option_parm3` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_val3`,
+	ADD COLUMN `option_id4` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_parm3`,
+	ADD COLUMN `option_val4` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_id4`,
+	ADD COLUMN `option_parm4` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_val4`;
+	
+ALTER TABLE `mail`
+	ADD COLUMN `option_id0` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `card3`,
+	ADD COLUMN `option_val0` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_id0`,
+	ADD COLUMN `option_parm0` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_val0`,
+	ADD COLUMN `option_id1` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_parm0`,
+	ADD COLUMN `option_val1` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_id1`,
+	ADD COLUMN `option_parm1` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_val1`,
+	ADD COLUMN `option_id2` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_parm1`,
+	ADD COLUMN `option_val2` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_id2`,
+	ADD COLUMN `option_parm2` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_val2`,
+	ADD COLUMN `option_id3` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_parm2`,
+	ADD COLUMN `option_val3` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_id3`,
+	ADD COLUMN `option_parm3` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_val3`,
+	ADD COLUMN `option_id4` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_parm3`,
+	ADD COLUMN `option_val4` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_id4`,
+	ADD COLUMN `option_parm4` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_val4`;
+	
+ALTER TABLE `storage`
+	ADD COLUMN `option_id0` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `card3`,
+	ADD COLUMN `option_val0` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_id0`,
+	ADD COLUMN `option_parm0` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_val0`,
+	ADD COLUMN `option_id1` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_parm0`,
+	ADD COLUMN `option_val1` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_id1`,
+	ADD COLUMN `option_parm1` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_val1`,
+	ADD COLUMN `option_id2` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_parm1`,
+	ADD COLUMN `option_val2` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_id2`,
+	ADD COLUMN `option_parm2` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_val2`,
+	ADD COLUMN `option_id3` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_parm2`,
+	ADD COLUMN `option_val3` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_id3`,
+	ADD COLUMN `option_parm3` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_val3`,
+	ADD COLUMN `option_id4` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_parm3`,
+	ADD COLUMN `option_val4` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_id4`,
+	ADD COLUMN `option_parm4` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_val4`;

+ 16 - 0
sql-files/upgrades/upgrade_20160814_log.sql

@@ -0,0 +1,16 @@
+ALTER TABLE `picklog`
+	ADD COLUMN `option_id0` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `card3`,
+	ADD COLUMN `option_val0` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_id0`,
+	ADD COLUMN `option_parm0` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_val0`,
+	ADD COLUMN `option_id1` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_parm0`,
+	ADD COLUMN `option_val1` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_id1`,
+	ADD COLUMN `option_parm1` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_val1`,
+	ADD COLUMN `option_id2` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_parm1`,
+	ADD COLUMN `option_val2` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_id2`,
+	ADD COLUMN `option_parm2` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_val2`,
+	ADD COLUMN `option_id3` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_parm2`,
+	ADD COLUMN `option_val3` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_id3`,
+	ADD COLUMN `option_parm3` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_val3`,
+	ADD COLUMN `option_id4` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_parm3`,
+	ADD COLUMN `option_val4` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_id4`,
+	ADD COLUMN `option_parm4` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0' AFTER `option_val4`;

+ 97 - 28
src/char/char.c

@@ -542,11 +542,10 @@ int char_mmo_char_tosql(uint32 char_id, struct mmo_charstatus* p){
 }
 
 /// Saves an array of 'item' entries into the specified table.
-int char_memitemdata_to_sql(const struct item items[], int max, int id, int tableswitch){
+int char_memitemdata_to_sql(const struct item items[], int max, int id, int tableswitch) {
 	StringBuf buf;
 	SqlStmt* stmt;
-	int i;
-	int j;
+	int i,j;
 	const char* tablename;
 	const char* selectoption;
 	struct item item; // temp storage variable
@@ -572,8 +571,14 @@ int char_memitemdata_to_sql(const struct item items[], int max, int id, int tabl
 
 	StringBuf_Init(&buf);
 	StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `bound`, `unique_id`");
-	for( j = 0; j < MAX_SLOTS; ++j )
-		StringBuf_Printf(&buf, ", `card%d`", j);
+
+	for( i = 0; i < MAX_SLOTS; ++i )
+		StringBuf_Printf(&buf, ", `card%d`", i);
+	for( i = 0; i < MAX_ITEM_RDM_OPT; ++i ) {
+		StringBuf_Printf(&buf, ", `option_id%d`", i);
+		StringBuf_Printf(&buf, ", `option_val%d`", i);
+		StringBuf_Printf(&buf, ", `option_parm%d`", i);
+	}
 	StringBuf_Printf(&buf, " FROM `%s` WHERE `%s`='%d'", tablename, selectoption, id);
 
 	stmt = SqlStmt_Malloc(sql_handle);
@@ -596,9 +601,13 @@ int char_memitemdata_to_sql(const struct item items[], int max, int id, int tabl
 	SqlStmt_BindColumn(stmt, 7, SQLDT_UINT,      &item.expire_time, 0, NULL, NULL);
 	SqlStmt_BindColumn(stmt, 8, SQLDT_UINT,      &item.bound,       0, NULL, NULL);
 	SqlStmt_BindColumn(stmt, 9, SQLDT_UINT64,    &item.unique_id,   0, NULL, NULL);
-	for( j = 0; j < MAX_SLOTS; ++j )
-		SqlStmt_BindColumn(stmt, 10+j, SQLDT_USHORT, &item.card[j], 0, NULL, NULL);
-
+	for( i = 0; i < MAX_SLOTS; ++i )
+		SqlStmt_BindColumn(stmt, 10+i, SQLDT_USHORT, &item.card[i], 0, NULL, NULL);
+	for( i = 0; i < MAX_ITEM_RDM_OPT; ++i ) {
+		SqlStmt_BindColumn(stmt, 10+MAX_SLOTS+i*3, SQLDT_SHORT, &item.option[i].id, 0, NULL, NULL);
+		SqlStmt_BindColumn(stmt, 11+MAX_SLOTS+i*3, SQLDT_SHORT, &item.option[i].value, 0, NULL, NULL);
+		SqlStmt_BindColumn(stmt, 12+MAX_SLOTS+i*3, SQLDT_CHAR, &item.option[i].param, 0, NULL, NULL);
+	}
 	// bit array indicating which inventory items have already been matched
 	flag = (bool*) aCalloc(max, sizeof(bool));
 
@@ -636,6 +645,11 @@ int char_memitemdata_to_sql(const struct item items[], int max, int id, int tabl
 						tablename, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time, items[i].bound, items[i].unique_id);
 					for( j = 0; j < MAX_SLOTS; ++j )
 						StringBuf_Printf(&buf, ", `card%d`=%hu", j, items[i].card[j]);
+					for( j = 0; j < MAX_ITEM_RDM_OPT; ++j ) {
+						StringBuf_Printf(&buf, ", `option_id%d`=%d", j, items[i].option[j].id);
+						StringBuf_Printf(&buf, ", `option_val%d`=%d", j, items[i].option[j].value);
+						StringBuf_Printf(&buf, ", `option_parm%d`=%d", j, items[i].option[j].param);
+					}
 					StringBuf_Printf(&buf, " WHERE `id`='%d' LIMIT 1", item.id);
 
 					if( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) )
@@ -664,6 +678,11 @@ int char_memitemdata_to_sql(const struct item items[], int max, int id, int tabl
 	StringBuf_Printf(&buf, "INSERT INTO `%s`(`%s`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `bound`, `unique_id`", tablename, selectoption);
 	for( j = 0; j < MAX_SLOTS; ++j )
 		StringBuf_Printf(&buf, ", `card%d`", j);
+	for( j = 0; j < MAX_ITEM_RDM_OPT; ++j ) {
+		StringBuf_Printf(&buf, ", `option_id%d`", j);
+		StringBuf_Printf(&buf, ", `option_val%d`", j);
+		StringBuf_Printf(&buf, ", `option_parm%d`", j);
+	}
 	StringBuf_AppendStr(&buf, ") VALUES ");
 
 	found = false;
@@ -683,6 +702,11 @@ int char_memitemdata_to_sql(const struct item items[], int max, int id, int tabl
 			id, items[i].nameid, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time, items[i].bound, items[i].unique_id);
 		for( j = 0; j < MAX_SLOTS; ++j )
 			StringBuf_Printf(&buf, ", '%hu'", items[i].card[j]);
+		for( j = 0; j < MAX_ITEM_RDM_OPT; ++j ) {
+			StringBuf_Printf(&buf, ", '%d'", items[i].option[j].id);
+			StringBuf_Printf(&buf, ", '%d'", items[i].option[j].value);
+			StringBuf_Printf(&buf, ", '%d'", items[i].option[j].param);
+		}
 		StringBuf_AppendStr(&buf, ")");
 	}
 
@@ -702,8 +726,7 @@ int char_memitemdata_to_sql(const struct item items[], int max, int id, int tabl
 int char_inventory_to_sql(const struct item items[], int max, int id) {
 	StringBuf buf;
 	SqlStmt* stmt;
-	int i;
-	int j;
+	int i, j;
 	struct item item; // temp storage variable
 	bool* flag; // bit array for inventory matching
 	bool found;
@@ -717,8 +740,13 @@ int char_inventory_to_sql(const struct item items[], int max, int id) {
 
 	StringBuf_Init(&buf);
 	StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `favorite`, `bound`, `unique_id`");
-	for( j = 0; j < MAX_SLOTS; ++j )
-		StringBuf_Printf(&buf, ", `card%d`", j);
+	for( i = 0; i < MAX_SLOTS; ++i )
+		StringBuf_Printf(&buf, ", `card%d`", i);
+	for( i = 0; i < MAX_ITEM_RDM_OPT; ++i ) {
+		StringBuf_Printf(&buf, ", `option_id%d`", i);
+		StringBuf_Printf(&buf, ", `option_val%d`", i);
+		StringBuf_Printf(&buf, ", `option_parm%d`", i);
+	}
 	StringBuf_Printf(&buf, " FROM `%s` WHERE `char_id`='%d'", schema_config.inventory_db, id);
 
 	stmt = SqlStmt_Malloc(sql_handle);
@@ -742,8 +770,13 @@ int char_inventory_to_sql(const struct item items[], int max, int id) {
 	SqlStmt_BindColumn(stmt, 8, SQLDT_CHAR,      &item.favorite,    0, NULL, NULL);
 	SqlStmt_BindColumn(stmt, 9, SQLDT_CHAR,      &item.bound,       0, NULL, NULL);
 	SqlStmt_BindColumn(stmt, 10,SQLDT_UINT64,    &item.unique_id,   0, NULL, NULL);
-	for( j = 0; j < MAX_SLOTS; ++j )
-		SqlStmt_BindColumn(stmt, 11+j, SQLDT_USHORT, &item.card[j], 0, NULL, NULL);
+	for( i = 0; i < MAX_SLOTS; ++i )
+		SqlStmt_BindColumn(stmt, 11+i, SQLDT_USHORT, &item.card[i], 0, NULL, NULL);
+	for( i = 0; i < MAX_ITEM_RDM_OPT; ++i ) {
+		SqlStmt_BindColumn(stmt, 11+MAX_SLOTS+i*3, SQLDT_SHORT, &item.option[i].id, 0, NULL, NULL);
+		SqlStmt_BindColumn(stmt, 12+MAX_SLOTS+i*3, SQLDT_SHORT, &item.option[i].value, 0, NULL, NULL);
+		SqlStmt_BindColumn(stmt, 13+MAX_SLOTS+i*3, SQLDT_CHAR, &item.option[i].param, 0, NULL, NULL);
+	}
 
 	// bit array indicating which inventory items have already been matched
 	flag = (bool*) aCalloc(max, sizeof(bool));
@@ -780,6 +813,11 @@ int char_inventory_to_sql(const struct item items[], int max, int id) {
 					    schema_config.inventory_db, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time, items[i].favorite, items[i].bound, items[i].unique_id);
 					for( j = 0; j < MAX_SLOTS; ++j )
 						StringBuf_Printf(&buf, ", `card%d`=%hu", j, items[i].card[j]);
+					for( j = 0; j < MAX_ITEM_RDM_OPT; ++j ) {
+						StringBuf_Printf(&buf, ", `option_id%d`=%d", j, items[i].option[j].id);
+						StringBuf_Printf(&buf, ", `option_val%d`=%d", j, items[i].option[j].value);
+						StringBuf_Printf(&buf, ", `option_parm%d`=%d", j, items[i].option[j].param);
+					}
 					StringBuf_Printf(&buf, " WHERE `id`='%d' LIMIT 1", item.id);
 
 					if( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) ) {
@@ -803,8 +841,13 @@ int char_inventory_to_sql(const struct item items[], int max, int id) {
 
 	StringBuf_Clear(&buf);
 	StringBuf_Printf(&buf, "INSERT INTO `%s` (`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `favorite`, `bound`, `unique_id`", schema_config.inventory_db);
-	for( j = 0; j < MAX_SLOTS; ++j )
-		StringBuf_Printf(&buf, ", `card%d`", j);
+	for( i = 0; i < MAX_SLOTS; ++i )
+		StringBuf_Printf(&buf, ", `card%d`", i);
+	for( i = 0; i < MAX_ITEM_RDM_OPT; ++i ) {
+		StringBuf_Printf(&buf, ", `option_id%d`", i);
+		StringBuf_Printf(&buf, ", `option_val%d`", i);
+		StringBuf_Printf(&buf, ", `option_parm%d`", i);
+	}
 	StringBuf_AppendStr(&buf, ") VALUES ");
 
 	found = false;
@@ -823,6 +866,11 @@ int char_inventory_to_sql(const struct item items[], int max, int id) {
 						 id, items[i].nameid, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time, items[i].favorite, items[i].bound, items[i].unique_id);
 		for( j = 0; j < MAX_SLOTS; ++j )
 			StringBuf_Printf(&buf, ", '%hu'", items[i].card[j]);
+		for( j = 0; j < MAX_ITEM_RDM_OPT; ++j ) {
+			StringBuf_Printf(&buf, ", '%d'", items[i].option[j].id);
+			StringBuf_Printf(&buf, ", '%d'", items[i].option[j].value);
+			StringBuf_Printf(&buf, ", '%d'", items[i].option[j].param);
+		}
 		StringBuf_AppendStr(&buf, ")");
 	}
 
@@ -989,7 +1037,7 @@ int char_mmo_chars_fromsql(struct char_session_data* sd, uint8* buf) {
 
 //=====================================================================================================
 int char_mmo_char_fromsql(uint32 char_id, struct mmo_charstatus* p, bool load_everything) {
-	int i,j;
+	int i, j;
 	struct mmo_charstatus* cp;
 	StringBuf buf;
 	SqlStmt* stmt;
@@ -1145,11 +1193,16 @@ int char_mmo_char_fromsql(uint32 char_id, struct mmo_charstatus* p, bool load_ev
 	StringBuf_AppendStr(&msg_buf, " memo");
 
 	//read inventory
-	//`inventory` (`id`,`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `card0`, `card1`, `card2`, `card3`, `expire_time`, `favorite`, `unique_id`)
+	//`inventory` (`id`,`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `card0`, `card1`, `card2`, `card3`, `option_id0`, `option_val0`, `option_id1`, `option_val1`, `option_id2`, `option_val2`, `option_id3`, `option_val3`, `option_id4`, `option_val4`, `expire_time`, `favorite`, `unique_id`)
 	StringBuf_Init(&buf);
 	StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `favorite`, `bound`, `unique_id`");
 	for( i = 0; i < MAX_SLOTS; ++i )
 		StringBuf_Printf(&buf, ", `card%d`", i);
+	for( i = 0; i < MAX_ITEM_RDM_OPT; ++i ) {
+		StringBuf_Printf(&buf, ", `option_id%d`", i);
+		StringBuf_Printf(&buf, ", `option_val%d`", i);
+		StringBuf_Printf(&buf, ", `option_parm%d`", i);
+	}
 	StringBuf_Printf(&buf, " FROM `%s` WHERE `char_id`=? LIMIT %d", schema_config.inventory_db, MAX_INVENTORY);
 
 	if( SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf))
@@ -1168,20 +1221,31 @@ int char_mmo_char_fromsql(uint32 char_id, struct mmo_charstatus* p, bool load_ev
 	||	SQL_ERROR == SqlStmt_BindColumn(stmt,10, SQLDT_UINT64,    &tmp_item.unique_id, 0, NULL, NULL) )
 		SqlStmt_ShowDebug(stmt);
 	for( i = 0; i < MAX_SLOTS; ++i )
-		if( SQL_ERROR == SqlStmt_BindColumn(stmt, 11+i, SQLDT_USHORT, &tmp_item.card[i], 0, NULL, NULL) )
+		if( SQL_ERROR == SqlStmt_BindColumn(stmt, 11+i, SQLDT_USHORT, &tmp_item.card[i], 0, NULL, NULL) ) {
 			SqlStmt_ShowDebug(stmt);
-
+	}
+	for( i = 0; i < MAX_ITEM_RDM_OPT; ++i ) {
+		if( SQL_ERROR == SqlStmt_BindColumn(stmt, 11+MAX_SLOTS+i*3, SQLDT_SHORT, &tmp_item.option[i].id, 0, NULL, NULL)
+		||	SQL_ERROR == SqlStmt_BindColumn(stmt, 12+MAX_SLOTS+i*3, SQLDT_SHORT, &tmp_item.option[i].value, 0, NULL, NULL)
+		||	SQL_ERROR == SqlStmt_BindColumn(stmt, 13+MAX_SLOTS+i*3, SQLDT_CHAR, &tmp_item.option[i].param, 0, NULL, NULL) )
+			SqlStmt_ShowDebug(stmt);
+	}
 	for( i = 0; i < MAX_INVENTORY && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i )
 		memcpy(&p->inventory[i], &tmp_item, sizeof(tmp_item));
 
 	StringBuf_AppendStr(&msg_buf, " inventory");
 
 	//read cart
-	//`cart_inventory` (`id`,`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `card0`, `card1`, `card2`, `card3`, expire_time`, `unique_id`)
+	//`cart_inventory` (`id`,`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `card0`, `card1`, `card2`, `card3`, `option_id0`, `option_val0`, `option_id1`, `option_val1`, `option_id2`, `option_val2`, `option_id3`, `option_val3`, `option_id4`, `option_val4`, `expire_time`, `favorite`, `unique_id`)
 	StringBuf_Clear(&buf);
 	StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `bound`, `unique_id`");
 	for( j = 0; j < MAX_SLOTS; ++j )
 		StringBuf_Printf(&buf, ", `card%d`", j);
+	for( i = 0; i < MAX_ITEM_RDM_OPT; ++i ) {
+		StringBuf_Printf(&buf, ", `option_id%d`", i);
+		StringBuf_Printf(&buf, ", `option_val%d`", i);
+		StringBuf_Printf(&buf, ", `option_parm%d`", i);
+	}
 	StringBuf_Printf(&buf, " FROM `%s` WHERE `char_id`=? LIMIT %d", schema_config.cart_db, MAX_CART);
 
 	if( SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf))
@@ -1201,7 +1265,12 @@ int char_mmo_char_fromsql(uint32 char_id, struct mmo_charstatus* p, bool load_ev
 	for( i = 0; i < MAX_SLOTS; ++i )
 		if( SQL_ERROR == SqlStmt_BindColumn(stmt, 10+i, SQLDT_USHORT, &tmp_item.card[i], 0, NULL, NULL) )
 			SqlStmt_ShowDebug(stmt);
-
+	for( i = 0; i < MAX_ITEM_RDM_OPT; i++ ) {
+		if( SQL_ERROR == SqlStmt_BindColumn(stmt, 10+MAX_SLOTS+i*3, SQLDT_SHORT, &tmp_item.option[i].id, 0, NULL, NULL)
+		||	SQL_ERROR == SqlStmt_BindColumn(stmt, 11+MAX_SLOTS+i*3, SQLDT_SHORT, &tmp_item.option[i].value, 0, NULL, NULL)
+		||	SQL_ERROR == SqlStmt_BindColumn(stmt, 12+MAX_SLOTS+i*3, SQLDT_CHAR, &tmp_item.option[i].param, 0, NULL, NULL) )
+			SqlStmt_ShowDebug(stmt);
+	}
 	for( i = 0; i < MAX_CART && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i )
 		memcpy(&p->cart[i], &tmp_item, sizeof(tmp_item));
 	StringBuf_AppendStr(&msg_buf, " cart");
@@ -2389,7 +2458,7 @@ bool char_checkdb(void){
 	//checking mail_db
 	if( SQL_ERROR == Sql_Query(sql_handle, "SELECT  `id`,`send_name`,`send_id`,`dest_name`,`dest_id`,"
 			"`title`,`message`,`time`,`status`,`zeny`,`nameid`,`amount`,`refine`,`attribute`,`identify`,"
-			"`card0`,`card1`,`card2`,`card3`,`unique_id`, `bound`"
+			"`card0`,`card1`,`card2`,`card3`,`option_id0`,`option_val0`,`option_parm0`,`option_id1`,`option_val1`,`option_parm1`,`option_id2`,`option_val2`,`option_parm2`,`option_id3`,`option_val3`,`option_parm3`,`option_id4`,`option_val4`,`option_parm4`,`unique_id`, `bound`"
 			" FROM `%s` LIMIT 1;", schema_config.mail_db) ){
 		Sql_ShowDebug(sql_handle);
 		return false;
@@ -2397,7 +2466,7 @@ bool char_checkdb(void){
 	//checking auction_db
 	if( SQL_ERROR == Sql_Query(sql_handle, "SELECT  `auction_id`,`seller_id`,`seller_name`,`buyer_id`,`buyer_name`,"
 			"`price`,`buynow`,`hours`,`timestamp`,`nameid`,`item_name`,`type`,`refine`,`attribute`,`card0`,`card1`,"
-			"`card2`,`card3`,`unique_id` "
+			"`card2`,`card3`,`option_id0`,`option_val0`,`option_parm0`,`option_id1`,`option_val1`,`option_parm1`,`option_id2`,`option_val2`,`option_parm2`,`option_id3`,`option_val3`,`option_parm3`,`option_id4`,`option_val4`,`option_parm4`,`unique_id` "
 			"FROM `%s` LIMIT 1;", schema_config.auction_db) ){
 		Sql_ShowDebug(sql_handle);
 		return false;
@@ -2455,28 +2524,28 @@ bool char_checkdb(void){
 	}
 	//checking cart_db
 	if( SQL_ERROR == Sql_Query(sql_handle, "SELECT  `id`,`char_id`,`nameid`,`amount`,`equip`,`identify`,`refine`,"
-		"`attribute`,`card0`,`card1`,`card2`,`card3`,`expire_time`,`bound`,`unique_id`"
+		"`attribute`,`card0`,`card1`,`card2`,`card3`,`option_id0`,`option_val0`,`option_parm0`,`option_id1`,`option_val1`,`option_parm1`,`option_id2`,`option_val2`,`option_parm2`,`option_id3`,`option_val3`,`option_parm3`,`option_id4`,`option_val4`,`option_parm4`,`expire_time`,`bound`,`unique_id`"
 		" FROM `%s` LIMIT 1;", schema_config.cart_db) ){
 		Sql_ShowDebug(sql_handle);
 		return false;
 	}
 	//checking inventory_db
 	if( SQL_ERROR == Sql_Query(sql_handle, "SELECT  `id`,`char_id`,`nameid`,`amount`,`equip`,`identify`,`refine`,"
-		"`attribute`,`card0`,`card1`,`card2`,`card3`,`expire_time`,`favorite`,`bound`,`unique_id`"
+		"`attribute`,`card0`,`card1`,`card2`,`card3`,`option_id0`,`option_val0`,`option_parm0`,`option_id1`,`option_val1`,`option_parm1`,`option_id2`,`option_val2`,`option_parm2`,`option_id3`,`option_val3`,`option_parm3`,`option_id4`,`option_val4`,`option_parm4`,`expire_time`,`favorite`,`bound`,`unique_id`"
 		" FROM `%s` LIMIT 1;", schema_config.inventory_db) ){
 		Sql_ShowDebug(sql_handle);
 		return false;
 	}
 	//checking storage_db
 	if( SQL_ERROR == Sql_Query(sql_handle, "SELECT  `id`,`account_id`,`nameid`,`amount`,`equip`,`identify`,`refine`,"
-		"`attribute`,`card0`,`card1`,`card2`,`card3`,`expire_time`,`bound`,`unique_id`"
+		"`attribute`,`card0`,`card1`,`card2`,`card3`,`option_id0`,`option_val0`,`option_parm0`,`option_id1`,`option_val1`,`option_parm1`,`option_id2`,`option_val2`,`option_parm2`,`option_id3`,`option_val3`,`option_parm3`,`option_id4`,`option_val4`,`option_parm4`,`expire_time`,`bound`,`unique_id`"
 		" FROM `%s` LIMIT 1;", schema_config.storage_db) ){
 		Sql_ShowDebug(sql_handle);
 		return false;
 	}
 	//checking guild_storage_db
 	if( SQL_ERROR == Sql_Query(sql_handle, "SELECT  `id`,`guild_id`,`nameid`,`amount`,`equip`,`identify`,`refine`,"
-		"`attribute`,`card0`,`card1`,`card2`,`card3`,`expire_time`,`bound`,`unique_id`"
+		"`attribute`,`card0`,`card1`,`card2`,`card3`,`option_id0`,`option_val0`,`option_parm0`,`option_id1`,`option_val1`,`option_parm1`,`option_id2`,`option_val2`,`option_parm2`,`option_id3`,`option_val3`,`option_parm3`,`option_id4`,`option_val4`,`option_parm4`,`expire_time`,`bound`,`unique_id`"
 		" FROM `%s` LIMIT 1;", schema_config.guild_storage_db) ){
 		Sql_ShowDebug(sql_handle);
 		return false;

+ 30 - 1
src/char/int_auction.c

@@ -54,6 +54,11 @@ void auction_save(struct auction_data *auction)
 		schema_config.auction_db, auction->seller_id, auction->buyer_id, auction->price, auction->buynow, auction->hours, (unsigned long)auction->timestamp, auction->item.nameid, auction->type, auction->item.refine, auction->item.attribute);
 	for( j = 0; j < MAX_SLOTS; j++ )
 		StringBuf_Printf(&buf, ", `card%d` = '%hu'", j, auction->item.card[j]);
+	for (j = 0; j < MAX_ITEM_RDM_OPT; j++) {
+		StringBuf_Printf(&buf, ", `option_id%d` = '%d'", j, auction->item.option[j].id);
+		StringBuf_Printf(&buf, ", `option_val%d` = '%d'", j, auction->item.option[j].value);
+		StringBuf_Printf(&buf, ", `option_parm%d` = '%d'", j, auction->item.option[j].param);
+	}
 	StringBuf_Printf(&buf, " WHERE `auction_id` = '%d'", auction->auction_id);
 
 	stmt = SqlStmt_Malloc(sql_handle);
@@ -85,10 +90,20 @@ unsigned int auction_create(struct auction_data *auction)
 	StringBuf_Printf(&buf, "INSERT INTO `%s` (`seller_id`,`seller_name`,`buyer_id`,`buyer_name`,`price`,`buynow`,`hours`,`timestamp`,`nameid`,`item_name`,`type`,`refine`,`attribute`,`unique_id`", schema_config.auction_db);
 	for( j = 0; j < MAX_SLOTS; j++ )
 		StringBuf_Printf(&buf, ",`card%d`", j);
+	for (j = 0; j < MAX_ITEM_RDM_OPT; ++j) {
+		StringBuf_Printf(&buf, ", `option_id%d`", j);
+		StringBuf_Printf(&buf, ", `option_val%d`", j);
+		StringBuf_Printf(&buf, ", `option_parm%d`", j);
+	}
 	StringBuf_Printf(&buf, ") VALUES ('%d',?,'%d',?,'%d','%d','%d','%lu','%hu',?,'%d','%d','%d','%"PRIu64"'",
 		auction->seller_id, auction->buyer_id, auction->price, auction->buynow, auction->hours, (unsigned long)auction->timestamp, auction->item.nameid, auction->type, auction->item.refine, auction->item.attribute, auction->item.unique_id);
-	for( j = 0; j < MAX_SLOTS; j++ )
+	for( j = 0; j < MAX_SLOTS; j++ )	
 		StringBuf_Printf(&buf, ",'%hu'", auction->item.card[j]);
+	for (j = 0; j < MAX_ITEM_RDM_OPT; ++j) {
+		StringBuf_Printf(&buf, ", '%d'", auction->item.option[j].id);
+		StringBuf_Printf(&buf, ", '%d'", auction->item.option[j].value);
+		StringBuf_Printf(&buf, ", '%d'", auction->item.option[j].param);
+	}
 	StringBuf_AppendStr(&buf, ")");
 
 	stmt = SqlStmt_Malloc(sql_handle);
@@ -184,6 +199,11 @@ void inter_auctions_fromsql(void)
 		"`price`,`buynow`,`hours`,`timestamp`,`nameid`,`item_name`,`type`,`refine`,`attribute`,`unique_id`");
 	for( i = 0; i < MAX_SLOTS; i++ )
 		StringBuf_Printf(&buf, ",`card%d`", i);
+	for (i = 0; i < MAX_ITEM_RDM_OPT; ++i) {
+		StringBuf_Printf(&buf, ", `option_id%d`", i);
+		StringBuf_Printf(&buf, ", `option_val%d`", i);
+		StringBuf_Printf(&buf, ", `option_parm%d`", i);
+	}
 	StringBuf_Printf(&buf, " FROM `%s` ORDER BY `auction_id` DESC", schema_config.auction_db);
 
 	if( SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf)) )
@@ -225,6 +245,15 @@ void inter_auctions_fromsql(void)
 			item->card[i] = atoi(data);
 		}
 
+		for (i = 0; i < MAX_ITEM_RDM_OPT; i++) {
+			Sql_GetData(sql_handle, 15 + MAX_SLOTS + i*3, &data, NULL);
+			item->option[i].id = atoi(data);
+			Sql_GetData(sql_handle, 16 + MAX_SLOTS + i*3, &data, NULL);
+			item->option[i].value = atoi(data);
+			Sql_GetData(sql_handle, 17 + MAX_SLOTS + i*3, &data, NULL);
+			item->option[i].param = atoi(data);
+		}
+
 		if( auction->timestamp > now )
 			endtick = ((unsigned int)(auction->timestamp - now) * 1000) + tick;
 		else

+ 42 - 1
src/char/int_mail.c

@@ -28,7 +28,11 @@ static int mail_fromsql(uint32 char_id, struct mail_data* md)
 		"`zeny`,`amount`,`nameid`,`refine`,`attribute`,`identify`,`unique_id`,`bound`");
 	for (i = 0; i < MAX_SLOTS; i++)
 		StringBuf_Printf(&buf, ",`card%d`", i);
-
+	for (i = 0; i < MAX_ITEM_RDM_OPT; ++i) {
+		StringBuf_Printf(&buf, ", `option_id%d`", i);
+		StringBuf_Printf(&buf, ", `option_val%d`", i);
+		StringBuf_Printf(&buf, ", `option_parm%d`", i);
+	}
 	// I keep the `status` < 3 just in case someone forget to apply the sqlfix
 	StringBuf_Printf(&buf, " FROM `%s` WHERE `dest_id`='%d' AND `status` < 3 ORDER BY `id` LIMIT %d",
 		schema_config.mail_db, char_id, MAIL_MAX_INBOX + 1);
@@ -68,6 +72,15 @@ static int mail_fromsql(uint32 char_id, struct mail_data* md)
 			Sql_GetData(sql_handle, 17 + j, &data, NULL);
 			item->card[j] = atoi(data);
 		}
+
+		for (j = 0; j < MAX_ITEM_RDM_OPT; j++) {
+			Sql_GetData(sql_handle, 17 + MAX_SLOTS + j * 3, &data, NULL);
+			item->option[j].id = atoi(data);
+			Sql_GetData(sql_handle, 18 + MAX_SLOTS + j * 3, &data, NULL);
+			item->option[j].value = atoi(data);
+			Sql_GetData(sql_handle, 19 + MAX_SLOTS + j * 3, &data, NULL);
+			item->option[j].param = atoi(data);
+		}
 	}
 
 	md->full = ( Sql_NumRows(sql_handle) > MAIL_MAX_INBOX );
@@ -109,10 +122,20 @@ int mail_savemessage(struct mail_message* msg)
 	StringBuf_Printf(&buf, "INSERT INTO `%s` (`send_name`, `send_id`, `dest_name`, `dest_id`, `title`, `message`, `time`, `status`, `zeny`, `amount`, `nameid`, `refine`, `attribute`, `identify`, `unique_id`, `bound`", schema_config.mail_db);
 	for (j = 0; j < MAX_SLOTS; j++)
 		StringBuf_Printf(&buf, ", `card%d`", j);
+	for (j = 0; j < MAX_ITEM_RDM_OPT; ++j) {
+		StringBuf_Printf(&buf, ", `option_id%d`", j);
+		StringBuf_Printf(&buf, ", `option_val%d`", j);
+		StringBuf_Printf(&buf, ", `option_parm%d`", j);
+	}
 	StringBuf_Printf(&buf, ") VALUES (?, '%d', ?, '%d', ?, ?, '%lu', '%d', '%d', '%d', '%hu', '%d', '%d', '%d', '%"PRIu64"', '%d'",
 		msg->send_id, msg->dest_id, (unsigned long)msg->timestamp, msg->status, msg->zeny, msg->item.amount, msg->item.nameid, msg->item.refine, msg->item.attribute, msg->item.identify, msg->item.unique_id, msg->item.bound);
 	for (j = 0; j < MAX_SLOTS; j++)
 		StringBuf_Printf(&buf, ", '%hu'", msg->item.card[j]);
+	for (j = 0; j < MAX_ITEM_RDM_OPT; ++j) {
+		StringBuf_Printf(&buf, ", '%d'", msg->item.option[j].id);
+		StringBuf_Printf(&buf, ", '%d'", msg->item.option[j].value);
+		StringBuf_Printf(&buf, ", '%d'", msg->item.option[j].param);
+	}
 	StringBuf_AppendStr(&buf, ")");
 
 	// prepare and execute query
@@ -147,6 +170,11 @@ static bool mail_loadmessage(int mail_id, struct mail_message* msg)
 		"`zeny`,`amount`,`nameid`,`refine`,`attribute`,`identify`,`unique_id`,`bound`");
 	for( j = 0; j < MAX_SLOTS; j++ )
 		StringBuf_Printf(&buf, ",`card%d`", j);
+	for (j = 0; j < MAX_ITEM_RDM_OPT; ++j) {
+		StringBuf_Printf(&buf, ", `option_id%d`", j);
+		StringBuf_Printf(&buf, ", `option_val%d`", j);
+		StringBuf_Printf(&buf, ", `option_parm%d`", j);
+	}
 	StringBuf_Printf(&buf, " FROM `%s` WHERE `id` = '%d'", schema_config.mail_db, mail_id);
 
 	if( SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf))
@@ -185,6 +213,14 @@ static bool mail_loadmessage(int mail_id, struct mail_message* msg)
 			Sql_GetData(sql_handle,17 + j, &data, NULL);
 			msg->item.card[j] = atoi(data);
 		}
+		for (j = 0; j < MAX_ITEM_RDM_OPT; j++) {
+			Sql_GetData(sql_handle, 17 + MAX_SLOTS + j * 3, &data, NULL);
+			msg->item.option[j].id = atoi(data);
+			Sql_GetData(sql_handle, 18 + MAX_SLOTS + j * 3, &data, NULL);
+			msg->item.option[j].value = atoi(data);
+			Sql_GetData(sql_handle, 19 + MAX_SLOTS + j * 3, &data, NULL);
+			msg->item.option[j].param = atoi(data);
+		}
 	}
 
 	StringBuf_Destroy(&buf);
@@ -238,6 +274,11 @@ static bool mail_DeleteAttach(int mail_id)
 	StringBuf_Printf(&buf, "UPDATE `%s` SET `zeny` = '0', `nameid` = '0', `amount` = '0', `refine` = '0', `attribute` = '0', `identify` = '0'", schema_config.mail_db);
 	for (i = 0; i < MAX_SLOTS; i++)
 		StringBuf_Printf(&buf, ", `card%d` = '0'", i);
+	for (i = 0; i < MAX_ITEM_RDM_OPT; ++i) {
+		StringBuf_Printf(&buf, ", `option_id%d` = 0", i);
+		StringBuf_Printf(&buf, ", `option_val%d` = 0", i);
+		StringBuf_Printf(&buf, ", `option_parm%d` = 0", i);
+	}
 	StringBuf_Printf(&buf, " WHERE `id` = '%d'", mail_id);
 
 	if( SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf)) )

+ 33 - 4
src/char/int_storage.c

@@ -30,11 +30,16 @@ int storage_fromsql(uint32 account_id, struct storage_data* p)
 	memset(p, 0, sizeof(struct storage_data)); //clean up memory
 	p->storage_amount = 0;
 
-	// storage {`account_id`/`id`/`nameid`/`amount`/`equip`/`identify`/`refine`/`attribute`/`card0`/`card1`/`card2`/`card3`}
+	// storage {`account_id`/`id`/`nameid`/`amount`/`equip`/`identify`/`refine`/`attribute`/`card0`/`card1`/`card2`/`card3`/`option_id0`/`option_val0`/`option_parm0`/`option_id1`/`option_val1`/`option_parm1`/`option_id2`/`option_val2`/`option_parm2`/`option_id3`/`option_val3`/`option_parm3`/`option_id4`/`option_val4`/`option_parm4`}
 	StringBuf_Init(&buf);
 	StringBuf_AppendStr(&buf, "SELECT `id`,`nameid`,`amount`,`equip`,`identify`,`refine`,`attribute`,`expire_time`,`bound`,`unique_id`");
 	for( j = 0; j < MAX_SLOTS; ++j )
 		StringBuf_Printf(&buf, ",`card%d`", j);
+	for( i = 0; i < MAX_ITEM_RDM_OPT; ++i ) {
+		StringBuf_Printf(&buf, ", `option_id%d`", i);
+		StringBuf_Printf(&buf, ", `option_val%d`", i);
+		StringBuf_Printf(&buf, ", `option_parm%d`", i);
+	}
 	StringBuf_Printf(&buf, " FROM `%s` WHERE `account_id`='%d' ORDER BY `nameid`", schema_config.storage_db, account_id);
 
 	if( SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf)) )
@@ -60,6 +65,11 @@ int storage_fromsql(uint32 account_id, struct storage_data* p)
 		for( j = 0; j < MAX_SLOTS; ++j ){
 			Sql_GetData(sql_handle, 10+j, &data, NULL); item->card[j] = atoi(data);
 		}
+		for( j = 0; j < MAX_ITEM_RDM_OPT; ++j ) {
+			Sql_GetData(sql_handle, 10+MAX_SLOTS+j*3, &data, NULL); item->option[j].id = atoi(data);
+			Sql_GetData(sql_handle, 11+MAX_SLOTS+j*3, &data, NULL); item->option[j].value = atoi(data);
+			Sql_GetData(sql_handle, 12+MAX_SLOTS+j*3, &data, NULL); item->option[j].param = atoi(data);
+		}
 	}
 	p->storage_amount = i;
 	Sql_FreeResult(sql_handle);
@@ -80,17 +90,22 @@ int guild_storage_tosql(int guild_id, struct guild_storage* p)
 int guild_storage_fromsql(int guild_id, struct guild_storage* p)
 {
 	StringBuf buf;
-	int i, j;
+	int i, j, k;
 
 	memset(p, 0, sizeof(struct guild_storage)); //clean up memory
 	p->storage_amount = 0;
 	p->guild_id = guild_id;
 
-	// storage {`guild_id`/`id`/`nameid`/`amount`/`equip`/`identify`/`refine`/`attribute`/`card0`/`card1`/`card2`/`card3`}
+	// storage {`guild_id`/`id`/`nameid`/`amount`/`equip`/`identify`/`refine`/`attribute`/`card0`/`card1`/`card2`/`card3`/`option_id0`/`option_val0`/`option_parm0`/`option_id1`/`option_val1`/`option_parm1`/`option_id2`/`option_val2`/`option_parm2`/`option_id3`/`option_val3`/`option_parm3`/`option_id4`/`option_val4`/`option_parm4`}
 	StringBuf_Init(&buf);
 	StringBuf_AppendStr(&buf, "SELECT `id`,`nameid`,`amount`,`equip`,`identify`,`refine`,`attribute`,`bound`,`unique_id`");
 	for( j = 0; j < MAX_SLOTS; ++j )
 		StringBuf_Printf(&buf, ",`card%d`", j);
+	for( j = 0; j < MAX_ITEM_RDM_OPT; ++j ) {
+		StringBuf_Printf(&buf, ", `option_id%d`", j);
+		StringBuf_Printf(&buf, ", `option_val%d`", j);
+		StringBuf_Printf(&buf, ", `option_parm%d`", j);
+	}
 	StringBuf_Printf(&buf, " FROM `%s` WHERE `guild_id`='%d' ORDER BY `nameid`", schema_config.guild_storage_db, guild_id);
 
 	if( SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf)) )
@@ -116,6 +131,11 @@ int guild_storage_fromsql(int guild_id, struct guild_storage* p)
 		for( j = 0; j < MAX_SLOTS; ++j ){
 			Sql_GetData(sql_handle, 9+j, &data, NULL); item->card[j] = atoi(data);
 		}
+		for( j = 0; j < MAX_ITEM_RDM_OPT; ++j ) {
+			Sql_GetData(sql_handle, 9+MAX_SLOTS+j*3, &data, NULL); item->option[j].id = atoi(data);
+			Sql_GetData(sql_handle, 10+MAX_SLOTS+j*3, &data, NULL); item->option[j].value = atoi(data);
+			Sql_GetData(sql_handle, 11+MAX_SLOTS+j*3, &data, NULL); item->option[j].param = atoi(data);
+		}
 	}
 	p->storage_amount = i;
 	Sql_FreeResult(sql_handle);
@@ -293,6 +313,11 @@ int mapif_parse_itembound_retrieve(int fd)
 	StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `bound`");
 	for( j = 0; j < MAX_SLOTS; ++j )
 		StringBuf_Printf(&buf, ", `card%d`", j);
+	for( j = 0; j < MAX_ITEM_RDM_OPT; ++j ) {
+		StringBuf_Printf(&buf, ", `option_id%d`", j);
+		StringBuf_Printf(&buf, ", `option_val%d`", j);
+		StringBuf_Printf(&buf, ", `option_parm%d`", j);
+	}
 	StringBuf_Printf(&buf, " FROM `%s` WHERE `char_id`='%d' AND `bound` = %d", schema_config.inventory_db,char_id, BOUND_GUILD);
 
 	stmt = SqlStmt_Malloc(sql_handle);
@@ -317,7 +342,11 @@ int mapif_parse_itembound_retrieve(int fd)
 	SqlStmt_BindColumn(stmt, 8, SQLDT_UINT,      &item.bound,       0, NULL, NULL);
 	for( j = 0; j < MAX_SLOTS; ++j )
 		SqlStmt_BindColumn(stmt, 9+j, SQLDT_USHORT, &item.card[j], 0, NULL, NULL);
-
+	for( j = 0; j < MAX_ITEM_RDM_OPT; ++j ) {
+		SqlStmt_BindColumn(stmt, 9+MAX_SLOTS+j*3, SQLDT_SHORT, &item.option[j].id, 0, NULL, NULL);
+		SqlStmt_BindColumn(stmt, 10+MAX_SLOTS+j*3, SQLDT_SHORT, &item.option[j].value, 0, NULL, NULL);
+		SqlStmt_BindColumn(stmt, 11+MAX_SLOTS+j*3, SQLDT_CHAR, &item.option[j].param, 0, NULL, NULL);
+	}
 	memset(&items, 0, sizeof(items));
 	while( SQL_SUCCESS == SqlStmt_NextRow(stmt) )
 		memcpy(&items[count++], &item, sizeof(struct item));

+ 6 - 0
src/common/mmo.h

@@ -78,6 +78,7 @@
 #define MAX_QUEST_OBJECTIVES 3 ///Max quest objectives for a quest
 #define MAX_QUEST_DROPS 3 ///Max quest drops for a quest
 #define MAX_PC_BONUS_SCRIPT 50 ///Max bonus script can be fetched from `bonus_script` table on player load [Cydh]
+#define MAX_ITEM_RDM_OPT 5	 /// Max item random option [Napster]
 
 // for produce
 #define MIN_ATTRIBUTE 0
@@ -186,6 +187,11 @@ struct item {
 	char refine;
 	char attribute;
 	unsigned short card[MAX_SLOTS];
+	struct {
+		short id;
+		short value;
+		char param;
+	} option[MAX_ITEM_RDM_OPT];		// max of 5 random options can be supported.
 	unsigned int expire_time;
 	char favorite, bound;
 	uint64 unique_id;

+ 1 - 0
src/map/battle.c

@@ -4519,6 +4519,7 @@ struct Damage battle_calc_defense_reduction(struct Damage wd, struct block_list
 
 	if (sd) {
 		int i = sd->ignore_def_by_race[tstatus->race] + sd->ignore_def_by_race[RC_ALL];
+		i += sd->ignore_def_by_class[tstatus->class_] + sd->ignore_def_by_class[CLASS_ALL];
 		if (i) {
 			i = min(i,100); //cap it to 100 for 0 def min
 			def1 -= def1 * i / 100;

+ 8 - 9
src/map/clif.c

@@ -2434,17 +2434,16 @@ static void clif_addcards(unsigned char* buf, struct item* item)
 		WBUFW(buf,6) = item->card[i];
 }
 
-/// Fills in part of the item buffers that calls for variable bonuses data. [Rytech]
-/// Dummy data used since this feature isnt supported yet (ITEM_RDM_OPT).
-/// A max of 5 random options can be supported.
-void clif_add_random_options(unsigned char* buf, struct item* item)
-{
+/// Fills in part of the item buffers that calls for variable bonuses data. [Napster]
+/// A maximum of 5 random options can be supported.
+void clif_add_random_options(unsigned char* buf, struct item *it) {
 #if PACKETVER >= 20150226
 	int i;
-	for (i = 0; i < 5; i++){
-		WBUFW(buf,i*5+0) = 0;	// OptIndex
-		WBUFW(buf,i*5+2) = 0;	// Value
-		WBUFB(buf,i*5+4) = 0;	// Param1
+
+	for (i = 0; i < MAX_ITEM_RDM_OPT; i++) {
+		WBUFW(buf, i*5 + 0) = it->option[i].id;		// OptIndex
+		WBUFW(buf, i*5 + 2) = it->option[i].value;	// Value
+		WBUFB(buf, i*5 + 4) = it->option[i].param;	// Param1
 	}
 #endif
 }

+ 99 - 0
src/map/itemdb.c

@@ -17,6 +17,7 @@
 static DBMap *itemdb; /// Item DB
 static DBMap *itemdb_combo; /// Item Combo DB
 static DBMap *itemdb_group; /// Item Group DB
+static DBMap *itemdb_randomopt; /// Random option DB
 
 struct item_data *dummy_item; /// This is the default dummy item used for non-existant items. [Skotlex]
 
@@ -1543,6 +1544,102 @@ bool itemdb_is_spellbook2(unsigned short nameid) {
 	return i == MAX_SKILL_SPELLBOOK_DB ? false : true;
 }
 
+/**
+* Retrieves random option data
+*/
+struct s_random_opt_data* itemdb_randomopt_exists(short id) {
+	return ((struct s_random_opt_data*)uidb_get(itemdb_randomopt, id));
+}
+
+/** Random option
+* <ID>,<{Script}>
+*/
+static bool itemdb_read_randomopt(const char* basedir, bool silent) {
+	uint32 lines = 0, count = 0;
+	char line[1024];
+
+	char path[256];
+	FILE* fp;
+
+	sprintf(path, "%s/%s", basedir, "item_randomopt_db.txt");
+
+	if ((fp = fopen(path, "r")) == NULL) {
+		if (silent == 0) ShowError("itemdb_read_randomopt: File not found \"%s\".\n", path);
+		return false;
+	}
+
+	while (fgets(line, sizeof(line), fp)) {
+		char *str[2], *p;
+
+		lines++;
+
+		if (line[0] == '/' && line[1] == '/') // Ignore comments
+			continue;
+
+		memset(str, 0, sizeof(str));
+
+		p = line;
+
+		p = trim(p);
+
+		if (*p == '\0')
+			continue;// empty line
+
+		if (!strchr(p, ','))
+		{
+			ShowError("itemdb_read_combos: Insufficient columns in line %d of \"%s\", skipping.\n", lines, path);
+			continue;
+		}
+
+		str[0] = p;
+		p = strchr(p, ',');
+		*p = '\0';
+		p++;
+
+		str[1] = p;
+
+		if (str[1][0] != '{') {
+			ShowError("itemdb_read_randomopt(#1): Invalid format (Script column) in line %d of \"%s\", skipping.\n", lines, path);
+			continue;
+		}
+		/* no ending key anywhere (missing \}\) */
+		if (str[1][strlen(str[1]) - 1] != '}') {
+			ShowError("itemdb_read_randomopt(#2): Invalid format (Script column) in line %d of \"%s\", skipping.\n", lines, path);
+			continue;
+		}
+		else {
+			int id;
+			str[0] = trim(str[0]);
+			if (ISDIGIT(str[0][0])) {
+				id = atoi(str[0]);
+			}
+			else {
+				script_get_constant(str[0], &id);
+			}
+			struct s_random_opt_data *data;
+			struct script_code *code;
+
+			if ((data = itemdb_randomopt_exists(id)) == NULL) {
+				data = malloc(sizeof(struct s_random_opt_data));
+				memset(data, 0, sizeof(struct s_random_opt_data));
+				uidb_put(itemdb_randomopt, id, data);
+			}
+			data->id = id;
+			if ((code = parse_script(str[1], "item_randomopt_db.txt", 0, 0)) == NULL) {
+				ShowWarning("itemdb_read_randomopt: Invalid script on option ID #%d.\n", id);
+				continue;
+			}
+			data->script = code;
+		}
+		count++;
+	}
+	fclose(fp);
+
+	ShowStatus("Done reading '"CL_WHITE"%lu"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, path);
+
+	return true;
+}
+
 /**
 * Read all item-related databases
 */
@@ -1588,6 +1685,7 @@ static void itemdb_read(void) {
 		sv_readdb(dbsubpath2, "item_package.txt",		',', 2, 10, -1, &itemdb_read_group, i);
 #endif
 		itemdb_read_combos(dbsubpath2,i); //TODO change this to sv_read ? id#script ?
+		itemdb_read_randomopt(dbsubpath2, i);
 		sv_readdb(dbsubpath2, "item_noequip.txt",       ',', 2, 2, -1, &itemdb_read_noequip, i);
 		sv_readdb(dbsubpath2, "item_trade.txt",         ',', 3, 3, -1, &itemdb_read_itemtrade, i);
 		sv_readdb(dbsubpath2, "item_delay.txt",         ',', 2, 3, -1, &itemdb_read_itemdelay, i);
@@ -1754,6 +1852,7 @@ void do_init_itemdb(void) {
 	itemdb = uidb_alloc(DB_OPT_BASE);
 	itemdb_combo = uidb_alloc(DB_OPT_BASE);
 	itemdb_group = uidb_alloc(DB_OPT_BASE);
+	itemdb_randomopt = uidb_alloc(DB_OPT_BASE);
 	itemdb_create_dummy();
 	itemdb_read();
 

+ 10 - 0
src/map/itemdb.h

@@ -453,6 +453,13 @@ struct item_data
 	short delay_sc; ///< Use delay group if any instead using player's item_delay data [Cydh]
 };
 
+// Struct for item random option [Secret]
+struct s_random_opt_data
+{
+	unsigned short id;
+	struct script_code *script;
+};
+
 struct item_data* itemdb_searchname(const char *name);
 int itemdb_searchname_array(struct item_data** data, int size, const char *str);
 struct item_data* itemdb_search(unsigned short nameid);
@@ -528,6 +535,9 @@ uint16 itemdb_get_randgroupitem_count(uint16 group_id, uint8 sub_group, unsigned
 
 bool itemdb_parse_roulette_db(void);
 
+struct s_random_opt_data* itemdb_randomopt_exists(short id);
+short itemdb_randomopt_name2id(const char *name);
+
 void itemdb_reload(void);
 
 void do_final_itemdb(void);

+ 1 - 0
src/map/map.h

@@ -469,6 +469,7 @@ enum _sp {
 	SP_HP_VANISH_RACE_RATE, SP_SP_VANISH_RACE_RATE, SP_ABSORB_DMG_MAXHP, SP_SUB_SKILL, SP_SUBDEF_ELE, // 2074-2078
 	SP_STATE_NORECOVER_RACE, SP_CRITICAL_RANGEATK, SP_MAGIC_ADDRACE2, SP_IGNORE_MDEF_RACE2_RATE, // 2079-2082
 	SP_WEAPON_ATK_RATE, SP_WEAPON_MATK_RATE, SP_DROP_ADDRACE, SP_DROP_ADDCLASS, SP_NO_MADO_FUEL, // 2083-2087
+	SP_IGNORE_DEF_CLASS_RATE, //2088
 };
 
 enum _look {

+ 5 - 0
src/map/pc.c

@@ -3534,6 +3534,11 @@ void pc_bonus2(struct map_session_data *sd,int type,int type2,int val)
 		if(sd->state.lr_flag != 2)
 			sd->ignore_def_by_race[type2] += val;
 		break;
+	case SP_IGNORE_DEF_CLASS_RATE: // bonus2 bIgnoreDefClassRate,r,n;
+		PC_BONUS_CHK_RACE(type2, SP_IGNORE_DEF_CLASS_RATE);
+		if (sd->state.lr_flag != 2)
+			sd->ignore_def_by_class[type2] += val;
+		break;
 	case SP_SKILL_USE_SP_RATE: // bonus2 bSkillUseSPrate,sk,n;
 		if(sd->state.lr_flag == 2)
 			break;

+ 1 - 0
src/map/pc.h

@@ -368,6 +368,7 @@ struct map_session_data {
 	int ignore_mdef_by_race[RC_MAX];
 	int ignore_mdef_by_class[CLASS_MAX];
 	int ignore_def_by_race[RC_MAX];
+	int ignore_def_by_class[CLASS_MAX];
 	short sp_gain_race[RC_MAX];
 	int magic_addrace2[RC2_MAX];
 	int ignore_mdef_by_race2[RC2_MAX];

+ 25 - 0
src/map/script.c

@@ -21529,6 +21529,30 @@ BUILDIN_FUNC(hateffect){
 	return SCRIPT_CMD_SUCCESS;
 }
 
+/**
+* Retrieves param of current random option. Intended for random option script only.
+* getrandomoptinfo(<type>);
+* @author [secretdataz]
+**/
+BUILDIN_FUNC(getrandomoptinfo) {
+	struct map_session_data *sd;
+	int param = script_getnum(st, 1);
+	if ((sd = script_rid2sd(st)) != NULL && current_equip_item_index && current_equip_item_index > -1 && sd->status.inventory[current_equip_item_index].option[current_equip_opt_index].id) {
+		if (param == ROA_VALUE)
+			script_pushint(st, sd->status.inventory[current_equip_item_index].option[current_equip_opt_index].value);
+		else if (param == ROA_PARAM)
+			script_pushint(st, sd->status.inventory[current_equip_item_index].option[current_equip_opt_index].param);
+		else {
+			ShowWarning("buildin_getrandomoptinfo: Unknown parameter %d.", param);
+			return SCRIPT_CMD_FAILURE;
+		}
+	}
+	else {
+		script_pushint(st, 0);
+	}
+	return SCRIPT_CMD_SUCCESS;
+}
+
 #include "../custom/script.inc"
 
 // declarations that were supposed to be exported from npc_chat.c
@@ -22108,6 +22132,7 @@ struct script_function buildin_func[] = {
 	BUILDIN_DEF(getexp2,"ii?"),
 	BUILDIN_DEF(recalculatestat,""),
 	BUILDIN_DEF(hateffect,"ii"),
+	BUILDIN_DEF(getrandomoptinfo, "i"),
 
 #include "../custom/script_def.inc"
 

+ 4 - 0
src/map/script.h

@@ -636,6 +636,10 @@ enum navigation_service {
 	NAV_ALL = NAV_AIRSHIP_ONLY + NAV_SCROLL_ONLY + NAV_KAFRA_ONLY ///< 111 (actually 111-255)
 };
 
+enum random_option_attribute {
+	ROA_VALUE = 0,
+	ROA_PARAM,
+};
 /**
  * used to generate quick script_array entries
  **/

+ 5 - 0
src/map/script_constants.h

@@ -663,6 +663,7 @@
 	script_set_constant("bDropAddRace", SP_DROP_ADDRACE, false);
 	script_set_constant("bDropAddClass", SP_DROP_ADDCLASS, false);
 	script_set_constant("bNoMadoFuel", SP_NO_MADO_FUEL, false);
+	script_set_constant("bIgnoreDefClassRate", SP_IGNORE_DEF_CLASS_RATE, false);
 
 	/* equip indices */
 	export_constant(EQI_HEAD_TOP);
@@ -3108,6 +3109,10 @@
 	export_constant(MOBG_Red_Pouch_Of_Surprise);
 	export_constant(MOBG_ClassChange);
 
+	/* random option attributes */
+	export_constant(ROA_VALUE);
+	export_constant(ROA_PARAM);
+
 	#undef export_constant
 
 #endif /* _SCRIPT_CONSTANTS_H_ */

+ 45 - 3
src/map/status.c

@@ -50,6 +50,7 @@ unsigned int current_equip_combo_pos; /// For combo items we need to save the po
 int current_equip_card_id; /// To prevent card-stacking (from jA) [Skotlex]
 bool running_npc_stat_calc_event; /// Indicate if OnPCStatCalcEvent is running.
 // We need it for new cards 15 Feb 2005, to check if the combo cards are insrerted into the CURRENT weapon only to avoid cards exploits
+short current_equip_opt_index; /// Contains random option index of an equipped item. [Secret]
 
 unsigned int SCDisabled[SC_MAX]; ///< List of disabled SC on map zones. [Cydh]
 
@@ -3450,10 +3451,51 @@ int status_calc_pc_(struct map_session_data* sd, enum e_status_calc_opt opt)
 	}
 	current_equip_card_id = 0; // Clear stored card ID [Secret]
 
-	if( sc->count && sc->data[SC_ITEMSCRIPT] ) {
+	// Parse random options
+	for (i = 0; i < EQI_MAX; i++) {
+		current_equip_item_index = index = sd->equip_index[i];
+		current_equip_combo_pos = 0;
+		if (index < 0)
+			continue;
+		if (i == EQI_AMMO)
+			continue;
+		if (pc_is_same_equip_index((enum equip_index)i, sd->equip_index, index))
+			continue;
+		
+		if (sd->inventory_data[index]) {
+			int j;
+			struct item_data *itemdata;
+			struct s_random_opt_data *data;
+			for (j = 0; j < MAX_ITEM_RDM_OPT; j++) {
+				short opt_id = sd->status.inventory[index].option[j].id;
+				unsigned short nameid = sd->status.inventory[index].nameid;
+				if (!opt_id)
+					continue;
+				current_equip_opt_index = j;
+				itemdata = itemdb_exists(nameid);
+				data = itemdb_randomopt_exists(opt_id);
+				if (!data || !data->script)
+					continue;
+				if (!pc_has_permission(sd, PC_PERM_USE_ALL_EQUIPMENT) && itemdb_isNoEquip(itemdata, sd->bl.m))
+					continue;
+				if (i == EQI_HAND_L && sd->status.inventory[index].equip == EQP_HAND_L) { // Left hand status.
+					sd->state.lr_flag = 1;
+					run_script(data->script, 0, sd->bl.id, 0);
+					sd->state.lr_flag = 0;
+				}
+				else
+					run_script(data->script, 0, sd->bl.id, 0);
+				if (!calculating)
+					return 1;
+			}
+		}
+		current_equip_opt_index = 0;
+	}
+
+	if (sc->count && sc->data[SC_ITEMSCRIPT]) {
 		struct item_data *data = itemdb_exists(sc->data[SC_ITEMSCRIPT]->val1);
-		if( data && data->script )
-			run_script(data->script,0,sd->bl.id,0);
+		if (data && data->script)
+			run_script(data->script, 0, sd->bl.id, 0);
 	}
 
 	pc_bonus_script(sd);

+ 1 - 0
src/map/status.h

@@ -1719,6 +1719,7 @@ extern short current_equip_item_index;
 extern unsigned int current_equip_combo_pos;
 extern int current_equip_card_id;
 extern bool running_npc_stat_calc_event;
+extern short current_equip_opt_index;
 
 /// Mode definitions to clear up code reading. [Skotlex]
 enum e_mode {