Browse Source

RE:Initial release script commands for Item Random Options (#2066)

* Added script commands getitem3, getitembound3, makeitem3, rentitem3, countitem3, and delitem3.
Cydh Ramdh 8 years ago
parent
commit
a15661ecfa
2 changed files with 301 additions and 41 deletions
  1. 77 0
      doc/script_commands.txt
  2. 224 41
      src/map/script.c

+ 77 - 0
doc/script_commands.txt

@@ -4393,6 +4393,8 @@ quite a few item scripts. For more examples check just about any official script
 
 
 *getitem2 <item id>,<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<account ID>};
 *getitem2 <item id>,<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<account ID>};
 *getitem2 "<item name>",<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<account ID>};
 *getitem2 "<item name>",<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<account ID>};
+*getitem3 <item id>,<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>,<RandomIDArray>,<RandomValueArray>,<RandomParamArray>{,<account ID>};
+*getitem3 "<item name>",<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>,<RandomIDArray>,<RandomValueArray>,<RandomParamArray>{,<account ID>};
 
 
 This command will give an amount of specified items to the invoking character. 
 This command will give an amount of specified items to the invoking character. 
 If an optional account ID is specified, and the target character is currently 
 If an optional account ID is specified, and the target character is currently 
@@ -4478,6 +4480,18 @@ command, creating a pet which is the same, but simultaneously exists in two
 eggs, and may hatch from either, although, I'm not sure what kind of a mess will 
 eggs, and may hatch from either, although, I'm not sure what kind of a mess will 
 this really cause.
 this really cause.
 
 
+'getitem3' is advance version of 'getitem2' that also use Item Random Option as additional values.
+<RandomIDArray>    : Array variable of ID for item random option, see db/[pre-]re/item_randomopt_db.txt
+<RandomValueArray> : Array variable of item random option's value.
+<RandomParamArray> : Array variable of item random option's param.
+
+Example to get Crimson Weapon with Ghost property:
+	// +9 Crimson Dagger [2]
+	setarray .@OptID[0],RDMOPT_WEAPON_ATTR_TELEKINESIS;
+	setarray .@OptVal[0],0;
+	setarray .@OptParam[0],0;
+	getitem3 28705,1,1,9,0,0,0,0,0,.@OptID,.@OptVal,.@OptParam;
+
 ---------------------------------------
 ---------------------------------------
 
 
 *getitembound <item id>,<amount>,<bound type>{,<account ID>};
 *getitembound <item id>,<amount>,<bound type>{,<account ID>};
@@ -4498,6 +4512,8 @@ Valid bound types are:
 
 
 *getitembound2 <item id>,<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>,<bound type>{,<account ID>};
 *getitembound2 <item id>,<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>,<bound type>{,<account ID>};
 *getitembound2 "<item name>",<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>,<bound type>{,<account ID>};
 *getitembound2 "<item name>",<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>,<bound type>{,<account ID>};
+*getitembound3 <item id>,<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>,<bound type>,<RandomIDArray>,<RandomValueArray>,<RandomParamArray>{,<account ID>};
+*getitembound3 "<item name>",<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>,<bound type>,<RandomIDArray>,<RandomValueArray>,<RandomParamArray>{,<account ID>};
 
 
 This command behaves identically to 'getitem2', but the items created will be
 This command behaves identically to 'getitem2', but the items created will be
 bound to the target character as specified by the bound type. All items created
 bound to the target character as specified by the bound type. All items created
@@ -4506,6 +4522,18 @@ some cases cannot be traded or stored.
 
 
 For a list of bound types see 'getitembound'.
 For a list of bound types see 'getitembound'.
 
 
+'getitembound3' is advance version of 'getitembound2' that also use Item Random Option as additional values.
+<RandomIDArray>    : Array variable of ID for item random option, see db/[pre-]re/item_randomopt_db.txt
+<RandomValueArray> : Array variable of item random option's value.
+<RandomParamArray> : Array variable of item random option's param.
+
+Example to get Crimson Weapon with Ghost property:
+	// +9 Crimson Dagger [2]
+	setarray .@OptID[0],RDMOPT_WEAPON_ATTR_TELEKINESIS;
+	setarray .@OptVal[0],0;
+	setarray .@OptParam[0],0;
+	getitembound3 28705,1,1,9,0,0,0,0,0,BOUND_CHAR,.@OptID,.@OptVal,.@OptParam;
+
 ---------------------------------------
 ---------------------------------------
 
 
 *getnameditem <item id>,<character name|character ID>;
 *getnameditem <item id>,<character name|character ID>;
@@ -4551,12 +4579,26 @@ Note: 'delitem' in an NPC script can still remove rental items.
 
 
 *rentitem2 <item id>,<time>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<account_id>};
 *rentitem2 <item id>,<time>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<account_id>};
 *rentitem2 "<item name>",<time>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<account_id>};
 *rentitem2 "<item name>",<time>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<account_id>};
+*rentitem3 <item id>,<time>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>,<RandomIDArray>,<RandomValueArray>,<RandomParamArray>{,<account_id>};
+*rentitem3 "<item name>",<time>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>,<RandomIDArray>,<RandomValueArray>,<RandomParamArray>{,<account_id>};
 
 
 Creates a rental item in the attached character's inventory. The item will expire 
 Creates a rental item in the attached character's inventory. The item will expire 
 in <time> seconds and be automatically deleted. See 'rentitem' for further details.
 in <time> seconds and be automatically deleted. See 'rentitem' for further details.
 
 
 See 'getitem2' for an explanation of the expanded parameters.
 See 'getitem2' for an explanation of the expanded parameters.
 
 
+'rentitem3' is advance version of 'rentitem2' that also use Item Random Option as additional values.
+<RandomIDArray>    : Array variable of ID for item random option, see db/[pre-]re/item_randomopt_db.txt
+<RandomValueArray> : Array variable of item random option's value.
+<RandomParamArray> : Array variable of item random option's param.
+
+Example to get Crimson Weapon with Ghost property:
+	// +9 Crimson Dagger [2]
+	setarray .@OptID[0],RDMOPT_WEAPON_ATTR_TELEKINESIS;
+	setarray .@OptVal[0],0;
+	setarray .@OptParam[0],0;
+	rentitem3 28705,(24*60*60),1,9,0,0,0,0,0,.@OptID,.@OptVal,.@OptParam;
+
 ---------------------------------------
 ---------------------------------------
 
 
 *makeitem <item id>,<amount>,"<map name>",<X>,<Y>;
 *makeitem <item id>,<amount>,"<map name>",<X>,<Y>;
@@ -4576,12 +4618,33 @@ If the map name is given as "this", the map the invoking character is on will be
 
 
 *makeitem2 <item id>,<amount>,"<map name>",<X>,<Y>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>;
 *makeitem2 <item id>,<amount>,"<map name>",<X>,<Y>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>;
 *makeitem2 "<item name>",<amount>,"<map name>",<X>,<Y>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>;
 *makeitem2 "<item name>",<amount>,"<map name>",<X>,<Y>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>;
+*makeitem3 <item id>,<amount>,"<map name>",<X>,<Y>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>,<RandomIDArray>,<RandomValueArray>,<RandomParamArray>;
+*makeitem3 "<item name>",<amount>,"<map name>",<X>,<Y>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>,<RandomIDArray>,<RandomValueArray>,<RandomParamArray>;
 
 
 This command will create an item on the specified cell of a map. See 'makeitem' for
 This command will create an item on the specified cell of a map. See 'makeitem' for
 further details.
 further details.
 
 
 See 'getitem2' for an explanation of the expanded parameters.
 See 'getitem2' for an explanation of the expanded parameters.
 
 
+'makeitem3' is advance version of 'makeitem2' that also use Item Random Option as additional values.
+<RandomIDArray>    : Array variable of ID for item random option, see db/[pre-]re/item_randomopt_db.txt
+<RandomValueArray> : Array variable of item random option's value.
+<RandomParamArray> : Array variable of item random option's param.
+
+Example to get Crimson Weapon with Ghost property:
+	// 0.5% chance to get +0 Valkyrie Shield [1]
+	// with Neutral Resistance +10% and 5% damage reduction from Demi-Human or Player
+	// when Valkyrie Randgris killed
+	OnNPCKillEvent:
+		if (killedrid == 1751 && rand(0,1000) > 950) { // Valkyrie Randgris
+			getmapxy(.@map$,.@x,.@y,UNITTYPE_PC);
+			setarray .@OptID[0],RDMOPT_ATTR_TOLERACE_NOTHING,RDMOPT_RACE_TOLERACE_HUMAN;
+			setarray .@OptVal[0],10,5;
+			setarray .@OptParam[0],0;
+			makeitem3 2115,1,.@map$,.@x,.@y,0,0,0,0,0,0,0,.@OptID,.@OptVal,.@OptParam;
+		}
+		end;
+
 ---------------------------------------
 ---------------------------------------
 
 
 *cleanarea "<map name>",<x1>,<y1>,<x2>,<y2>;
 *cleanarea "<map name>",<x1>,<y1>,<x2>,<y2>;
@@ -4643,10 +4706,17 @@ If player is not in a guild or storage is open, 'guildstoragedelitem' will retur
 
 
 *delitem2 <item id>,<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<account ID>};
 *delitem2 <item id>,<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<account ID>};
 *delitem2 "<item name>",<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<account ID>};
 *delitem2 "<item name>",<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<account ID>};
+*delitem3 <item id>,<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>,<RandomIDArray>,<RandomValueArray>,<RandomParamArray>{,<account ID>};
+*delitem3 "<item name>",<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>,<RandomIDArray>,<RandomValueArray>,<RandomParamArray>{,<account ID>};
 
 
 This command will remove a specified amount of items from the invoking/target character. 
 This command will remove a specified amount of items from the invoking/target character. 
 See 'getitem2' for an explanation of the expanded parameters.
 See 'getitem2' for an explanation of the expanded parameters.
 
 
+'delitem3' is advance version of 'delitem2' that also use Item Random Option as criteria.
+<RandomIDArray>    : Array variable of ID for item random option, see db/[pre-]re/item_randomopt_db.txt
+<RandomValueArray> : Array variable of item random option's value.
+<RandomParamArray> : Array variable of item random option's param.
+
 ---------------------------------------
 ---------------------------------------
 
 
 *cartdelitem2 <item id>,<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<account ID>};
 *cartdelitem2 <item id>,<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<account ID>};
@@ -4703,6 +4773,8 @@ If player is not in a guild or storage is open, 'guildstoragecountitem' will ret
 
 
 *countitem2(<item id>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>)
 *countitem2(<item id>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>)
 *countitem2("<item name>",<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>)
 *countitem2("<item name>",<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>)
+*countitem3(<item id>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>,<RandomIDArray>,<RandomValueArray>,<RandomParamArray>)
+*countitem3("<item name>",<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>,<RandomIDArray>,<RandomValueArray>,<RandomParamArray>)
 
 
 Expanded version of 'countitem' function, used for created/carded/forged items.
 Expanded version of 'countitem' function, used for created/carded/forged items.
 
 
@@ -4710,6 +4782,11 @@ This function will return the number of items for the specified item ID and
 other parameters that the invoking character has in the inventory.
 other parameters that the invoking character has in the inventory.
 See 'getitem2' for an explanation of the expanded parameters.
 See 'getitem2' for an explanation of the expanded parameters.
 
 
+'countitem3' is advance version of 'countitem2' that also use Item Random Option as criteria.
+<RandomIDArray>    : Array variable of ID for item random option, see db/[pre-]re/item_randomopt_db.txt
+<RandomValueArray> : Array variable of item random option's value.
+<RandomParamArray> : Array variable of item random option's param.
+
 ---------------------------------------
 ---------------------------------------
 
 
 *cartcountitem2(<item id>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<accountID>})
 *cartcountitem2(<item id>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<accountID>})

+ 224 - 41
src/map/script.c

@@ -667,7 +667,6 @@ static void script_reportfunc(struct script_state* st)
 		ShowDebug("Function: %s (no parameters)\n", get_str(id));
 		ShowDebug("Function: %s (no parameters)\n", get_str(id));
 	}
 	}
 }
 }
-
 /*==========================================
 /*==========================================
  * Output error message
  * Output error message
  *------------------------------------------*/
  *------------------------------------------*/
@@ -6661,6 +6660,74 @@ BUILDIN_FUNC(viewpoint)
 	return SCRIPT_CMD_SUCCESS;
 	return SCRIPT_CMD_SUCCESS;
 }
 }
 
 
+/**
+ * Set random options for new item
+ * @param st Script state
+ * @param it Temporary item data
+ * @param funcname Function name
+ * @param x First position of random option id array from the script
+ **/
+static int script_getitem_randomoption(struct script_state *st, struct item *it, const char *funcname, int x) {
+	int i, opt_id_n, opt_val_n, opt_param_n;
+	struct script_data *opt_id = script_getdata(st,x);
+	struct script_data *opt_val = script_getdata(st,x+1);
+	struct script_data *opt_param = script_getdata(st,x+2);
+	const char *opt_id_var = reference_getname(opt_id);
+	const char *opt_val_var = reference_getname(opt_val);
+	const char *opt_param_var = reference_getname(opt_param);
+	int32 opt_id_id, opt_id_idx;
+	int32 opt_val_id, opt_val_idx;
+	int32 opt_param_id, opt_param_idx;
+	struct reg_db *opt_id_ref = NULL, *opt_val_ref = NULL, *opt_param_ref = NULL;
+
+	if (opt_id_var[strlen(opt_id_var)-1] == '$') {
+		ShowError("buildin_%s: The array %s is not numeric type.\n", funcname, opt_id_var);
+		return SCRIPT_CMD_FAILURE;
+	}
+
+	if (opt_val_var[strlen(opt_val_var)-1] == '$') {
+		ShowError("buildin_%s: The array %s is not numeric type.\n", funcname, opt_val_var);
+		return SCRIPT_CMD_FAILURE;
+	}
+
+	if (opt_param_var[strlen(opt_param_var)-1] == '$') {
+		ShowError("buildin_%s: The array %s is not numeric type.\n", funcname, opt_param_var);
+		return SCRIPT_CMD_FAILURE;
+	}
+
+	opt_id_ref = reference_getref(opt_id);
+	opt_id_n = script_array_highest_key(st, NULL, opt_id_var, opt_id_ref);
+
+	if (opt_id_n < 1) {
+		ShowError("buildin_%s: No option id listed.\n", funcname);
+		return SCRIPT_CMD_FAILURE;
+	}
+
+	opt_val_ref = reference_getref(opt_val);
+	opt_param_ref = reference_getref(opt_param);
+
+	opt_val_n = script_array_highest_key(st, NULL, opt_val_var, opt_val_ref);
+	opt_param_n = script_array_highest_key(st, NULL, opt_param_var, opt_param_ref);
+
+	opt_id_id = reference_getid(opt_id);
+	opt_val_id = reference_getid(opt_val);
+	opt_param_id = reference_getid(opt_param);
+
+	opt_id_idx = reference_getindex(opt_id);
+	opt_val_idx = reference_getindex(opt_val);
+	opt_param_idx = reference_getindex(opt_param);
+	
+	for (i = 0; i < opt_id_n && i < MAX_ITEM_RDM_OPT; i++) {
+		it->option[i].id = (short)__64BPRTSIZE(get_val2(st,reference_uid(opt_id_id,opt_id_idx+i),opt_id_ref));
+		script_removetop(st, -1, 0);
+		it->option[i].value = (short)__64BPRTSIZE(get_val2(st,reference_uid(opt_val_id,opt_val_idx+i),opt_val_ref));
+		script_removetop(st, -1, 0);
+		it->option[i].param = (char)__64BPRTSIZE(get_val2(st,reference_uid(opt_param_id,opt_param_idx+i),opt_param_ref));
+		script_removetop(st, -1, 0);
+	}
+	return SCRIPT_CMD_SUCCESS;
+}
+
 /// Returns number of items in inventory/cart/storage
 /// Returns number of items in inventory/cart/storage
 /// countitem <nameID>{,<accountID>});
 /// countitem <nameID>{,<accountID>});
 /// countitem2 <nameID>,<Identified>,<Refine>,<Attribute>,<Card0>,<Card1>,<Card2>,<Card3>{,<accountID>}) [Lupus]
 /// countitem2 <nameID>,<Identified>,<Refine>,<Attribute>,<Card0>,<Card1>,<Card2>,<Card3>{,<accountID>}) [Lupus]
@@ -6670,6 +6737,8 @@ BUILDIN_FUNC(viewpoint)
 /// storagecountitem2 <nameID>,<Identified>,<Refine>,<Attribute>,<Card0>,<Card1>,<Card2>,<Card3>{,<accountID>})
 /// storagecountitem2 <nameID>,<Identified>,<Refine>,<Attribute>,<Card0>,<Card1>,<Card2>,<Card3>{,<accountID>})
 /// guildstoragecountitem <nameID>{,<accountID>});
 /// guildstoragecountitem <nameID>{,<accountID>});
 /// guildstoragecountitem2 <nameID>,<Identified>,<Refine>,<Attribute>,<Card0>,<Card1>,<Card2>,<Card3>{,<accountID>})
 /// guildstoragecountitem2 <nameID>,<Identified>,<Refine>,<Attribute>,<Card0>,<Card1>,<Card2>,<Card3>{,<accountID>})
+/// countitem3(<item id>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>,<RandomIDArray>,<RandomValueArray>,<RandomParamArray>)
+/// countitem3("<item name>",<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>,<RandomIDArray>,<RandomValueArray>,<RandomParamArray>)
 BUILDIN_FUNC(countitem)
 BUILDIN_FUNC(countitem)
 {
 {
 	int i = 0, aid = 3;
 	int i = 0, aid = 3;
@@ -6686,7 +6755,11 @@ BUILDIN_FUNC(countitem)
 		i = 1;
 		i = 1;
 		aid = 10;
 		aid = 10;
 	}
 	}
-	
+	else if (command[strlen(command)-1] == '3') {
+		i = 1;
+		aid = 13;
+	}
+
 	if( script_hasdata(st,aid) ) {
 	if( script_hasdata(st,aid) ) {
 		if( !(sd = map_id2sd( (aid = script_getnum(st, aid)) )) ) {
 		if( !(sd = map_id2sd( (aid = script_getnum(st, aid)) )) ) {
 			ShowError("buildin_%s: player not found (AID=%d).\n", command, aid);
 			ShowError("buildin_%s: player not found (AID=%d).\n", command, aid);
@@ -6698,7 +6771,7 @@ BUILDIN_FUNC(countitem)
 		if( !script_rid2sd(sd) )
 		if( !script_rid2sd(sd) )
 			return SCRIPT_CMD_SUCCESS;
 			return SCRIPT_CMD_SUCCESS;
 	}
 	}
-	
+
 	if( !strncmp(command, "cart", 4) ) {
 	if( !strncmp(command, "cart", 4) ) {
 		loc = TABLE_CART;
 		loc = TABLE_CART;
 		size = MAX_CART;
 		size = MAX_CART;
@@ -6756,27 +6829,45 @@ BUILDIN_FUNC(countitem)
 				count += items[i].amount;
 				count += items[i].amount;
 	}
 	}
 	else { // For count/cart/storagecountitem2 function
 	else { // For count/cart/storagecountitem2 function
-		unsigned short nameid;
-		int iden, ref, attr, c1, c2, c3, c4;
-
-		nameid = id->nameid;
-		iden = script_getnum(st,3);
-		ref  = script_getnum(st,4);
-		attr = script_getnum(st,5);
-		c1 = script_getnum(st,6);
-		c2 = script_getnum(st,7);
-		c3 = script_getnum(st,8);
-		c4 = script_getnum(st,9);
+		struct item it;
+		bool check_randomopt = false;
+		memset(&it, 0, sizeof(it));
+
+		it.nameid = id->nameid;
+		it.identify = script_getnum(st,3);
+		it.refine  = script_getnum(st,4);
+		it.attribute = script_getnum(st,5);
+		it.card[0] = script_getnum(st,6);
+		it.card[1] = script_getnum(st,7);
+		it.card[2] = script_getnum(st,8);
+		it.card[3] = script_getnum(st,9);
+
+		if (command[strlen(command)-1] == '3') {
+			int res = script_getitem_randomoption(st, &it, command, 10);
+			if (res != SCRIPT_CMD_SUCCESS)
+				return SCRIPT_CMD_FAILURE;
+			check_randomopt = true;
+		}
 
 
-		for( i = 0; i < size; i++ )
-			if( &items[i] && items[i].nameid > 0 && items[i].nameid == nameid &&
-				items[i].amount > 0 && items[i].identify == iden &&
-				items[i].refine == ref && items[i].attribute == attr &&
-				items[i].card[0] == c1 && items[i].card[1] == c2 &&
-				items[i].card[2] == c3 && items[i].card[3] == c4 )
-			{
-				count += items[i].amount;
+		for( i = 0; i < size; i++ ) {
+			struct item *itm = &items[i];
+			if (!itm || !itm->nameid || itm->amount < 1)
+				continue;
+			if (itm->nameid != it.nameid || itm->identify != it.identify || itm->refine != it.refine || itm->attribute != it.attribute)
+				continue;
+			if (memcmp(it.card, itm->card, sizeof(it.card)))
+				continue;
+			if (check_randomopt) {
+				uint8 j;
+				for (j = 0; j < MAX_ITEM_RDM_OPT; j++) {
+					if (itm->option[j].id != it.option[j].id || itm->option[j].value != it.option[j].value || itm->option[j].param != it.option[j].param)
+						break;
+				}
+				if (j != MAX_ITEM_RDM_OPT)
+					continue;
 			}
 			}
+			count += items[i].amount;
+		}
 	}
 	}
 
 
 	if (loc == TABLE_GUILD_STORAGE) {
 	if (loc == TABLE_GUILD_STORAGE) {
@@ -7071,6 +7162,12 @@ BUILDIN_FUNC(getitem)
  *
  *
  * getitembound2 <item id>,<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>,<bound type>{,<account ID>};
  * getitembound2 <item id>,<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>,<bound type>{,<account ID>};
  * getitembound2 "<item name>",<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>,<bound type>{,<account ID>};
  * getitembound2 "<item name>",<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>,<bound type>{,<account ID>};
+ *
+ * getitem3 <item id>,<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>,<RandomIDArray>,<RandomValueArray>,<RandomParamArray>{,<account ID>};
+ * getitem3 "<item name>",<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>,<RandomIDArray>,<RandomValueArray>,<RandomParamArray>{,<account ID>};
+ *
+ * getitembound3 <item id>,<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>,<bound type>,<RandomIDArray>,<RandomValueArray>,<RandomParamArray>{,<account ID>};
+ * getitembound3 "<item name>",<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>,<bound type>,<RandomIDArray>,<RandomValueArray>,<RandomParamArray>{,<account ID>};
  * Type:
  * Type:
  *	0 - No bound
  *	0 - No bound
  *	1 - Account Bound
  *	1 - Account Bound
@@ -7089,16 +7186,27 @@ BUILDIN_FUNC(getitem2)
 	TBL_PC *sd;
 	TBL_PC *sd;
 	struct script_data *data;
 	struct script_data *data;
 	const char* command = script_getfuncname(st);
 	const char* command = script_getfuncname(st);
+	int offset = 0;
 
 
-	if( !strcmp(command,"getitembound2") ) {
+	if( !strncmp(command,"getitembound",12) ) {
+		int aid_pos = 12;
 		bound = script_getnum(st,11);
 		bound = script_getnum(st,11);
 		if( bound < BOUND_NONE || bound >= BOUND_MAX ) {
 		if( bound < BOUND_NONE || bound >= BOUND_MAX ) {
 			ShowError("script_getitembound2: Not a correct bound type! Type=%d\n",bound);
 			ShowError("script_getitembound2: Not a correct bound type! Type=%d\n",bound);
 			return SCRIPT_CMD_FAILURE;
 			return SCRIPT_CMD_FAILURE;
 		}
 		}
-		script_mapid2sd(12,sd);
+		if (command[strlen(command)-1] == '3') {
+			offset = 12;
+			aid_pos = 15;
+		}
+		script_mapid2sd(aid_pos,sd);
 	} else {
 	} else {
-		script_mapid2sd(11,sd);
+		int aid_pos = 11;
+		if (strcmpi(command,"getitem3") == 0) {
+			offset = 11;
+			aid_pos = 14;
+		} 
+		script_mapid2sd(aid_pos,sd);
 	}
 	}
 
 
 	if( sd == NULL ) // no target
 	if( sd == NULL ) // no target
@@ -7156,6 +7264,12 @@ BUILDIN_FUNC(getitem2)
 		item_tmp.card[3] = c4;
 		item_tmp.card[3] = c4;
 		item_tmp.bound = bound;
 		item_tmp.bound = bound;
 
 
+		if (offset != 0) {
+			int res = script_getitem_randomoption(st, &item_tmp, command, offset);
+			if (res == SCRIPT_CMD_FAILURE)
+				return SCRIPT_CMD_FAILURE;
+		}
+
 		//Check if it's stackable.
 		//Check if it's stackable.
 		if (!itemdb_isstackable2(item_data))
 		if (!itemdb_isstackable2(item_data))
 			get_count = 1;
 			get_count = 1;
@@ -7239,10 +7353,14 @@ BUILDIN_FUNC(rentitem) {
 	return SCRIPT_CMD_SUCCESS;
 	return SCRIPT_CMD_SUCCESS;
 }
 }
 
 
-/** Gives rental item to player with advanced option
-* rentitem2 <item id>,<time>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<account_id>};
-* rentitem2 "<item name>",<time>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<account_id>};
-*/
+/**
+ * Gives rental item to player with advanced option
+ * rentitem2 <item id>,<time>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<account_id>};
+ * rentitem2 "<item name>",<time>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<account_id>};
+ *
+ * rentitem3 <item id>,<time>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>,<RandomIDArray>,<RandomValueArray>,<RandomParamArray>{,<account_id>};
+ * rentitem3 "<item name>",<time>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>,<RandomIDArray>,<RandomValueArray>,<RandomParamArray>{,<account_id>};
+ */
 BUILDIN_FUNC(rentitem2) {
 BUILDIN_FUNC(rentitem2) {
 	struct map_session_data *sd;
 	struct map_session_data *sd;
 	struct script_data *data;
 	struct script_data *data;
@@ -7252,11 +7370,15 @@ BUILDIN_FUNC(rentitem2) {
 	unsigned short nameid = 0;
 	unsigned short nameid = 0;
 	unsigned char flag = 0;
 	unsigned char flag = 0;
 	int iden,ref,attr,c1,c2,c3,c4;
 	int iden,ref,attr,c1,c2,c3,c4;
+	const char *funcname = script_getfuncname(st);
 
 
 	data = script_getdata(st,2);
 	data = script_getdata(st,2);
 	get_val(st,data);
 	get_val(st,data);
 
 
-	if (!script_accid2sd(11,sd))
+	if (funcname[strlen(funcname)-1] == '3') {
+		if (!script_accid2sd(14,sd))
+			return SCRIPT_CMD_FAILURE;
+	} else if (!script_accid2sd(11,sd))
 		return SCRIPT_CMD_FAILURE;
 		return SCRIPT_CMD_FAILURE;
 
 
 	if( data_isstring(data) ) {
 	if( data_isstring(data) ) {
@@ -7313,6 +7435,12 @@ BUILDIN_FUNC(rentitem2) {
 	it.card[3] = (short)c4;
 	it.card[3] = (short)c4;
 	it.expire_time = (unsigned int)(time(NULL) + seconds);
 	it.expire_time = (unsigned int)(time(NULL) + seconds);
 
 
+	if (funcname[strlen(funcname)-1] == '3') {
+		int res = script_getitem_randomoption(st, &it, funcname, 11);
+		if (res != SCRIPT_CMD_SUCCESS)
+			return res;
+	}
+
 	if( (flag = pc_additem(sd, &it, 1, LOG_TYPE_SCRIPT)) ) {
 	if( (flag = pc_additem(sd, &it, 1, LOG_TYPE_SCRIPT)) ) {
 		clif_additem(sd, 0, 0, flag);
 		clif_additem(sd, 0, 0, flag);
 		return SCRIPT_CMD_FAILURE;
 		return SCRIPT_CMD_FAILURE;
@@ -7464,9 +7592,12 @@ BUILDIN_FUNC(makeitem) {
 }
 }
 
 
 /**
 /**
-* makeitem2 <item id>,<amount>,"<map name>",<X>,<Y>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>;
-* makeitem2 "<item name>",<amount>,"<map name>",<X>,<Y>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>;
-*/
+ * makeitem2 <item id>,<amount>,"<map name>",<X>,<Y>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>;
+ * makeitem2 "<item name>",<amount>,"<map name>",<X>,<Y>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>;
+ *
+ * makeitem3 <item id>,<amount>,"<map name>",<X>,<Y>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>,<RandomIDArray>,<RandomValueArray>,<RandomParamArray>;
+ * makeitem3 "<item name>",<amount>,"<map name>",<X>,<Y>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>,<RandomIDArray>,<RandomValueArray>,<RandomParamArray>;
+ */
 BUILDIN_FUNC(makeitem2) {
 BUILDIN_FUNC(makeitem2) {
 	uint16 nameid, amount, x, y;
 	uint16 nameid, amount, x, y;
 	const char *mapname;
 	const char *mapname;
@@ -7474,7 +7605,8 @@ BUILDIN_FUNC(makeitem2) {
 	struct item item_tmp;
 	struct item item_tmp;
 	struct script_data *data;
 	struct script_data *data;
 	struct item_data *id;
 	struct item_data *id;
-	
+	const char *funcname = script_getfuncname(st);
+
 	data = script_getdata(st,2);
 	data = script_getdata(st,2);
 	get_val(st,data);
 	get_val(st,data);
 	if( data_isstring(data) ){
 	if( data_isstring(data) ){
@@ -7531,6 +7663,12 @@ BUILDIN_FUNC(makeitem2) {
 		item_tmp.card[2] = script_getnum(st,12);
 		item_tmp.card[2] = script_getnum(st,12);
 		item_tmp.card[3] = script_getnum(st,13);
 		item_tmp.card[3] = script_getnum(st,13);
 
 
+		if (funcname[strlen(funcname)-1] == '3') {
+			int res = script_getitem_randomoption(st, &item_tmp, funcname, 14);
+			if (res != SCRIPT_CMD_SUCCESS)
+				return res;
+		}
+
 		map_addflooritem(&item_tmp,amount,m,x,y,0,0,0,4,0);
 		map_addflooritem(&item_tmp,amount,m,x,y,0,0,0,4,0);
 	}
 	}
 	else
 	else
@@ -7602,9 +7740,12 @@ static void buildin_delitem_delete(struct map_session_data* sd, int idx, int* am
 /// Searches for item(s) and checks, if there is enough of them.
 /// Searches for item(s) and checks, if there is enough of them.
 /// Used by delitem and delitem2
 /// Used by delitem and delitem2
 /// Relies on all input data being already fully valid.
 /// Relies on all input data being already fully valid.
-/// @param exact_match will also match item attributes and cards, not just name id
+/// @param exact_match will also match item by specified attributes
+///   0x0: Only item id
+///   0x1: identify, attributes, cards
+///   0x2: random option
 /// @return true when all items could be deleted, false when there were not enough items to delete
 /// @return true when all items could be deleted, false when there were not enough items to delete
-static bool buildin_delitem_search(struct map_session_data* sd, struct item* it, bool exact_match, uint8 loc)
+static bool buildin_delitem_search(struct map_session_data* sd, struct item* it, uint8 exact_match, uint8 loc)
 {
 {
 	bool delete_items = false;
 	bool delete_items = false;
 	int i, amount, size;
 	int i, amount, size;
@@ -7668,10 +7809,19 @@ static bool buildin_delitem_search(struct map_session_data* sd, struct item* it,
 
 
 			if( exact_match )
 			if( exact_match )
 			{
 			{
-				if( itm->identify != it->identify || itm->attribute != it->attribute || memcmp(itm->card, it->card, sizeof(itm->card)) )
+				if( (exact_match&0x1) && ( itm->identify != it->identify || itm->attribute != it->attribute || memcmp(itm->card, it->card, sizeof(itm->card)) ) )
 				{// not matching exact attributes
 				{// not matching exact attributes
 					continue;
 					continue;
 				}
 				}
+				if (exact_match&0x2) {
+					uint8 j;
+					for (j = 0; j < MAX_ITEM_RDM_OPT; j++) {
+						if (itm->option[j].id != it->option[j].id || itm->option[j].value != it->option[j].value || itm->option[j].param != it->option[j].param)
+							break;
+					}
+					if (j != MAX_ITEM_RDM_OPT)
+						continue;
+				}
 			}
 			}
 			else
 			else
 			{
 			{
@@ -7714,10 +7864,19 @@ static bool buildin_delitem_search(struct map_session_data* sd, struct item* it,
 
 
 			if( exact_match )
 			if( exact_match )
 			{
 			{
-				if( itm->refine != it->refine || itm->identify != it->identify || itm->attribute != it->attribute || memcmp(itm->card, it->card, sizeof(itm->card)) )
+				if( (exact_match&0x1) && ( itm->refine != it->refine || itm->identify != it->identify || itm->attribute != it->attribute || memcmp(itm->card, it->card, sizeof(itm->card)) ) )
 				{// not matching attributes
 				{// not matching attributes
 					continue;
 					continue;
 				}
 				}
+				if (exact_match&0x2) {
+					uint8 j;
+					for (j = 0; j < MAX_ITEM_RDM_OPT; j++) {
+						if (itm->option[j].id != it->option[j].id || itm->option[j].value != it->option[j].value || itm->option[j].param != it->option[j].param)
+							break;
+					}
+					if (j != MAX_ITEM_RDM_OPT)
+						continue;
+				}
 			}
 			}
 
 
 			// count / delete item
 			// count / delete item
@@ -7816,7 +7975,7 @@ BUILDIN_FUNC(delitem)
 	if( it.amount <= 0 )
 	if( it.amount <= 0 )
 		return SCRIPT_CMD_SUCCESS;// nothing to do
 		return SCRIPT_CMD_SUCCESS;// nothing to do
 
 
-	if( buildin_delitem_search(sd, &it, false, loc) )
+	if( buildin_delitem_search(sd, &it, 0, loc) )
 	{// success
 	{// success
 		return SCRIPT_CMD_SUCCESS;
 		return SCRIPT_CMD_SUCCESS;
 	}
 	}
@@ -7838,6 +7997,8 @@ BUILDIN_FUNC(delitem)
 /// storagedelitem2 "<Item name>",<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<account ID>}
 /// storagedelitem2 "<Item name>",<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<account ID>}
 /// guildstoragedelitem2 <item id>,<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<account ID>}
 /// guildstoragedelitem2 <item id>,<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<account ID>}
 /// guildstoragedelitem2 "<Item name>",<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<account ID>}
 /// guildstoragedelitem2 "<Item name>",<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<account ID>}
+/// delitem3 <item id>,<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>,<RandomIDArray>,<RandomValueArray>,<RandomParamArray>{,<account ID>};
+/// delitem3 "<item name>",<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>,<RandomIDArray>,<RandomValueArray>,<RandomParamArray>{,<account ID>};
 BUILDIN_FUNC(delitem2)
 BUILDIN_FUNC(delitem2)
 {
 {
 	TBL_PC *sd;
 	TBL_PC *sd;
@@ -7845,6 +8006,8 @@ BUILDIN_FUNC(delitem2)
 	struct script_data *data;
 	struct script_data *data;
 	uint8 loc = 0;
 	uint8 loc = 0;
 	char* command = (char*)script_getfuncname(st);
 	char* command = (char*)script_getfuncname(st);
+	int aid_pos = 11;
+	uint8 flag = 0x1;
 
 
 	if(!strncmp(command, "cart", 4))
 	if(!strncmp(command, "cart", 4))
 		loc = TABLE_CART;
 		loc = TABLE_CART;
@@ -7853,7 +8016,10 @@ BUILDIN_FUNC(delitem2)
 	else if(!strncmp(command, "guildstorage", 12))
 	else if(!strncmp(command, "guildstorage", 12))
 		loc = TABLE_GUILD_STORAGE;
 		loc = TABLE_GUILD_STORAGE;
 
 
-	if( !script_accid2sd(11,sd) ){
+	if (command[strlen(command)-1] == '3')
+		aid_pos = 14;
+
+	if( !script_accid2sd(aid_pos,sd) ){
 		// In any case cancel script execution
 		// In any case cancel script execution
 		st->state = END;
 		st->state = END;
 		return SCRIPT_CMD_SUCCESS;
 		return SCRIPT_CMD_SUCCESS;
@@ -7873,6 +8039,8 @@ BUILDIN_FUNC(delitem2)
 		}
 		}
 	}
 	}
 
 
+	memset(&it, 0, sizeof(it));
+
 	data = script_getdata(st,2);
 	data = script_getdata(st,2);
 	get_val(st,data);
 	get_val(st,data);
 	if( data_isstring(data) )
 	if( data_isstring(data) )
@@ -7907,10 +8075,17 @@ BUILDIN_FUNC(delitem2)
 	it.card[2]=(short)script_getnum(st,9);
 	it.card[2]=(short)script_getnum(st,9);
 	it.card[3]=(short)script_getnum(st,10);
 	it.card[3]=(short)script_getnum(st,10);
 
 
+	if (command[strlen(command)-1] == '3') {
+		int res = script_getitem_randomoption(st, &it, command, 11);
+		if (res != SCRIPT_CMD_SUCCESS)
+			return SCRIPT_CMD_FAILURE;
+		flag |= 0x2;
+	}
+
 	if( it.amount <= 0 )
 	if( it.amount <= 0 )
 		return SCRIPT_CMD_SUCCESS;// nothing to do
 		return SCRIPT_CMD_SUCCESS;// nothing to do
 
 
-	if( buildin_delitem_search(sd, &it, true, loc) )
+	if( buildin_delitem_search(sd, &it, flag, loc) )
 	{// success
 	{// success
 		return SCRIPT_CMD_SUCCESS;
 		return SCRIPT_CMD_SUCCESS;
 	}
 	}
@@ -23459,6 +23634,14 @@ struct script_function buildin_func[] = {
 	BUILDIN_DEF(channel_kick,"sv"),
 	BUILDIN_DEF(channel_kick,"sv"),
 	BUILDIN_DEF(channel_delete,"s"),
 	BUILDIN_DEF(channel_delete,"s"),
 
 
+	// Item Random Option Extension [Cydh]
+	BUILDIN_DEF2(getitem2,"getitem3","viiiiiiiirrr?"),
+	BUILDIN_DEF2(getitem2,"getitembound3","viiiiiiiiirrr?"),
+	BUILDIN_DEF2(rentitem2,"rentitem3","viiiiiiiirrr?"),
+	BUILDIN_DEF2(makeitem2,"makeitem3","visiiiiiiiiirrr"),
+	BUILDIN_DEF2(delitem2,"delitem3","viiiiiiiirrr?"),
+	BUILDIN_DEF2(countitem,"countitem3","viiiiiiirrr?"),
+
 #include "../custom/script_def.inc"
 #include "../custom/script_def.inc"
 
 
 	{NULL,NULL,NULL},
 	{NULL,NULL,NULL},