Jump to content

Replacement for addrid


Tokei

Recommended Posts


  • Group:  Members
  • Topic Count:  16
  • Topics Per Day:  0.00
  • Content Count:  658
  • Reputation:   663
  • Joined:  11/12/12
  • Last Seen:  

Heya,

The following script commands replace addrid and they were initially implemented by Luxuri. The main advantage of these is that they do not attach the players on the current script, allowing an easier code flow. The commands:

foreachinserver "<npc_label>"
foreachinmap "<npc_label>", "<map_name>"
foreachinparty "<npc_label>", <party_id>
foreachinarea "<npc_label>", "<map_name>", <x1>, <y1>, <x2>, <y2>
foreachinshootablerange "<npc_label>", "<map_name>", <x>, <y>, <range>
foreachinguild "<npc_label>", <guild_id>

prontera,155,185,3	script	Test	77,{
	foreachinserver("Test::OnEvent");
	foreachinmap("Test::OnEvent", "prontera");
	foreachinparty("Test::OnEvent", getcharid(1));
	foreachinarea("Test::OnEvent", "this", 153, 182, 159, 177);
	foreachinshootablerange("Test::OnEvent", "this", 153, 182, 2);
	foreachinguild("Test::OnEvent", getcharid(2));
	end;
OnEvent:
	announce "Attached script to " + strcharinfo(0), 0;
	end;
}

 

For example, for making a script that kicks dead players without using OnPCDieEvent, you could use:

prontera,155,185,3	script	Test	77,{
	initnpctimer;
	dispbottom "Kicking dead players.";
	end;
OnTimer1000:
	.kicked = 0;
	foreachinmap("Test::OnKick", "prontera");
	
	if (.kicked > 0) {
		announce .kicked + " player(s) have died!", 0;
	}
	
	initnpctimer;
	end;
OnKick:
	if (HP <= 0) {
		.kicked++;
		getitem 501, 1;
		warp "alberta", 192, 147;
		percentheal 100, 100;
	}
	
	end;
}

 

You can easily make your own foreach methods (for BG, clans, etc). Diff file:

diff --git a/src/map/npc.cpp b/src/map/npc.cpp
index 647a765..c60a5d7 100644
--- a/src/map/npc.cpp
+++ b/src/map/npc.cpp
@@ -2224,6 +2224,20 @@ int npc_unload(struct npc_data* nd, bool single) {
 	return 0;
 }
 
+/// Returns the NPC associated with the specified event label.
+struct npc_data* npc_event_label_nd(const char* labelname)
+{
+	struct event_data* ev = (struct event_data*)strdb_get(ev_db, labelname);
+	return (ev != NULL ? ev->nd : NULL);
+}
+
+/// Returns the bytecode position that the specified event label refers to.
+int npc_event_label_pos(const char* labelname)
+{
+	struct event_data* ev = (struct event_data*)strdb_get(ev_db, labelname);
+	return (ev != NULL ? ev->pos : -1);
+}
+
 //
 // NPC Source Files
 //
diff --git a/src/map/npc.hpp b/src/map/npc.hpp
index d6a9b97..3049651 100644
--- a/src/map/npc.hpp
+++ b/src/map/npc.hpp
@@ -1162,6 +1162,9 @@ bool npc_isnear(struct block_list * bl);
 
 int npc_get_new_npc_id(void);
 
+struct npc_data* npc_event_label_nd(const char* labelname);
+int npc_event_label_pos(const char* labelname);
+
 int npc_addsrcfile(const char* name, bool loadscript);
 void npc_delsrcfile(const char* name);
 int npc_parsesrcfile(const char* filepath, bool runOnInit);
diff --git a/src/map/script.cpp b/src/map/script.cpp
index 180f9ba..5535094 100644
--- a/src/map/script.cpp
+++ b/src/map/script.cpp
@@ -12230,6 +12230,150 @@ BUILDIN_FUNC(isloggedin)
 	return SCRIPT_CMD_SUCCESS;
 }
 
+static int script_foreach_sub(TBL_PC* sd, const char* event)
+{
+	struct npc_data* nd;
+	int pos;
+
+	if ((nd = npc_event_label_nd(event)) == NULL || (pos = npc_event_label_pos(event)) == -1)
+		return 0;
+
+	run_script(nd->u.scr.script, pos, sd->bl.id, nd->bl.id);
+	return 1;
+}
+
+static int script_foreach_sub_va_bl(struct block_list* bl, va_list args) {
+	const char* event = va_arg(args, const char*);
+	return script_foreach_sub((TBL_PC*)bl, event);
+}
+
+static int script_foreach_sub_va_sd(TBL_PC* sd, va_list args) {
+	const char* event = va_arg(args, const char*);
+	return script_foreach_sub(sd, event);
+}
+
+/// foreachinserver "<npc_label>"
+BUILDIN_FUNC(foreachinserver)
+{
+	const char* event = script_getstr(st, 2);
+	map_foreachpc(script_foreach_sub_va_sd, event);
+	return SCRIPT_CMD_SUCCESS;
+}
+
+/// foreachinmap "<npc_label>", "<map_name>"
+BUILDIN_FUNC(foreachinmap)
+{
+	const char* event = script_getstr(st, 2);
+	const char* mapname = script_getstr(st, 3);
+	TBL_NPC* nd = map_id2nd(st->oid);
+	int16 m = (nd && strcmp(mapname, "this") == 0) ? nd->bl.m : map_mapname2mapid(mapname);
+
+	if (m < 0) {
+		ShowWarning("buildin_foreachinmap: Invalid map name '%s'.\n", mapname);
+		return SCRIPT_CMD_SUCCESS;
+	}
+
+	map_foreachinmap(script_foreach_sub_va_bl, m, BL_PC, event);
+	return SCRIPT_CMD_SUCCESS;
+}
+
+/// foreachinparty "<npc_label>", <party_id>
+BUILDIN_FUNC(foreachinparty)
+{
+	const char* event = script_getstr(st, 2);
+	int party_id = script_getnum(st, 3);
+	struct party_data* p;
+	int i;
+
+	if ((p = party_search(party_id)) == NULL) {
+		ShowWarning("buildin_foreachinparty: Party id '%d' doesn't exist or is not loaded yet.\n", party_id);
+		return SCRIPT_CMD_SUCCESS;
+	}
+
+	for (i = 0; i < MAX_PARTY; ++i) {
+		TBL_PC* sd;
+		int char_id = p->party.member[i].char_id;
+
+		if (char_id == 0 || (sd = map_charid2sd(char_id)) == NULL)
+			continue;
+
+		script_foreach_sub(sd, event);
+	}
+
+	return SCRIPT_CMD_SUCCESS;
+}
+
+/// foreachinarea "<npc_label>", "<map_name>", <x1>, <y1>, <x2>, <y2>
+BUILDIN_FUNC(foreachinarea)
+{
+	const char* event = script_getstr(st, 2);
+	const char* mapname = script_getstr(st, 3);
+	int x1 = script_getnum(st, 4);
+	int y1 = script_getnum(st, 5);
+	int x2 = script_getnum(st, 6);
+	int y2 = script_getnum(st, 7);
+	TBL_NPC* nd = map_id2nd(st->oid);
+	int16 m = (nd && strcmp(mapname, "this") == 0) ? nd->bl.m : map_mapname2mapid(mapname);
+
+	if (m < 0) {
+		ShowWarning("buildin_foreachinarea: Invalid map name '%s'.\n", mapname);
+		return SCRIPT_CMD_SUCCESS;
+	}
+
+	map_foreachinarea(script_foreach_sub_va_bl, m, x1, y1, x2, y2, BL_PC, event);
+	return SCRIPT_CMD_SUCCESS;
+}
+
+/// foreachinshootablerange "<npc_label>", "<map_name>", <x>, <y>, <range>
+BUILDIN_FUNC(foreachinshootablerange)
+{
+	const char* event = script_getstr(st, 2);
+	const char* mapname = script_getstr(st, 3);
+	struct block_list bl;
+	int x1 = script_getnum(st, 4);
+	int y1 = script_getnum(st, 5);
+	int range = script_getnum(st, 6);
+	TBL_NPC* nd = map_id2nd(st->oid);
+	int16 m = (nd && strcmp(mapname, "this") == 0) ? nd->bl.m : map_mapname2mapid(mapname);
+
+	if (m < 0) {
+		ShowWarning("buildin_foreachinarea: Invalid map name '%s'.\n", mapname);
+		return SCRIPT_CMD_SUCCESS;
+	}
+
+	memset(&bl, 0, sizeof(struct block_list));
+	bl.m = m;
+	bl.x = x1;
+	bl.y = y1;
+
+	map_foreachinshootrange(script_foreach_sub_va_bl, &bl, range, BL_PC, event);
+	return SCRIPT_CMD_SUCCESS;
+}
+
+/// foreachinguild "<npc_label>", <guild_id>
+BUILDIN_FUNC(foreachinguild)
+{
+	const char* event = script_getstr(st, 2);
+	int guild_id = script_getnum(st, 3);
+	struct guild* g;
+	int i;
+
+	if ((g = guild_search(guild_id)) == NULL) {
+		ShowWarning("buildin_foreachinguild: Guild id '%d' doesn't exist or is not loaded yet.\n", guild_id);
+		return SCRIPT_CMD_SUCCESS;
+	}
+
+	for (i = 0; i < MAX_GUILD; ++i) {
+		TBL_PC* sd;
+
+		if (!(sd = g->member[i].sd))
+			continue;
+		
+		script_foreach_sub(sd, event);
+	}
+
+	return SCRIPT_CMD_SUCCESS;
+}
 
 /*==========================================
  *
@@ -24642,6 +24786,13 @@ struct script_function buildin_func[] = {
 	BUILDIN_DEF2(round, "floor", "i"),
 	BUILDIN_DEF(getequiptradability, "i?"),
 	BUILDIN_DEF(mail, "isss*"),
+
+	BUILDIN_DEF(foreachinserver, "s"),
+	BUILDIN_DEF(foreachinmap, "ss"),
+	BUILDIN_DEF(foreachinparty, "si"),
+	BUILDIN_DEF(foreachinarea, "ssiiii"),
+	BUILDIN_DEF(foreachinshootablerange, "ssiii"),
+	BUILDIN_DEF(foreachinguild, "si"),
 #include "../custom/script_def.inc"
 
 	{NULL,NULL,NULL},

 

foreach.diff

  • Upvote 2
  • Love 1
  • Like 2
Link to comment
Share on other sites


  • Group:  Members
  • Topic Count:  11
  • Topics Per Day:  0.00
  • Content Count:  41
  • Reputation:   13
  • Joined:  03/20/16
  • Last Seen:  

Good

Edited by JohnnyPlayy
Link to comment
Share on other sites


  • Group:  Members
  • Topic Count:  11
  • Topics Per Day:  0.00
  • Content Count:  81
  • Reputation:   14
  • Joined:  11/17/17
  • Last Seen:  

I like the foreach command. I hope rA will implement the foreach command for array.

Link to comment
Share on other sites


  • Group:  Developer
  • Topic Count:  50
  • Topics Per Day:  0.02
  • Content Count:  763
  • Reputation:   227
  • Joined:  02/11/17
  • Last Seen:  

just the thing im looking for thanks for sharing, this can be use in many ways

Link to comment
Share on other sites

  • 6 months later...

  • Group:  Members
  • Topic Count:  11
  • Topics Per Day:  0.00
  • Content Count:  81
  • Reputation:   14
  • Joined:  11/17/17
  • Last Seen:  

Hi @Tokei. My map-server crashed after using these commands. I noticed that the server crashed only when I used the `getitem` command in this script.

-	script	stest	-1,{
OnTest:
	.@labelReward$ = "stest::OnReward";
	foreachinserver(.@labelReward$);
	end;
OnReward:
	getitem 531,1; // Crashed
	dispbottom "test"; // No crashed
	end;
OnInit:
	bindatcmd "test",strnpcinfo(0)+"::OnTest",99,99;
	end;
}

The bug occurred when I updated this PR https://github.com/rathena/rathena/commit/db3267a868c2855da68481c0807f14004c984da7

Here is the dump log:
381951886_42AE454B-9A41-4D76-902C-1E39AAAE0AC7.png.jpg.03a8b475df01da45261a632c81f7ed01.jpg

Please fix it, thanks.

Link to comment
Share on other sites

  • 3 weeks later...

  • Group:  Members
  • Topic Count:  4
  • Topics Per Day:  0.00
  • Content Count:  7
  • Reputation:   0
  • Joined:  09/23/17
  • Last Seen:  

I can't get this to work, here's a simple breakdown of my script:

por_dun,172,285,3	script	Herkemer	832,{

OnPoringDead:

foreachinmap("Herkemer::L_CombatMES", "por_dun");
end;
L_CombatMES:
	//showscript "In combat";
	//dispbottom "test";
	debugmes "testdbmBEGIN";
	end;

}

I have put a few debug messages into the source and it looks like "npc_event_label_nd" and "npc_event_label_pos" always return "NULL"/"0" or "-1". I see the same function "struct event_data* ev = (struct event_data*)strdb_get(ev_db, labelname);" used elsewhere in the sourcecode and presumably it works but I can't for the life of me figure this one out. I am using a modified version of rev ~42000.

Any ideas would be helpful.

 

EDIT: I'm stupid, I have to use "OnCombatMES" not "L_CombatMES" for this type of script

Edited by khalint
Link to comment
Share on other sites

  • 10 months later...

  • Group:  Members
  • Topic Count:  2
  • Topics Per Day:  0.00
  • Content Count:  9
  • Reputation:   0
  • Joined:  10/13/13
  • Last Seen:  

On 1/28/2019 at 2:54 AM, rongmauhong said:

Hi @Tokei. My map-server crashed after using these commands. I noticed that the server crashed only when I used the `getitem` command in this script.


-	script	stest	-1,{
OnTest:
	.@labelReward$ = "stest::OnReward";
	foreachinserver(.@labelReward$);
	end;
OnReward:
	getitem 531,1; // Crashed
	dispbottom "test"; // No crashed
	end;
OnInit:
	bindatcmd "test",strnpcinfo(0)+"::OnTest",99,99;
	end;
}

The bug occurred when I updated this PR https://github.com/rathena/rathena/commit/db3267a868c2855da68481c0807f14004c984da7

Here is the dump log:
381951886_42AE454B-9A41-4D76-902C-1E39AAAE0AC7.png.jpg.03a8b475df01da45261a632c81f7ed01.jpg

Please fix it, thanks.

Hi,

You fixed it? 

Would be great if this release get updated to latest src ?

Link to comment
Share on other sites

  • 11 months later...

  • Group:  Members
  • Topic Count:  1
  • Topics Per Day:  0.00
  • Content Count:  5
  • Reputation:   0
  • Joined:  08/11/20
  • Last Seen:  

i applied the diff file without knowing the consequences if its outdated or not.

Is there a way to fix this?
clvIL9E.png

Link to comment
Share on other sites


  • Group:  Members
  • Topic Count:  9
  • Topics Per Day:  0.00
  • Content Count:  477
  • Reputation:   269
  • Joined:  06/13/17
  • Last Seen:  

@nasaankaalex revert the patch. 

  • Love 1
Link to comment
Share on other sites


  • Group:  Members
  • Topic Count:  1
  • Topics Per Day:  0.00
  • Content Count:  5
  • Reputation:   0
  • Joined:  08/11/20
  • Last Seen:  

@Haruka Mayumi im just currently learning the workaround of git and tortoise svn, and I managed to the add the line of codes of this patch (foreach.diff) without errors(im not 100% sure) by just simply adding them to the source.

Now with my limited knowledge of scripting/codes. Im curious as to what data does this foreach returns?

Im trying to implement/use foreachinarea to heal a group of players centered around the npc(hence im using the foreachinarea) every x amount of seconds. Note that this group of players changes every x seconds. This uses an infinite loop yet I dont know how to implement the foreachinarea inside the infinite loop.

 

Link to comment
Share on other sites


  • Group:  Members
  • Topic Count:  9
  • Topics Per Day:  0.00
  • Content Count:  477
  • Reputation:   269
  • Joined:  06/13/17
  • Last Seen:  

Just now, nasaankaalex said:

Now with my limited knowledge of scripting/codes. Im curious as to what data does this foreach returns?

it doesn't return anything it will just make the players do the NPC Event specified on the foreach..

Just now, nasaankaalex said:

Im trying to implement/use foreachinarea to heal a group of players centered around the npc(hence im using the foreachinarea) every x amount of seconds. Note that this group of players changes every x seconds. This uses an infinite loop yet I dont know how to implement the foreachinarea inside the infinite loop.

You don't actually need this diff since there's getareaunits to get their name or game id's

*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.

then finally use sc_start and specialeffect2 to buff them.

  • Upvote 1
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...