Przeglądaj źródła

inarray script commands (#3071)

Thanks to @anacondaqq, @Lemongrass3110, @Jeybla, @secretdataz, @aleos89, @Atemo and @hurtsky for reviewing and testing.
Sader Fawall 7 lat temu
rodzic
commit
151c8476af
3 zmienionych plików z 356 dodań i 0 usunięć
  1. 115 0
      doc/sample/inarray.txt
  2. 56 0
      doc/script_commands.txt
  3. 185 0
      src/map/script.cpp

+ 115 - 0
doc/sample/inarray.txt

@@ -0,0 +1,115 @@
+//===== rAthena Script =======================================
+//= Sample: inarray
+//===== By: ==================================================
+//= rAthena Dev Team
+//===== Last Updated: ========================================
+//= 20180424
+//===== Description: ========================================= 
+//= Demonstrates the 'inarray' and 'countinarray' commands.
+//============================================================
+
+prontera,160,190,3	script	inarray sample	847,{
+	switch(select("inarray:countinarray")){
+		case 1:	//inarray command test
+			mes "[inarray Test]";
+			setarray .@array1[0],100,200,300,400,500,600,700;
+			setarray .@array2$[0],"One Hundred","Two Hundred","Three Hundred","Four Hundred","Five Hundred","Six Hundred","Seven Hundred";
+			
+			mes .@array2$[inarray(.@array1,100)];	//return One Hundred
+			mes .@array2$[inarray(.@array1,300)];	//return Three Hundred
+			
+			//mes .@array2$[inarray(.@array1,800)];	//this will return with an error
+				//800 is not an element of the array .@array1
+				
+			mes "" + inarray(.@array1,800);	//this return -1
+				//800 is not an element of the array .@array1
+			
+			close;
+		case 2:	//countinarray command test
+			switch(select("Basic:Advanced")){
+				case 1:
+					mes "[countinarray Basic Test]";
+					setarray .@array$[0],"rathena","ragnarok","poring","script";
+					mes "the array elements: ";
+					for(.@i=0;.@i<getarraysize(.@array$);.@i++)
+						mes .@array$[.@i];
+					
+					input .@element$;
+					clear;
+					
+					//also in this example we are using normal variable instead of an array
+					//arrays are variables but with more than one index
+					//so you can use array or variable
+					
+					//using countinarray command
+					mes "[countinarray Basic Test]";
+					if(countinarray(.@array$[0], .@element$) == 1)
+						mes "we found " + .@element$ + " inside the array";
+					else
+						mes .@element$ + " is not an element of the array";
+					/*
+					without using countinarray command
+					------------------------------------------
+					for(.@i=0;.@i<getarraysize(.@array$);.@i++){
+						if(.@array$[.@i] == .@element$){
+							.@count ++;
+						}
+					}
+					if(.@count == 1)
+						mes "we found " + .@element$ + " inside the array";
+					else
+						mes .@element$ + " is not an element of the array";
+					------------------------------------------
+					*/
+					close;
+					
+				case 2:
+					mes "[countinarray Advanced Test]";
+					setarray .@array[0],50,40,80,90,70,500,60,400,700,1,2,2,2,2;
+					mes "open the script and read to know what's going on";
+					mes " ";
+					
+					//50 and 70 are elements of the array
+					//we make new array that have the values 50 and 70
+					//you will see this all over the sample
+					setarray .@array2[0],50,70;
+					//2 cases true, so the command returns 2
+					mes "searching for 50 and 70";
+					mes "return " + countinarray(.@array[0], .@array2[0]);
+					mes " ";
+					
+					//50 is an element of the array
+					//100 is not an element of the array
+					setarray .@array3[0],50,100;
+					//1 case true, so the command returns 1
+					mes "searching for 50 and 100";
+					mes "return " + countinarray(.@array[0], .@array3[0]);
+					mes " ";
+					
+					//586 and 100 are not elements of the array
+					setarray .@array4[0],586,100;
+					//0 case true, so the command returns 0
+					mes "searching for 586 and 100";
+					mes "return " + countinarray(.@array[0], .@array4[0]);
+					mes " ";
+					
+					//1 and 1 are elements of the array
+					setarray .@array5[0],1,1;
+					//2 cases true, so the command returns 2
+					mes "searching for 1 and 1";
+					mes "return " + countinarray(.@array[0], .@array5[0]);
+					mes " ";
+					
+					//2 is an element of the array, but it's in four indexes
+					//the command will return the number valid cases
+					//so here the command returns 4
+					//this can be used to know the count of an element inside an array
+					.@variable = 2;
+					
+					mes "searching for 2";
+					mes "return " + countinarray(.@array[0], .@variable);
+					
+					close;
+			}
+	}
+}

+ 56 - 0
doc/script_commands.txt

@@ -2260,6 +2260,62 @@ array, shifting all the elements beyond this towards the beginning.
 
 ---------------------------------------
 
+*inarray <array name>,<value>;
+
+This command returns the index of the first matching value found in the array.
+It will return -1 if the value is not found.
+
+	setarray .@array[0], 100, 200, 300, 400, 500, 600, 100;
+	
+	inarray(.@array[0], 200);
+	//return 1 because 200 is in index 1
+	//another way to say it that .@array[1] == 200
+	
+	.@index = inarray(.@array[0], 600);
+	//.@index is now 5 because .@array[5] == 600
+	
+	inarray(.@array[0], 100);
+	//while index 6 is also 100, the command will return the first instance it finds
+	//return 0 because .@array[0] == 100
+
+	inarray(.@array[0], 800);
+	//return -1 because 800 is not an element of the array .@array
+
+For more details, see the sample in 'doc/sample/inarray.txt'.
+
+---------------------------------------
+
+*countinarray <array name>{[<start index>]},<array name>{[<start index>]};
+
+This command will check for matches between the array values and return the number of matches.
+While being optional, if [<start index>] is supplied, the search will begin from the given index value.
+
+	setarray .@array[0], 100, 200, 300, 400, 500, 600;
+	
+	.@variable = 100;
+	if(countinarray(.@array[0], .@variable))
+		mes "The number 100 was found in the array @array";
+	
+	countinarray(.@array[0], .@variable);
+	//return 1 because the number 100 is an element of the array .@array
+	
+	setarray .@array2[0],100,500;
+	countinarray(.@array[0], .@array2[0]);
+	//return 2 because the numbers 100 and 500 are elements of the array .@array
+	
+	setarray .@array3[0],100,700;
+	countinarray(.@array[0], .@array3[0]);
+	//return 1 because the number 100 is an element of the array .@array
+	//but the number 700 is not an element of the array .@array
+
+	//also you can change the position between the arrays in the command
+	if(countinarray(.@array[0], .@array3[0]) == countinarray(.@array3[0], .@array[0]))
+		//This is true
+
+For more details, see the sample in 'doc/sample/inarray.txt'.
+
+---------------------------------------
+
 ======================================
 |2.- Information-retrieving commands.|
 ======================================

+ 185 - 0
src/map/script.cpp

@@ -6659,6 +6659,189 @@ BUILDIN_FUNC(getelementofarray)
 	return SCRIPT_CMD_SUCCESS;
 }
 
+/// Return the index number of the first matching value in an array.
+/// ex: inarray arr,1;
+///
+/// inarray <array variable>,<value>;
+BUILDIN_FUNC(inarray)
+{
+	struct script_data *data;
+	const char* name;
+	int id, i, array_size;
+	struct map_session_data* sd = NULL;
+	struct reg_db *ref = NULL;
+	data = script_getdata(st, 2);
+
+	if (!data_isreference(data))
+	{
+		ShowError("buildin_inarray: not a variable\n");
+		script_reportdata(data);
+		st->state = END;
+		return SCRIPT_CMD_FAILURE;
+	}
+
+	name = reference_getname(data);
+	ref = reference_getref(data);
+
+	if (not_server_variable(*name) && !script_rid2sd(sd))
+		return SCRIPT_CMD_FAILURE;
+
+	array_size = script_array_highest_key(st, sd, name, ref) - 1;
+
+	if (array_size > SCRIPT_MAX_ARRAYSIZE)
+	{
+		ShowError("buildin_inarray: The array is too large.\n");
+		script_reportdata(data);
+		st->state = END;
+		return SCRIPT_CMD_FAILURE;
+	}
+
+	id = reference_getid(data);
+	if (is_string_variable(name))
+	{
+		const char* temp;
+		const char* value;
+		value = script_getstr(st, 3);
+		for (i = 0; i <= array_size; ++i)
+		{
+			temp = (char*)get_val2(st, reference_uid(id, i), ref);
+			script_removetop(st, -1, 0);
+			if (!strcmp(temp, value))
+			{
+				script_pushint(st, i);
+				return SCRIPT_CMD_SUCCESS;
+			}
+			
+		}
+	}
+	else
+	{
+		int temp, value;
+		value = script_getnum(st, 3);
+		for (i = 0; i <= array_size; ++i)
+		{
+			temp = (int32)__64BPRTSIZE(get_val2(st, reference_uid(id, i), ref));
+			script_removetop(st, -1, 0);
+			if (temp == value)
+			{
+				script_pushint(st, i);
+				return SCRIPT_CMD_SUCCESS;
+			}
+			
+		}
+	}
+
+	script_pushint(st, -1);
+	return SCRIPT_CMD_SUCCESS;
+}
+
+/// Return the number of matches in two arrays.
+/// ex: countinarray arr[0],arr1[0];
+///
+/// countinarray <array variable>,<array variable>;
+BUILDIN_FUNC(countinarray)
+{
+	struct script_data *data1 , *data2;
+	const char* name1;
+	const char* name2;
+	int id1, id2, i, j, array_size1, array_size2, case_count = 0;
+	struct map_session_data* sd = NULL;
+	struct reg_db *ref1 = NULL, *ref2 = NULL;
+	data1 = script_getdata(st, 2);
+	data2 = script_getdata(st, 3);
+
+	if (!data_isreference(data1) || !data_isreference(data2))
+	{
+		ShowError("buildin_countinarray: not a variable\n");
+		script_reportdata(data1);
+		script_reportdata(data2);
+		st->state = END;
+		return SCRIPT_CMD_FAILURE;
+	}
+
+	name1 = reference_getname(data1);
+	name2 = reference_getname(data2);
+	ref1 = reference_getref(data1);
+	ref2 = reference_getref(data2);
+
+	if (not_server_variable(*name1) && not_server_variable(*name2) && !script_rid2sd(sd))
+		return SCRIPT_CMD_FAILURE;
+
+	array_size1 = script_array_highest_key(st, sd, name1, ref1) - 1;
+	array_size2 = script_array_highest_key(st, sd, name2, ref2) - 1;
+
+	if (array_size1 > SCRIPT_MAX_ARRAYSIZE || array_size2 > SCRIPT_MAX_ARRAYSIZE)
+	{
+		ShowError("buildin_countinarray: The array is too large.\n");
+		script_reportdata(data1);
+		script_reportdata(data2);
+		st->state = END;
+		return SCRIPT_CMD_FAILURE;
+	}
+
+	i = reference_getindex(data1);
+	j = reference_getindex(data2);
+	if (array_size1 < i || array_size2 < j)
+	{	//To prevent unintended behavior
+		ShowError("buildin_countinarray: The given index of the array is higher than the array size.\n");
+		script_reportdata(data1);
+		script_reportdata(data2);
+		st->state = END;
+		return SCRIPT_CMD_FAILURE;
+	}
+
+	id1 = reference_getid(data1);
+	id2 = reference_getid(data2);
+	if (is_string_variable(name1) && is_string_variable(name2))
+	{
+		const char* temp1;
+		const char* temp2;
+		for (; i <= array_size1; ++i)
+		{
+			temp1 = (char*)get_val2(st, reference_uid(id1, i), ref1);
+			for (j = reference_getindex(data2); j <= array_size2; j++)
+			{
+				temp2 = (char*)get_val2(st, reference_uid(id2, j), ref2);
+				if (!strcmp(temp1, temp2))
+				{
+					case_count++;
+				}
+				script_removetop(st, -1, 0);
+			}
+			script_removetop(st, -1, 0);
+		}
+	}
+	else if (!is_string_variable(name1) && !is_string_variable(name2))
+	{
+		int temp1, temp2;
+		for (; i <= array_size1; ++i)
+		{
+			temp1 = (int32)__64BPRTSIZE(get_val2(st, reference_uid(id1, i), ref1));
+			for (j = reference_getindex(data2); j <= array_size2; j++)
+			{
+				temp2 = (int32)__64BPRTSIZE(get_val2(st, reference_uid(id2, j), ref2));
+				if (temp1 == temp2)
+				{
+					case_count++;
+				}
+				script_removetop(st, -1, 0);
+			}
+			script_removetop(st, -1, 0);
+		}
+	}
+	else
+	{
+		ShowError("buildin_countinarray: Arrays does not match , You can't compare int array to string array.\n");
+		script_reportdata(data1);
+		script_reportdata(data2);
+		st->state = END;
+		return SCRIPT_CMD_FAILURE;
+	}
+
+	script_pushint(st, case_count);
+	return SCRIPT_CMD_SUCCESS;
+}
+
 /////////////////////////////////////////////////////////////////////
 /// ...
 ///
@@ -24141,6 +24324,8 @@ struct script_function buildin_func[] = {
 	BUILDIN_DEF(getarraysize,"r"),
 	BUILDIN_DEF(deletearray,"r?"),
 	BUILDIN_DEF(getelementofarray,"ri"),
+	BUILDIN_DEF(inarray,"rv"),
+	BUILDIN_DEF(countinarray,"rr"),
 	BUILDIN_DEF(getitem,"vi?"),
 	BUILDIN_DEF(rentitem,"vi?"),
 	BUILDIN_DEF(rentitem2,"viiiiiiii?"),