Jump to content

Utility: Reset NPC that can only reset your current class


Tero

Recommended Posts


  • Group:  Members
  • Topic Count:  8
  • Topics Per Day:  0.01
  • Content Count:  58
  • Reputation:   113
  • Joined:  10/01/22
  • Last Seen:  

This has been a request that I think everyone has made at one point or another, but I initially looked at it and said "too complicated".  Well, today I decided to finally code the thing.

image.png.0d8ca1e323e3f158f721e02f055831dc.png

 

Basically, this is an adjustment to the Reset NPC that gives you the option to only reset your current class, leaving your previous classes untouched.  

 

This requires code changes to support it, and you'll have to recompile your server afterwards.  A quick caveat, though this includes code to support third and fourth classes (for Renewal), that code is untested.  It's similar to the second class logic so it should work, but if you have some kind of weird issue it's probably there.

 

In pc.cpp, find the pc_resetskill method

 

Find this line:

int i, skill_point=0;

Replace it with this:

int i, j, k, l, baseClass, secondTransClass, thirdClass, currentClass, skid, skill_point = 0;
bool previousClassSkill, isSecondClass = false, isThirdClass = false, isFourthClass = false;

 

Find this line:

if( flag&4 && (sd->class_&MAPID_UPPERMASK) != MAPID_BARDDANCER )
		return 0;

Insert this below it (don't replace the code above).  If your server has fourth classes, uncomment that line.

baseClass = pc_mapid2jobid(sd->class_ & MAPID_BASEMASK, sd->status.sex);
secondTransClass = pc_mapid2jobid(sd->class_ & MAPID_UPPERMASK | JOBL_UPPER, sd->status.sex);
thirdClass = pc_mapid2jobid(sd->class_ | JOBL_THIRD, sd->status.sex);
currentClass = pc_mapid2jobid(sd->class_, sd->status.sex);

if ((sd->class_ & MAPID_BASEMASK) != sd->class_ && (sd->class_ & MAPID_BASEMASK | JOBL_UPPER) != sd->class_ && (sd->class_ & MAPID_BASEMASK | JOBL_BABY) != sd->class_) isSecondClass = true;
if ((sd->class_ | JOBL_THIRD) == sd->class_ && (sd->class_ & MAPID_BASEMASK) != sd->class_ && (sd->class_ & MAPID_UPPERMASK) != sd->class_) isThirdClass = true;
//if ((sd->class_ | JOBL_FOURTH) == sd->class_ && (sd->class_ & MAPID_BASEMASK) != sd->class_ && (sd->class_ & MAPID_UPPERMASK) != sd->class_ && (sd->class_ | JOBL_THIRD) != sd->class_) isFourthClass = true;

currentClass = pc_class2idx(currentClass);
baseClass = pc_class2idx(baseClass);
secondTransClass = pc_class2idx(secondTransClass);
thirdClass = pc_class2idx(thirdClass);

 

Find this line

if (lv == 0 || skill_id == 0)
			continue;

 

What you need to add next depends on your version of eathena.  If you are on latest, which has the new skill tree, add this below that line:

if (flag & 16) {
	previousClassSkill = false;

	if (baseClass != currentClass) {
		std::shared_ptr<s_skill_tree> firstTree = skill_tree_db.find(baseclass);
	
		if (tree != nullptr && !tree->skills.empty()) {
			for (const auto &it : tree->skills) {
				skid = skill_get_index(it.first);
				if (skid == skill_id) previousClassSkill = true;	
			}
		}
	}

	if (isThirdClass) {
		std::shared_ptr<s_skill_tree> secondTree = skill_tree_db.find(secondTransClass);
	
		if (tree != nullptr && !tree->skills.empty()) {
			for (const auto &it : tree->skills) {
				skid = skill_get_index(it.first);
				if (skid == skill_id) previousClassSkill = true;	
			}
		}
	}
          
    if (isFourthClass) {
		std::shared_ptr<s_skill_tree> thirdTree = skill_tree_db.find(thirdClass);
	
		if (tree != nullptr && !tree->skills.empty()) {
			for (const auto &it : tree->skills) {
				skid = skill_get_index(it.first);
				if (skid == skill_id) previousClassSkill = true;	
			}
		}
	}
}

 

If you are on an older version, which has the old form of skill_tree, add this below that line instead:

if (flag & 16) {
	previousClassSkill = false;

	if (baseClass != currentClass) {				
		for (j = 0; j < MAX_SKILL_TREE && (skid = skill_tree[baseClass][j].skill_id) > 0; j++) {
			if (skid == skill_id) previousClassSkill = true;
		}
	}

	if (isThirdClass) {
		for (k = 0; k < MAX_SKILL_TREE && (skid = skill_tree[secondTransClass][k].skill_id) > 0; k++) {
			if (skid == skill_id) previousClassSkill = true;
		}
	}

	if (previousClassSkill) continue;
}

 

We're pretty much done with pc_resetskill, but if you want, you can add this to the comment at the top of the method, as the final line:

 * if flag&16, Only reset skills that the current class can learn

 

Almost done with code changes, now we just need to add the script function.

 

The remainder of the changes are in script.cpp:

 

First, find the definitions of the script functions by searching for this:

struct script_function buildin_func[]

And add the following line somewhere, ideally below the one for resetskill

BUILDIN_DEF(resetskillcurrentonly, "?"),

 

Now add this method somewhere, ideally below resetskill but it can in theory go anywhere.

/**
 * Reset player's skill, leaving previous classes untouched
 * resetskillcurrentonly({<char_id>});
 **/
BUILDIN_FUNC(resetskillcurrentonly)
{
	TBL_PC* sd;
	if (!script_charid2sd(2, sd))
		return SCRIPT_CMD_FAILURE;
	pc_resetskill(sd, 17);
	return SCRIPT_CMD_SUCCESS;
}

 

With this done, you can recompile the client and everything should be set.  Now all you need is the new version of the resetnpc script below and you'll have the new functionality.  Man, this was a lot harder than it should have been.  Rathena should really just add this option by default.

resetnpc.txt

Edited by Tero
  • Upvote 2
Link to comment
Share on other sites

  • 4 weeks later...

  • Group:  Members
  • Topic Count:  45
  • Topics Per Day:  0.01
  • Content Count:  140
  • Reputation:   11
  • Joined:  09/28/14
  • Last Seen:  

Great job!

Link to comment
Share on other sites

  • 4 months later...

  • Group:  Members
  • Topic Count:  5
  • Topics Per Day:  0.00
  • Content Count:  51
  • Reputation:   19
  • Joined:  04/21/13
  • Last Seen:  

I love this. And yeah this should be the default behavior of the reset npc!
Could someone with good rA scripting knowledge check the script, could there be issues with 4th jobs ?

Edited by eleriaqueen
Link to comment
Share on other sites


  • Group:  Members
  • Topic Count:  48
  • Topics Per Day:  0.02
  • Content Count:  180
  • Reputation:   6
  • Joined:  10/22/18
  • Last Seen:  

On 10/12/2023 at 9:00 AM, Tero said:
* if flag&16, Only reset skills that the current class can learn

i dont understand this part. where should i put this line?

Link to comment
Share on other sites


  • Group:  Forum Moderator
  • Topic Count:  44
  • Topics Per Day:  0.01
  • Content Count:  896
  • Reputation:   117
  • Joined:  05/23/12
  • Last Seen:  

On 10/12/2023 at 3:00 AM, Tero said:

We're pretty much done with pc_resetskill, but if you want, you can add this to the comment at the top of the method, as the final line:

If u want and Tero already write where to add this line. It's just a comment for the method. It's do nothing. U can add it on the comments on top of pc_resetskill for explain reasons.

 

Rynbef~

Edited by Rynbef
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...