• 0
Seravy

How to find nearest enemy/obtain a list of units on the same map, etc...

Question

I'm trying to implement a @ command that makes the character have limited autopilot capabilities like, buff or attack the nearest thing. I'm playing the game alone on my server and would like to use multiple characters...but there is a limit to how many I can play actively at a time, and it's not very fun to do it that way. I tried using a bot but it didn't work but then I realized "hey I can just make the server do it for me, even better and I get to code all the AI". Yes, I'm crazy enough to play RO as a single player game, but even then, I'm going to need a party to fight the stronger enemies  :)

So I was able to add the command (and tested it actually works by outputting a message), made it get stored in a variable : sd->autopilotmode = 1;, added a new timer to unit.cpp, got as far as


// @autopilot timer
int unit_autopilot_timer(int tid, unsigned int tick, int id, intptr_t data)
{
	struct block_list *bl;
	struct unit_data *ud;
	int target_id;

	bl = map_id2bl(id);

	if (!bl || bl->prev == NULL)
		return 0;

	ud = unit_bl2ud(bl);

	if (!ud)
		return 0;


	if (bl->type != BL_PC) // Players are handled by map_quit
	{
		ShowError("Nonplayer set to autopilot!");
		return 0;
	}

	struct map_session_data *sd = (struct map_session_data*)bl;

	if (sd->status.autopilotmode==0) {

		return 0;
	}

	// Tanking mode is set
	if (sd->status.autopilotmode == 1) 	{



	}

 

although this is mostly guessing so far, but here I'm stuck. How do I find the nearest enemy (or party member, for buffs) to target? Tried searching for other code parts that target monster attacks and similar but it looks way too complicated. It's hard without even knowing what each structure is for. Didn't see any Findnearest kind of functions anywhere either. In fact I don't even know how to access a list of units on the same map. I think I'm going to need to call "clif_parse_ActionRequest_sub(struct map_session_data *sd, int action_type, int target_id, unsigned int tick)" to execute the action but first I need to somehow find a target.

Share this post


Link to post
Share on other sites

Recommended Posts

  • 0
12 minutes ago, Seravy said:

How do I find the nearest enemy (or party member, for buffs) to target? Tried searching for other code parts that target monster attacks and similar but it looks way too complicated.

map_foreachinrange
https://github.com/rathena/rathena/blob/master/src/map/map.hpp#L1005

13 minutes ago, Seravy said:

In fact I don't even know how to access a list of units on the same map.

map_foreachinmap

check my getmemberaid plugin
http://herc.ws/board/topic/4593-getmemberaid-checkmes/

or check the *getunits script command

and actually this can be written entirely with just script commands without touching source code

well up to you want to implement in C language or rathena script language ...

Share this post


Link to post
Share on other sites
  • 0

Thank you!

I was able to make the timer work, and used map_foreachinmap to output the names of the mobs. So next is to figure out how to find the closest one valid for a normal attack. Is there a function I can call to check the distance between the two units? I assume unit_can_attack will work for checking target validity.

Share this post


Link to post
Share on other sites
  • 0

3 things done wrong here

1 hour ago, Seravy said:

used map_foreachinmap to output the names of the mobs. So next is to figure out how to find the closest one valid for a normal attack.

no, should use map_foreachinrange
because the server's unitmove command can only move 14 space away, and 14 space is area_size
https://github.com/rathena/rathena/blob/master/conf/battle/client.conf#L40-L41

so if there is no monster in sight, do a random move

 

1 hour ago, Seravy said:

Is there a function I can call to check the distance between the two units?

battle_check_range
https://github.com/rathena/rathena/blob/master/src/map/battle.hpp#L122

 

1 hour ago, Seravy said:

I assume unit_can_attack will work for checking target validity.

wrong, its battle_check_target

Share this post


Link to post
Share on other sites
  • 0

Thank you very much, this has worked! I made it move to the nearest enemy (outside range) when one in range to attack doesn't exist. I used path_search_long(NULL, sd2->bl.m, sd2->bl.x, sd2->bl.y, md->bl.x, md->bl.y, CELL_CHKWALL)) to check what can be reached and it seems to work although it seems to have problems going around obstacles. That's not a problem, I'm going to be playing manually afterall, so I can always just move the stuck character if it happens, although if there is a fix for this that would be of course even better.

So next up is implementing skills slowly one at a time but first, characters not in "tanking" mode should follow the tank to ensure they are in range to use their skills. I'm going to simplify this and make it a rule for myself that it's always the party leader who is doing the tanking, whether I'm playing that character or it's automatic -that makes most sense anyway as the tank determines which way the party will be heading. So now I need a way to get the party leader of a specific player, so I can send them to follow it, then I'll need a way to check if they have a specific skill or not and if yes, use it on the leader's target for attack skills.  I might be able to get that done on my own, but I got stuck on an unexpected thing. Even though I added autopilot: true to my groups.conf file for players, it still only works on the GM account, any idea what could cause that? I have no problems with the other commands so I guess custom ones are different somehow?  I can't test the feature with multiple characters as is although I guess I can make all my accounts admins but I rather not.

Oh, this is case sensitive I bet. I had "ACMD_DEF(Autopilot)," in the def file, that has to be the problem. Indeed, it was. I missed it because it wasn't case sensitive ingame.

More progress : following the leader now works. Only skills are left to tackle now. Thanks for all the help one more time!

Edit : changing the max walk path from 32 to 128 fixed the issue of getting stuck. So moving and normal attacking is fully functional now.

Edited by Seravy
  • Love 1

Share this post


Link to post
Share on other sites
  • 0

seeing as you are newer member here, just want to give you some advice

you should consider selling or releasing this modification to public
you'll be amaze the project you are doing right now, there's some demand for it in the public

Share this post


Link to post
Share on other sites
  • 0

I'll consider that once all skills are complete...which will probably take like a year, there are so many classes. Making the AI actually smart enough to be reliable takes some effort. I might even open a server, I'm changing drops and improving items as well anyway. I know absolutely nothing about making a server for the public though - but if I'm still playing it next year despite being all alone, it probably shows the result was good enough to do that :)

Meanwhile my thief has learned to use her potions, and finally she is not drinking them at max health anymore :D

Share this post


Link to post
Share on other sites
  • 0

I ran into a problem when using skills.

unit_skilluse_id(&sd->bl, closesttarget, TF_POISON, pc_checkskill(sd, TF_POISON));

This works fine, except doesn't seem to check for various requirements. It checks some, but not everything. For example it still tries to use the skill without SP, although fortunately it fails with a no SP message. It also seems to ignore animation time/delay, it spammed Envenom much faster than I normally can. Not sure if it ignores other requirements as there aren't anything else for this particular skill I think.

So what else do I call if I want to execute a skill only if able? I found void clif_parse_UseSkillToId(int fd, struct map_session_data *sd) but that seems to require a packet and there isn't one.

 

Edited by Seravy

Share this post


Link to post
Share on other sites
  • 0

Okay, if I seriously want to make this public, especially if before completion, I probably need to start using Git immediately.

Wait it was the git site that said I need a new browser to register wasn't it. I guess I need to find one that works then, too.

Okay so following the tutorial on this forum, I downloaded https://desktop.github.com/

but the installer closes without an error message or starting to install. So I guess no git for me then.

I don't mind sharing my files, even right now if you want, but you have to separate this feature from my other changes. (Don't think there is much of them yet but probably more and more will happen over time.)

Back to making skills work, if I understand you correctly you are telling me I have to check all the requirements myself, there is no premade "checkallanduseifable" function yet. I guess I can try do that.

Edit : doing that seems to have worked, I just copied all the checks from the procedure used when the player is trying to use their skill manually. Behold, the power of copy-paste! Anyway, Steal and Envenom now works as intended... added Detoxify and pick stone to that. Soon I can start on the Acolyte skills.

Edited by Seravy

Share this post


Link to post
Share on other sites
  • 0

By the way, I'm writing all the code with the assumption that there are no other human players on the server. So it'll need modifications to be suitable for more generic use - at the very least needs checks on all player targeting to only consider own party members and on all monster targeting to avoid KS. Do you still want it anyway?

Share this post


Link to post
Share on other sites
  • 0
16 hours ago, Seravy said:

Okay, if I seriously want to make this public, especially if before completion, I probably need to start using Git immediately.

Wait it was the git site that said I need a new browser to register wasn't it. I guess I need to find one that works then, too.

Okay so following the tutorial on this forum, I downloaded https://desktop.github.com/

but the installer closes without an error message or starting to install. So I guess no git for me then.

there's also someone in discord currently asking me how to setup an offline server properly
so I start a guide How to make your (offline) server in more than 5 hours

 

16 hours ago, Seravy said:

I don't mind sharing my files, even right now if you want, but you have to separate this feature from my other changes. (Don't think there is much of them yet but probably more and more will happen over time.)

once you learned how to use Git, you can create branch in your current project, and only push the commit into your fork repo that anyone can see
then we can download it in the patch file format

.... there's gonna be another topic for it

 

16 hours ago, Seravy said:

Back to making skills work, if I understand you correctly you are telling me I have to check all the requirements myself, there is no premade "checkallanduseifable" function yet. I guess I can try do that.

I am quite sure there's a function call skill_check_condition_castbegin
https://github.com/rathena/rathena/blob/818ff109f3eea1715dc1477795bd1094510a4de4/src/map/skill.hpp#L484

 

15 minutes ago, Seravy said:

By the way, I'm writing all the code with the assumption that there are no other human players on the server. So it'll need modifications to be suitable for more generic use - at the very least needs checks on all player targeting to only consider own party members and on all monster targeting to avoid KS. Do you still want it anyway?

yes please, however you have to learn how to use Git, either TortoiseGit or Sourcetree
I'm more familiar with TortoiseGit, as I can upload the screenshot for it anytime

Share this post


Link to post
Share on other sites
  • 0

Well, I know what git is (although only used it once and it was a nightmare - I had to change a particular file because the project refused to compile otherwise, but wanted to keep that change local and there literally was no way to do that at all.) , but that particular one the site told me to install doesn't seem to install on my computer. So I guess I'll try the one in your guide next, maybe I have better luck with it.

...uh no I'm not installing Visual Studio 2017. Installing 2013 took like 3 full hours. I'm not THAT patient. (I mean, this would probably be like 8+ hours, judging on the installation size)

....system requirements, well, barely passed (minus the SSD) but I really don't think this is a good idea to install on a 10 years old computer.

" if using Windows 7/8, there is a windows update that will crash all the programs in your operating system " oh that sounds like a great thing to happen, yeah definitely not risking it.

What's Hercules? I googled it and it seems to be a different server emulator? Why would I need two of them?

Btw, for skills that don't target anything, like Angelus, which do I call, unit_skilluse_id or unit_skilluse_pos and what do I use for id/position?

Edited by Seravy

Share this post


Link to post
Share on other sites
  • 0

Either way, whether you have a way of using Git on VS 2013 for me or not, it'll take a while so here is my current entire src folder. As far as I remember I only changed like, 3 numbers related to 3 useless first job skills the rest should be this feature.

https://drive.google.com/open?id=1eb9ZXY-7_4I5l95_lbEK-6F3sU9IFQUQ

Currently it has walking, attacking and the skills Envenom, Steal, Detoxify, Cure, Pick Stone, Heal, Inc Agi, Bless, and it seems Angelus is also working. Throw Stone and Cure are still untested.

  • Upvote 1

Share this post


Link to post
Share on other sites
  • 0

...it seems Visual Studio 2013 has Git support in it. I can start using it without installing anything. It's local though, not cloned or forked anything in fact I don't even see such options anywhere, it works on the downloaded files I had - but that should still be good enough to keep various changes I'm making separate I guess.

  • Love 1

Share this post


Link to post
Share on other sites
  • 0

I've finished that How to make your offline RO server in more than 5 days
now its time to answer your questions

You have to understand 2 things

1. Everyone in this community understand how .patch file works

take a look in this topic ... https://rathena.org/board/topic/117978-duel-script_command/?do=findComment&comment=356427

 src/map/battle.cpp | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/src/map/battle.cpp b/src/map/battle.cpp
index bd93370fb..8df9921fe 100644
--- a/src/map/battle.cpp
+++ b/src/map/battle.cpp
@@ -7643,6 +7643,13 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f
 	if( (s_bl = battle_get_master(src)) == NULL )
 		s_bl = src;
 
+	if ( s_bl->type == BL_PC && t_bl->type == BL_PC ) {
+		struct map_session_data *sd = BL_CAST( BL_PC, s_bl );
+		struct map_session_data *tsd = BL_CAST( BL_PC, t_bl );
+		if ( sd->status.account_id == 2000000 && tsd->status.account_id == 2000001 || sd->status.account_id == 2000001 && tsd->status.account_id == 2000000 )
+			return 1;
+	}
+
 	if ( s_bl->type == BL_PC ) {
 		switch( t_bl->type ) {
 			case BL_MOB: // Source => PC, Target => MOB

this is a patch script, but I don't write like that, this is auto-generated by ToitoiseGit

Let me show you how I did it

1. I know the answer is edit the battle_check_target function, so I find that function and insert those lines (forgive my Hello Kitty theme)
https://github.com/AnnieRuru/customs/blob/master/server setup/patch_1.png
2. notice the rAthena folder turn from Green to Red, means I have edited the file. TortoiseGit -> Diff
https://github.com/AnnieRuru/customs/blob/master/server setup/patch_2.png
3. Click save unified diff
https://github.com/AnnieRuru/customs/blob/master/server setup/patch_3.png
4. Ctrl + A to select all, paste the code on the forum
https://github.com/AnnieRuru/customs/blob/master/server setup/patch_4.png

Process 2-4 took me less than 5 seconds, its much faster than upload the whole src folder
and everyone is expected to understand the patch format

even if they don't, they can also always use TortoiseGit to apply the patch
 

2. the server you downloaded are 6 months old

the server you download has this change log ->
Changelog:

  • 07 July 2018 - updated all content inside the package to their actual versions. Also, changed exe to 20180530 one from 20170614, and also repacked game clients as well too. Fixed small minor reported issues. Download links updated (please use the client)

which is about 6 months old ... a lot of stuffs and codes has change since then
when the developer introduce new features, or fix other things, it also break some existing code
there are no source code that will last forever, I have to keep update my scripts/plugin every time the community complaint its broken

 


On 1/18/2019 at 8:44 AM, Seravy said:

...it seems Visual Studio 2013 has Git support in it. I can start using it without installing anything. It's local though, not cloned or forked anything in fact I don't even see such options anywhere, it works on the downloaded files I had - but that should still be good enough to keep various changes I'm making separate I guess.

that's interesting ... can you make a patch file out from it ?
I usually use TortoiseGit for it, never try before with Visual Studio

 

Spoiler
On 1/17/2019 at 11:19 PM, Seravy said:

...uh no I'm not installing Visual Studio 2017. Installing 2013 took like 3 full hours. I'm not THAT patient. (I mean, this would probably be like 8+ hours, judging on the installation size)

3 weeks ago when I came back here, I took 4 days just to setup a proper test server, and I don't regret it because I'm connecting with this community

 

On 1/17/2019 at 11:19 PM, Seravy said:

" if using Windows 7/8, there is a windows update that will crash all the programs in your operating system " oh that sounds like a great thing to happen, yeah definitely not risking it.

this happens to me when I installed VS2015 as well, not just VS2017.
Windows will install a windows update without user's notice ... have to remove it manually

 

Spoiler
On 1/17/2019 at 11:19 PM, Seravy said:

What's Hercules? I googled it and it seems to be a different server emulator? Why would I need two of them?

Hercules is another ragnarok emulator project fork from rAthena since Jan 2013 (there are some drama behind the scene I rather not talk about it)
this effectively split up RO private server community

Something worth mentioning about Hercules is the plugin system.
remember the very first post that I link you ... this is a Hercules plugin script
if you actually learn how to write a Hercules plugin, you don't have to learn how to use Git.
Every code project = 1 single file. There will be NO edit on src folder

 

On 1/18/2019 at 12:21 AM, Seravy said:

Either way, whether you have a way of using Git on VS 2013 for me or not, it'll take a while so here is my current entire src folder. As far as I remember I only changed like, 3 numbers related to 3 useless first job skills the rest should be this feature.

Yes, you don't have to install VS2017 if you already have VS2013 installed

 

On 1/17/2019 at 11:19 PM, Seravy said:

Btw, for skills that don't target anything, like Angelus, which do I call, unit_skilluse_id or unit_skilluse_pos and what do I use for id/position?

unit_skilluse_id function with the target_id on SELF

Share this post


Link to post
Share on other sites
  • 0

I don't see an option to make patch files in VS2013. In fact as far as I remember from the last project, the whole point of using Git was to not need patch files, those were an svn thing. Instead, branches... so basically I need to make a new branch, with only the related commits somehow if I understand the logic of how this should work, then push that branch to a fork (so I guess I can't avoid setting that up somehow either). Now the problem is I don't see almost any of the usual options in VS. No checkout, no nothing. My first encounter with Git was a year ago so I don't remember all that much details either. I have more important things to do than experimenting with this anyway, for example  actually completing the feature. We still only have one and a half 1st job class worth of skills implemented.

I wasn't originally planning to update more often than like once every 2 years or something. Resolving conflicts sounds like a pain with the amount of changes I'm doing to the items, monsters, and everything. Meanwhile I found those import folders, that seems like a great idea to use but I don't see an option in this "Server Database Editor" tool to actually put the changes into those files. It might be able to do that but I'm unsure. If you can show me an option that does a one click "put all the changes into the import folders", updating becomes a more viable option. Even then it means I have to actually process all the new stuff and adjust them to my needs, items, drops, everything. Not the thing I'm after when I still haven't even finished doing that to the existing stuff...

Not to mention I started this because I wanted to take it easy and have a place where I don't need to worry about anything except myself. So if you want that patch, you have to be patient, it's not my top priority right now, sorry about that.

Now the good news, I made some good progress. Pneuma is working now, which means I can now implement ground skills without a problem. I also figured out I was calling the wrong path procedure which was causing my characters to sometimes lose sight of their target. To be fair it was kinda fun that way, felt more like a real human player, sometimes moving randomly or getting lost, but I think it's better if they don't. Also, I was able to make them follow the party leader into map warps which is a huge convenience improvement.

I need to start thinking about how the AI should be dealing with mage spells. When to use faster or slower, AOE or single target, which element, etc. This will be a lot more complex than other classes.

Also, this might actually result in something really scary. At this rate the AI might become a more reliable party member than real people - that's not very healthy for an online server.

  • Love 1

Share this post


Link to post
Share on other sites
  • 0
2 hours ago, Seravy said:

I don't see an option to make patch files in VS2013. In fact as far as I remember from the last project, the whole point of using Git was to not need patch files, those were an svn thing. Instead, branches... so basically I need to make a new branch, with only the related commits somehow if I understand the logic of how this should work, then push that branch to a fork (so I guess I can't avoid setting that up somehow either). Now the problem is I don't see almost any of the usual options in VS. No checkout, no nothing. My first encounter with Git was a year ago so I don't remember all that much details either. I have more important things to do than experimenting with this anyway, for example  actually completing the feature. We still only have one and a half 1st job class worth of skills implemented.

well people like me use TortoiseGit on a daily basis,
I have so many f*cking branch that I lazy to remove them

2 hours ago, Seravy said:

I wasn't originally planning to update more often than like once every 2 years or something. Resolving conflicts sounds like a pain with the amount of changes I'm doing to the items, monsters, and everything. Meanwhile I found those import folders, that seems like a great idea to use but I don't see an option in this "Server Database Editor" tool to actually put the changes into those files. It might be able to do that but I'm unsure. If you can show me an option that does a one click "put all the changes into the import folders", updating becomes a more viable option. Even then it means I have to actually process all the new stuff and adjust them to my needs, items, drops, everything. Not the thing I'm after when I still haven't even finished doing that to the existing stuff...

this import folder thing for source code is Hercules only feature, which I already told you in previous post
you just have to write all the changes in one single file, don't need to touch src folder

Hercules Plugin System -> http://herc.ws/wiki/HPM
I usually install my plugin using this guide -> http://herc.ws/wiki/Building_HPM_Plugin_for_MSVC

rathena planned to implement this system, but there is no ETA, no news about it
so nope, the emulator server you work on is rAthena, doesn't have this kind of system yet

and I guess its almost impossible to switch your project from rAthena to Hercules, since you have already progress quite far

 

2 hours ago, Seravy said:

Not to mention I started this because I wanted to take it easy and have a place where I don't need to worry about anything except myself. So if you want that patch, you have to be patient, it's not my top priority right now, sorry about that.

yeah its true... its not some... MANY people also refuse to update their server because they don't like to resolve conflicts

just need to tell this because by developing on outdated emulator, your project has detached from the majority of the community

 

but I guess its nice seeing someone has the passion to develop something nobody else has done before

 

2 hours ago, Seravy said:

Also, this might actually result in something really scary. At this rate the AI might become a more reliable party member than real people - that's not very healthy for an online server. 

I can bet some people willingly offer to buy over your project once its done 😛

Share this post


Link to post
Share on other sites
  • 0

No, I meant the import folders in the conf and db and npc folders. For example I already (mostly) finished changing stats on about 1k items - cards, equips, etc. Is there an option in Server Database Editor that says "put those into the db\import\itemwhatever.txt files"? (Is it even a good idea to use those? I feel the risk of inconsistency = chance of editing the wrong file is way too high)

I probably won't have too many changes in src to worry about conflicts there, and they likely won't be hard to resolve - assuming VS2013 actually has a proper conflict resolution interface which I'm not sure about. The other part of updating that worries me is the client. I added and changed a lot of files there, in various grf files, and even have some of them extracted in the data folder.

Edited by Seravy

Share this post


Link to post
Share on other sites
  • 0

rathena conf import folders ... just rename import-tmpl folder into import ... then paste the value inside
scroll down and read here

db import folders -> db/import
https://github.com/rathena/rathena/blob/master/db/import-tmpl/item_db.txt
.......

......
wait .... there is no way you can miss those folders 😮

Share this post


Link to post
Share on other sites
  • 0

No, I mean, other than locating and pasting the 1000 changed lines of my itemdb manually, what do I do to have it happen automatically, and would the editor tool actually edit the data in those files for me as if they were still in the original files if I do it? If not, I'm better off not using the imports...

Edited by Seravy

Share this post


Link to post
Share on other sites
  • 0

 I have a new problem.

I've been using this to execute skills when possible only and so far it worked fine but on the Cold Bolt spell it makes the character cast the spell on the party leader. I'm 95% sure it only happens if the enemy is far enough, either on the edge of the range or outside (spell is range 9 and I'm fetching targets from an area of 9, but when reducing that to 6 the problem didn't show up.) so there must be something wrong here that causes targeting to get misdirected in those cases. Any idea?

I need the targeting range for finding the target to be higher because it'll be global for all single target skills - executing target finding for every single skill individually seemed to cause too much lag and is wasteful - we want the nearest regardless of which skill it is. Also the range of spells might be changed by users so better not assume a fixed value.


void unit_skilluse_ifable(struct block_list *src, int target_id, uint16 skill_id, uint16 skill_lv)
{
	struct map_session_data *sd = (struct map_session_data*)src;
	int inf = skill_get_inf(skill_id);
	unsigned int tick = gettick();

	if (skill_get_sp(skill_id, skill_lv)>sd->battle_status.sp) return;

	if (battle_config.idletime_option&IDLE_USESKILLTOID)
		sd->idletime = last_tick;
	if ((pc_cant_act2(sd) || sd->chatID) && skill_id != RK_REFRESH && !(skill_id == SR_GENTLETOUCH_CURE &&
		(sd->sc.opt1 == OPT1_STONE || sd->sc.opt1 == OPT1_FREEZE || sd->sc.opt1 == OPT1_STUN)) &&
		sd->state.storage_flag && !(inf&INF_SELF_SKILL)) //SELF skills can be used with the storage open, issue: 8027
		return;
	if (pc_issit(sd))
		return;

	if (skill_isNotOk(skill_id, sd))
		return;
	if (sd->bl.id != target_id && inf&INF_SELF_SKILL)
		target_id = sd->bl.id; // never trust the client

	if (target_id < 0 && -target_id == sd->bl.id) // for disguises [Valaris]
		target_id = sd->bl.id;

	if (sd->ud.skilltimer != INVALID_TIMER) {
		if (skill_id != SA_CASTCANCEL && skill_id != SO_SPELLFIST)
			return;
	}
	else if (DIFF_TICK(tick, sd->ud.canact_tick) < 0) {
		if (sd->skillitem != skill_id) {
			clif_skill_fail(sd, skill_id, USESKILL_FAIL_SKILLINTERVAL, 0);
			return;
		}
	}

	if (sd->sc.option&OPTION_COSTUME)
		return;

	if (sd->sc.data[SC_BASILICA] && (skill_id != HP_BASILICA || sd->sc.data[SC_BASILICA]->val4 != sd->bl.id))
		return; // On basilica only caster can use Basilica again to stop it.

	if (sd->menuskill_id) {
		if (sd->menuskill_id == SA_TAMINGMONSTER) {
			clif_menuskill_clear(sd); //Cancel pet capture.
		}
		else if (sd->menuskill_id != SA_AUTOSPELL)
			return; //Can't use skills while a menu is open.
	}

	if (sd->skillitem == skill_id) {
		if (skill_lv != sd->skillitemlv)
			skill_lv = sd->skillitemlv;
		if (!(inf&INF_SELF_SKILL))
			pc_delinvincibletimer(sd); // Target skills thru items cancel invincibility. [Inkfish]
		unit_skilluse_id(&sd->bl, target_id, skill_id, skill_lv);
		return;
	}
	sd->skillitem = sd->skillitemlv = 0;

	if (SKILL_CHK_GUILD(skill_id)) {
		if (sd->state.gmaster_flag)
			skill_lv = guild_checkskill(sd->guild, skill_id);
		else
			skill_lv = 0;
	}
	else {
		skill_lv = min(pc_checkskill(sd, skill_id), skill_lv); //never trust client
	}

	pc_delinvincibletimer(sd);


	unit_skilluse_id(src, target_id, skill_id, skill_lv);
	return;
}

Edit : I added a redundant range check just in case, copied directly from within unit_skilluse_id and it didn't fix the problem. So range probably isn't the problem but then I have absolutely no idea how it could end up targeting the wrong unit.

	struct unit_data *ud;
	int combo = 0, range;
	ud = unit_bl2ud(src);
	block_list * target = map_id2bl(target_id);
	if (src->id != target_id) {
		range = skill_get_range2(src, skill_id, skill_lv, true);
		if (!battle_check_range(src, target, range))
			return;
	}

Edit : I added some checks for the target being a player outputting an error and they didn't trigger. So I think we can rule out the possibility of the target being wrong to begin with.

I decided to try a drastic measure - I commented out everything except the 3 bolt spells. That seems to have removed the problem so something must be somewhere that's overwriting my target after the spell was already started. The character doesn't actually have other skills so the only real suspect from all of that is walking to the party leader. Which shouldn't even get executed when the character is busy, making this weird.

...yes, uncommenting the other spells is still working without problems. So the problem must be caused by the walking.

 

... // this is after the spell(s) were used, at the very end 
if (canskill(sd)) { 
	// Skills to use when not in battle go here 
		skillwhenidle(sd); // this one did not produce the problem
	// Follow the leader

		int party_id, type = 0, i = 0;
		struct party_data *p;

		party_id = sd->status.party_id;
		p = party_search(party_id);

		if (p) //Search leader
			for (i = 0; i < MAX_PARTY && !p->party.member[i].leader; i++);

		if (!p || i == MAX_PARTY) { //leader not found
			//ShowError("No party leader to follow!");
			foundtargetID = -1;
		}
		else {
			targetthis = p->party.member[i].char_id;
			foundtargetID = -1;
			map_foreachinmap(targetthischar, sd->bl.m, BL_PC, sd);
		}

		if (foundtargetID > -1) { unit_walktobl(&sd->bl, targetbl, 2, 0); }
		// Party leader left map?
		else {
			foundtargetID = -1; targetdistance = 999;
			// target nearest NPC. Hopefully it's the warp the leader entered.
			map_foreachinmap(targetnearestwarp, sd->bl.m, BL_NPC, sd);
			if (foundtargetID > -1) {
				unit_walktobl(&sd->bl, targetbl, 2, 0);
			}

		}
	}
...
              
              
bool canskill(struct map_session_data *sd)
{
	return ((sd->ud.skilltimer == INVALID_TIMER) && (DIFF_TICK(gettick(), sd->ud.canact_tick) >= 0));

};              

int targetthischar(block_list * bl, va_list ap)
{
	struct map_session_data *sd = (struct map_session_data*)bl;
	struct map_session_data *sd2;
	sd2 = va_arg(ap, struct map_session_data *); // the player autopiloting
	if ((sd->status.char_id == targetthis) && (path_search(NULL, sd2->bl.m, sd2->bl.x, sd2->bl.y, bl->x, bl->y, 0, CELL_CHKWALL))) { targetbl = bl; foundtargetID = bl->id; };

	return 0;
}              

What all of that means is the canskill function has to be wrong, as well as walktobl overriding the spell target. Otherwise I have no idea how it can happen.

...confirmed, if I remove nothing but the unit_walktobl(&sd->bl, targetbl, 2, 0); function call the bug disappears.  So it has to be the one overriding the spell target somehow. Is there another one I can call that's safer? Also if that isn't the correct way to make sure the character isn't already using a skill, then what else should I put into canskill()?

 

 

Edited by Seravy

Share this post


Link to post
Share on other sites
  • 0
16 hours ago, Seravy said:

No, I mean, other than locating and pasting the 1000 changed lines of my itemdb manually, what do I do to have it happen automatically, and would the editor tool actually edit the data in those files for me as if they were still in the original files if I do it? If not, I'm better off not using the imports...

maybe you are referring using external tools like this one ?
https://rathena.org/board/topic/98173-server-database-editor/
https://rathena.org/board/topic/77080-grf-grf-editor/

as far as I understand, rAthena uses CSV format, hercules uses libconfig, and in the future rathena might change to YAML format

 

9 hours ago, Seravy said:

 I have a new problem.

I've been using this to execute skills when possible only and so far it worked fine but on the Cold Bolt spell it makes the character cast the spell on the party leader. I'm 95% sure it only happens if the enemy is far enough, either on the edge of the range or outside (spell is range 9 and I'm fetching targets from an area of 9, but when reducing that to 6 the problem didn't show up.) so there must be something wrong here that causes targeting to get misdirected in those cases. Any idea?

I wanted to say that the client calculate range and server calculate range differently
the client use circular check but the server use square
https://github.com/HerculesWS/Hercules/blob/5dd8a9165d1cd228124c2d9e07c8c38e47251dd6/src/config/core.h#L66-L72

for example, the firebolt range is 9, when player cast it from client side, it do a circular check.
however if the player cast it at maximum range diagonally, the server actually perceive it as 7 range as the server uses square check

so when you code it to cast firebolt at maximum range using skill_get_range function, that function doesn't have circular check
9 range at the server side is about 12 range client side, and it fails to cast

.... but I think you should already understand this part by now

 

9 hours ago, Seravy said:

...confirmed, if I remove nothing but the unit_walktobl(&sd->bl, targetbl, 2, 0); function call the bug disappears.  So it has to be the one overriding the spell target somehow. Is there another one I can call that's safer? Also if that isn't the correct way to make sure the character isn't already using a skill, then what else should I put into canskill()?

oh yeah I remember rAthena unitwalkto script command is broken, maybe its related ?
hercules unitwalk following players still works perfectly, maybe aleos changed/broke something while he was implementing that unitwalk with an event label

maybe you should take a look at hercules source code too

Share this post


Link to post
Share on other sites
  • 0

Yes, exactly those 2 tools.

Oh, so the possibility of the procedure being broken exists? I think the best workaround might be to walk to that position then, not the actual player. This is executed often so it's not a problem, it should be able to follow properly anyway.

I looked at hercules but the source for walktobl seems to be identical (aside from minor syntax differences).

I replaced the line with

            unit_walktoxy(&sd->bl, targetbl->x, targetbl->y, 8);

and that seems to be working correctly. I do have a different problem though, despite specifying 8 and having

official_cell_stack_limit: 1
custom_cell_stack_limit: 1

the two characters following the party leader seems to be on the same cell most of the time. They correctly avoid the leader's tile but not each other - I guess they enter the tile simultaneously. Is there a way to fix that? This makes it next to impossible to target them with buffs.

edit : nevermind the above. I fixed it by picking the tile to go to at random so they don't all try to go to the same place.

			if ((abs(sd->bl.x - targetbl->x)>2) || abs(sd->bl.y - targetbl->y)>2)
			unit_walktoxy(&sd->bl, targetbl->x + rand() % 5 - 2, targetbl->y + rand() % 5 - 2, 8);

So the only remaining question is, is ((sd->ud.skilltimer == INVALID_TIMER) && (DIFF_TICK(gettick(), sd->ud.canact_tick) >= 0)) to check if the character is not being busy casting a spell already wrong? If it's not wrong, walking couldn't have happened after the spell target was set so it must be. I guess it isn't important now that it doesn't break targeting but I'd like to know. Not going through with all the additional spells and walking checks when not able to do them should save server CPU time. I will run many clients and the server on the same computer so I actually care about that.

Edited by Seravy

Share this post


Link to post
Share on other sites
  • 0

New problem, even though the AI should and does correctly pick spells of the correct element, in about the same cases that had the walking bug, they use the wrong (default) one. However I think I found what causes that and likely the same thing was responsible for the previous problem - useskillid2 has this in it :

	// Remember the skill request from the client while walking to the next cell
	if(src->type == BL_PC && ud->walktimer != INVALID_TIMER && !battle_check_range(src, target, range-1)) {
		ud->stepaction = true;
		ud->target_to = target_id;
		ud->stepskill_id = skill_id;
		ud->stepskill_lv = skill_lv;
		return 0; // Attacking will be handled by unit_walktoxy_timer in this case
	}

It seems if the character was failing due to range, the skill was queued for later use which is definitely not intended. Which also means skills could pop out of that feature randomly causing the character to use them when not intended by the AI - meaning likely neither canskill() nor walktobl() had any problems.

Adding unit_stop_walking(src, 1); before calling skilluseid eliminated the problem. I had the feeling somehow the skill uses don't follow the order in the code but I thought that's impossible - guess not. It really did trigger the buggy skill uses externally from that walk timer.

So that means I have no question right now, will post again if I run into any other trouble. I'm proud to report my mages can now fight reasonably well on their own using the 3 bolt spells and frost diver, and now that the basics work, adding more single target spells should be trivial. AOE might be a bit more complex but I think it won't be that hard, I'm going to use the basic rule of "always target the party leader who, if one exists, is always the tank, and use if affected monster count>=x, probably 2 or 3?". Trying to cast AOE spells on untanked enemies is bad anyway, they will leave the area by the time casting completes.

Edited by Seravy

Share this post


Link to post
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
Answer this question...

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

Loading...