Browse Source

Added script command getunits (#3389)

* Closes #3159.
* Adds script commands getunits, getmapunits, and getareaunits.
* Replacement for script commands getusers, getmapusers, getareausers. (In a future commit)
Thanks to @sader1992, @Atemo, and @anacondaqq!
Sader Fawall 6 years ago
parent
commit
10e7035beb
4 changed files with 204 additions and 1 deletions
  1. 51 0
      doc/sample/npc_test_getunits.txt
  2. 65 1
      doc/script_commands.txt
  3. 87 0
      src/map/script.cpp
  4. 1 0
      src/map/script_constants.hpp

+ 51 - 0
doc/sample/npc_test_getunits.txt

@@ -0,0 +1,51 @@
+//===== rAthena Script =======================================
+//= Sample: getunits Test
+//===== By: ==================================================
+//= rAthena Dev Team
+//===== Last Updated: ========================================
+//= 20180831
+//===== Description: ========================================= 
+//= An example of getunits command script
+//============================================================
+prontera,145,177,0	script	getunits Test	857,{
+	mes "server information option will take a while if there is large amount of objects";
+	switch(select("server information:map information")){
+		case 1:
+			mes "server information";
+			mes getunits(BL_PC,.@Character$[0]) + " Character Online.";
+			mes getunits(BL_MOB,.@Monster$[0]) + " Monster.";
+			mes getunits(BL_PET,.@Pet$[0]) + " Pet.";
+			mes getunits(BL_HOM,.@Homunculus$[0]) + " Homunculus.";
+			mes getunits(BL_MER,.@Mercenary$[0]) + " Mercenary.";
+			mes getunits(BL_NPC,.@NPC$[0]) + " NPC.";
+			break;
+		case 2:
+			clear;
+			mes "input the map name.";
+			input .@input$;
+			clear;
+			mes "map information : " + .@input$;
+			mes getmapunits(BL_PC,.@input$,.@Character$[0]) + " Character Online.";
+			mes getmapunits(BL_MOB,.@input$,.@Monster$[0]) + " Monster.";
+			mes getmapunits(BL_PET,.@input$,.@Pet$[0]) + " Pet.";
+			mes getmapunits(BL_HOM,.@input$,.@Homunculus$[0]) + " Homunculus.";
+			mes getmapunits(BL_MER,.@input$,.@Mercenary$[0]) + " Mercenary.";
+			mes getmapunits(BL_NPC,.@input$,.@NPC$[0]) + " NPC.";
+	}
+	mes "select for more info";
+	setarray .@list$,"Character","Monster","Pet","Homunculus","Mercenary","NPC";
+	.@s = select(implode(.@list$,":")) -1;
+	clear;
+	copyarray .@name$[0], getd(".@" + .@list$[.@s] + "$"), getarraysize(getd(".@" + .@list$[.@s] + "$"));
+	mes "count : " + getarraysize(.@name$);
+	freeloop(1);
+	for(.@i=0;.@i<getarraysize(.@name$);.@i++){
+		mes (.@i+1) + " - " + .@name$[.@i];
+		if((.@i + 1) == 100){
+			mes "and more ...";
+			break;
+		}
+	}
+	freeloop(0);
+end;
+}

+ 65 - 1
doc/script_commands.txt

@@ -3,7 +3,7 @@
 //===== By:==================================================
 //===== By:==================================================
 //= rAthena Dev Team
 //= rAthena Dev Team
 //===== Last Updated:========================================
 //===== Last Updated:========================================
-//= 20171011
+//= 20180831
 //===== Description:=========================================
 //===== Description:=========================================
 //= A reference manual for the rAthena scripting language.
 //= A reference manual for the rAthena scripting language.
 //= Commands are sorted depending on their functionality.
 //= Commands are sorted depending on their functionality.
@@ -3206,6 +3206,70 @@ within the specified area - an x1/y1-x2/y2 square on the specified map.
 This is useful for maps that are split into many buildings, such as all the
 This is useful for maps that are split into many buildings, such as all the
 "*_in" maps, due to all the shops and houses.
 "*_in" maps, due to all the shops and houses.
 
 
+---------------------------------------
+
+*getunits(<type>{,<array_variable>[<first value>]})
+*getmapunits(<type>,<"map name">{,<array_variable>[<first value>]})
+*getareaunits(<type>,<"map name">,<x1>,<y1>,<x2>,<y2>{,<array_variable>[<first value>]})
+
+The 'getunits' command will return the number of <type> objects active on the server.
+
+The 'getmapunits' command will return the number of <type> objects active on the
+specified <"map name">.
+
+The 'getareaunits' command will return the number of <type> objects actively located
+within the specified area where <x1>, <y1>, <x2>, <y2> form the area.
+
+Type is the type of object to search for:
+
+	BL_PC   - Character objects
+	BL_MOB  - Monster objects
+	BL_PET  - Pet objects
+	BL_HOM  - Homunculus objects
+	BL_MER  - Mercenary objects
+	BL_NPC  - NPC objects
+	BL_ELEM - Elemental objects
+
+If <array_variable> is provided:
+	- An int variable will return the list of GID.
+	- A string variable will return the list of names.
+
+Example 1:
+	// getting the players count and building a string array of the names.
+	.@num = getunits(BL_PC,.@array$[0]);
+
+	mes "the number of Users Connected to the server is " + .@num + " .";
+	mes "list of Players names :";
+	freeloop(1);	// for if the list was too big.
+	for(.@i=0;.@i<getarraysize(.@array$);.@i++)
+		mes (.@i + 1) + " " + .@array$[.@i];
+	freeloop(0);
+	end;
+
+Example 2:
+	// getting the npc count in Prontera and building a string array of the names.
+	.@num = getmapunits(BL_NPC,"prontera",.@array$[0]);
+
+	mes "the number of NPCs in Prontera is " + .@num + " .";
+	mes "list of NPCs name :";
+	freeloop(1);	// for if the list was too big.
+	for(.@i=0;.@i<getarraysize(.@array$);.@i++)
+		mes (.@i + 1) + " " + .@array$[.@i];
+	freeloop(0);
+	end;
+
+Example 3:
+	// getting the monster count in Prontera with specific coordinates and building a int array of the GIDs.
+	.@num = getareaunits(BL_MOB,"prontera",154,186,159,182,.@array[0]);
+
+	mes "the number of Monsters in Prontera in that Coordinates is " + .@num + " .";
+	mes "list of Monsters GID :";
+	freeloop(1);	// for if the list was too big.
+	for(.@i=0;.@i<getarraysize(.@array);.@i++)
+		mes (.@i + 1) + " " + .@array[.@i];
+	freeloop(0);
+	end;
+
 ---------------------------------------
 ---------------------------------------
 \\
 \\
 2,2.- Guild-related commands
 2,2.- Guild-related commands

+ 87 - 0
src/map/script.cpp

@@ -11059,6 +11059,90 @@ BUILDIN_FUNC(getareausers)
 	return SCRIPT_CMD_SUCCESS;
 	return SCRIPT_CMD_SUCCESS;
 }
 }
 
 
+/*==========================================
+ * getunits(<type>{,<array_variable>[<first value>]})
+ * getmapunits(<type>,<"map name">{,<array_variable>[<first value>]})
+ * getareaunits(<type>,<"map name">,<x1>,<y1>,<x2>,<y2>{,<array_variable>[<first value>]})
+ *------------------------------------------*/
+BUILDIN_FUNC(getunits)
+{
+	struct block_list *bl = NULL;
+	struct map_session_data *sd = NULL;
+	struct script_data *data = NULL;
+	char *command = (char *)script_getfuncname(st);
+	const char *str;
+	const char *name;
+	int type = script_getnum(st, 2);
+	int size = 0;
+	int32 idx, id;
+	int16 m = 0, x0 = 0, y0 = 0, x1 = 0, y1 = 0;
+	struct s_mapiterator *iter = mapit_alloc(MAPIT_NORMAL, bl_type(type));
+
+	if (!strcmp(command, "getmapunits"))
+	{
+		str = script_getstr(st, 3);
+		if ((m = map_mapname2mapid(str)) < 0) {
+			script_pushint(st, -1);
+			st->state = END;
+			ShowWarning("buildin_%s: Unknown map '%s'.\n", command, str);
+			return SCRIPT_CMD_FAILURE;
+		}
+		if (script_hasdata(st, 4))
+			data = script_getdata(st, 4);
+	}
+	else if (!strcmp(command, "getareaunits"))
+	{
+		str = script_getstr(st, 3);
+		if ((m = map_mapname2mapid(str)) < 0) {
+			script_pushint(st, -1);
+			st->state = END;
+			ShowWarning("buildin_%s: Unknown map '%s'.\n", command, str);
+			return SCRIPT_CMD_FAILURE;
+		}
+		x0 = script_getnum(st, 4);
+		y0 = script_getnum(st, 5);
+		x1 = script_getnum(st, 6);
+		y1 = script_getnum(st, 7);
+
+		if (script_hasdata(st, 8))
+			data = script_getdata(st, 8);
+	}
+	else
+	{
+		if (script_hasdata(st, 3))
+			data = script_getdata(st, 3);
+	}
+
+	if (data)
+	{
+		if (!data_isreference(data))
+		{
+			ShowError("buildin_%s: not a variable\n", command);
+			script_reportdata(data);
+			st->state = END;
+			return SCRIPT_CMD_FAILURE;
+		}
+		id = reference_getid(data);
+		idx = reference_getindex(data);
+		name = reference_getname(data);
+	}
+
+	for (bl = (struct block_list*)mapit_first(iter); mapit_exists(iter); bl = (struct block_list*)mapit_next(iter))
+	{
+		if (!m || (m == bl->m && !x0 && !y0 && !x1 && !y1) || (bl->m == m && (bl->x >= x0 && bl->y <= y0) && (bl->x <= x1 && bl->y >= y1)))
+		{
+			if (data)
+				set_reg(st, sd, reference_uid(id, idx + size), name, (is_string_variable(name) ? (void*)status_get_name(bl) : (void*)__64BPRTSIZE(bl->id)), reference_getref(data));
+			size++;
+		}
+	}
+
+	mapit_free(iter);
+
+	script_pushint(st, size);
+	return SCRIPT_CMD_SUCCESS;
+}
+
 /*==========================================
 /*==========================================
  *------------------------------------------*/
  *------------------------------------------*/
 static int buildin_getareadropitem_sub(struct block_list *bl,va_list ap)
 static int buildin_getareadropitem_sub(struct block_list *bl,va_list ap)
@@ -24029,6 +24113,9 @@ struct script_function buildin_func[] = {
 	BUILDIN_DEF(getmapguildusers,"si"),
 	BUILDIN_DEF(getmapguildusers,"si"),
 	BUILDIN_DEF(getmapusers,"s"),
 	BUILDIN_DEF(getmapusers,"s"),
 	BUILDIN_DEF(getareausers,"siiii"),
 	BUILDIN_DEF(getareausers,"siiii"),
+	BUILDIN_DEF(getunits, "i?"),
+	BUILDIN_DEF2(getunits, "getmapunits", "is?"),
+	BUILDIN_DEF2(getunits, "getareaunits", "isiiii?"),
 	BUILDIN_DEF(getareadropitem,"siiiiv"),
 	BUILDIN_DEF(getareadropitem,"siiiiv"),
 	BUILDIN_DEF(enablenpc,"s"),
 	BUILDIN_DEF(enablenpc,"s"),
 	BUILDIN_DEF(disablenpc,"s"),
 	BUILDIN_DEF(disablenpc,"s"),

+ 1 - 0
src/map/script_constants.hpp

@@ -7295,6 +7295,7 @@
 	export_constant(BL_PET);
 	export_constant(BL_PET);
 	export_constant(BL_HOM);
 	export_constant(BL_HOM);
 	export_constant(BL_MER);
 	export_constant(BL_MER);
+	export_constant(BL_NPC);
 	export_constant(BL_ELEM);
 	export_constant(BL_ELEM);
 
 
 	/* skill damage mapflag types */
 	/* skill damage mapflag types */