From 7580593b6c5d8bcb63befb0027609255ab255ef6 Mon Sep 17 00:00:00 2001 From: gumi Date: Wed, 29 Mar 2017 14:52:49 -0400 Subject: add getunits() buildin --- doc/constants.md | 15 ++++++++ doc/script_commands.txt | 34 ++++++++++++++++ src/map/script.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 149 insertions(+) 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(, , , ""{, , , , }) + +This function searches a whole map or area for units and adds their GID to +the provided array. It filters units by and stops searching +after units have been found. Set 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); -- cgit v1.2.3-60-g2f50