summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/constants.md15
-rw-r--r--doc/script_commands.txt34
-rw-r--r--src/map/script.c100
3 files changed, 149 insertions, 0 deletions
diff --git a/doc/constants.md b/doc/constants.md
index 22d285412..e6bf656d8 100644
--- a/doc/constants.md
+++ b/doc/constants.md
@@ -3758,6 +3758,21 @@
- `BG_AREA_WOS`: 30
- `BG_QUEUE`: 31
+### block_list types (units)
+
+- `BL_PC`: 1
+- `BL_MOB`: 2
+- `BL_PET`: 4
+- `BL_HOM`: 8
+- `BL_MER`: 16
+- `BL_ITEM`: 32
+- `BL_SKILL`: 64
+- `BL_NPC`: 128
+- `BL_CHAT`: 256
+- `BL_ELEM`: 512
+- `BL_CHAR`: 539 (shorthand for `BL_PC|BL_MOB|BL_HOM|BL_MER|BL_ELEM`)
+- `BL_ALL`: 4095
+
### LOOK_ constants, use in setlook/changelook script commands
- `LOOK_BASE`: 0
diff --git a/doc/script_commands.txt b/doc/script_commands.txt
index 581ec182c..e209b0e56 100644
--- a/doc/script_commands.txt
+++ b/doc/script_commands.txt
@@ -3229,6 +3229,40 @@ Notice that NPC objects disabled with disablenpc() will still be located.
---------------------------------------
+*getunits(<type>, <variable>, <limit>, "<map>"{, <x1>, <y1>, <x2>, <y2>})
+
+This function searches a whole map or area for units and adds their GID to
+the provided <variable> array. It filters units by <type> and stops searching
+after <limit> units have been found. Set <limit> to false (0) if you wish to
+disable the limit altogether.
+
+Type is the type of unit to search for:
+
+ BL_PC - Character object
+ BL_MOB - Monster object
+ BL_PET - Pet object
+ BL_HOM - Homunculus object
+ BL_MER - Mercenary object
+ BL_IEM - Item object (item drops)
+ BL_SKILL - Skill object (skill fx & sfx)
+ BL_NPC - NPC object
+ BL_CHAT - Chat object
+ BL_ELEM - Elemental object
+ BL_CHAR - Shorthand for (BL_PC|BL_MOB|BL_HOM|BL_MER|BL_ELEM)
+ BL_ALL - Any kind of object
+
+** Do NOT use UNITTYPE_ constants here, they have different values.
+
+Example:
+
+ .@count = getunits((BL_PC | BL_NPC), .@units, false, "prontera");
+
+The above example would search the map "prontera" for all PC and NPC units and
+add them to the .@units array, while setting .@count to the amount of units
+added to the array (useful in for() loops).
+
+---------------------------------------
+
*getgmlevel()
This function will return the (GM) level of player group the account to
diff --git a/src/map/script.c b/src/map/script.c
index ce740e81b..48596ea22 100644
--- a/src/map/script.c
+++ b/src/map/script.c
@@ -10955,6 +10955,91 @@ BUILDIN(gettimer)
return true;
}
+int buildin_getunits_sub(struct block_list *bl, va_list ap)
+{
+ struct script_state *st = va_arg(ap, struct script_state *);
+ struct map_session_data *sd = va_arg(ap, struct map_session_data *);
+ int32 id = va_arg(ap, int32);
+ uint32 start = va_arg(ap, uint32);
+ uint32 *count = va_arg(ap, uint32 *);
+ uint32 limit = va_arg(ap, uint32);
+ const char *name = va_arg(ap, const char *);
+ struct reg_db *ref = va_arg(ap, struct reg_db *);
+ uint32 index = start + *count;
+
+ if (index >= SCRIPT_MAX_ARRAYSIZE || *count > limit) {
+ return 1;
+ }
+
+ script->set_reg(st, sd, reference_uid(id, index), name,
+ (const void *)h64BPTRSIZE(bl->id), ref);
+
+ (*count)++;
+ return 0;
+}
+
+BUILDIN(getunits)
+{
+ const char *mapname, *name;
+ int16 m, x1, y1, x2, y2;
+ int32 id;
+ uint32 start;
+ struct reg_db *ref;
+ enum bl_type type = script_getnum(st, 2);
+ struct script_data *data = script_getdata(st, 3);
+ uint32 count = 0, limit = script_getnum(st, 4);
+ struct map_session_data *sd = NULL;
+
+ if (!data_isreference(data) || reference_toconstant(data)) {
+ ShowError("script:getunits: second argument must be a variable\n");
+ script->reportdata(data);
+ st->state = END;
+ return false;
+ }
+
+ id = reference_getid(data);
+ start = reference_getindex(data);
+ name = reference_getname(data);
+ ref = reference_getref(data);
+
+ if (not_server_variable(*name)) {
+ sd = script->rid2sd(st);
+ if (sd == NULL) {
+ return true; // player variable but no player attached
+ }
+ }
+
+ if (is_string_variable(name)) {
+ ShowError("script:getunits: second argument must be an integer variable\n");
+ script->reportdata(data);
+ st->state = END;
+ return false;
+ }
+
+ if (limit < 1 || limit > SCRIPT_MAX_ARRAYSIZE) {
+ limit = SCRIPT_MAX_ARRAYSIZE;
+ }
+
+ mapname = script_getstr(st, 5);
+ m = map->mapname2mapid(mapname);
+
+ if (script_hasdata(st, 9)) {
+ x1 = script_getnum(st, 6);
+ y1 = script_getnum(st, 7);
+ x2 = script_getnum(st, 8);
+ y2 = script_getnum(st, 9);
+
+ map->foreachinarea(buildin_getunits_sub, m, x1, y1, x2, y2, type,
+ st, sd, id, start, &count, limit, name, ref);
+ } else {
+ map->foreachinmap(buildin_getunits_sub, m, type,
+ st, sd, id, start, &count, limit, name, ref);
+ }
+
+ script_pushint(st, count);
+ return true;
+}
+
/*==========================================
*------------------------------------------*/
BUILDIN(initnpctimer)
@@ -21210,6 +21295,7 @@ void script_parse_builtin(void) {
BUILDIN_DEF(deltimer,"s?"),
BUILDIN_DEF(addtimercount,"si?"),
BUILDIN_DEF(gettimer,"i??"),
+ BUILDIN_DEF(getunits,"iris????"),
BUILDIN_DEF(initnpctimer,"??"),
BUILDIN_DEF(stopnpctimer,"??"),
BUILDIN_DEF(startnpctimer,"??"),
@@ -21761,6 +21847,20 @@ void script_hardcoded_constants(void)
script->set_constant("NAV_KAFRA_AND_SCROLL", NAV_KAFRA_AND_SCROLL, false, false);
script->set_constant("NAV_ALL", NAV_ALL, false, false);
+ script->constdb_comment("BL types");
+ script->set_constant("BL_PC",BL_PC,false, false);
+ script->set_constant("BL_MOB",BL_MOB,false, false);
+ script->set_constant("BL_PET",BL_PET,false, false);
+ script->set_constant("BL_HOM",BL_HOM,false, false);
+ script->set_constant("BL_MER",BL_MER,false, false);
+ script->set_constant("BL_ITEM",BL_ITEM,false, false);
+ script->set_constant("BL_SKILL",BL_SKILL,false, false);
+ script->set_constant("BL_NPC",BL_NPC,false, false);
+ script->set_constant("BL_CHAT",BL_CHAT,false, false);
+ script->set_constant("BL_ELEM",BL_ELEM,false, false);
+ script->set_constant("BL_CHAR",BL_CHAR,false, false);
+ script->set_constant("BL_ALL",BL_ALL,false, false);
+
script->constdb_comment("Renewal");
#ifdef RENEWAL
script->set_constant("RENEWAL", 1, false, false);