NPC masking

Garr

New member
Messages
482
Points
0
Github
HeroGarr
Emulator
File Name: npcmask
File Submitter: Garr
File Submitted: 10 Oct 2014
File Category: Plugins

Masks NPCs on player's client based on his/her variables. Will need to leave NPC sight range/@refresh for it to trigger (if you change variable while NPC is still in sight nothing will change, but @refresh/leaving screen and entering again will trigger mask).
 

Usage:

npcmask <new sprite>,<int variable name>,<compare method>,<value1>,{<value 2>,{<new size>,{<new name>,{<npc name>}}}}npcunmask {<npc name>}

Applies and removes NPC masking, accordingly.

<new sprite> - sprite NPC will show if conditions are met

<int variable name> - variable name to check, only integer character variables.

<compare method> - compare method, based on following masks (v - variable, a- value1, b - value2)
0x01 - Less, uses value1 (v < a)
0x02 - Equal, uses value1 (v == a)
0x04 - More, uses value1 (v > a)
0x10 - "BETWEEN" - Between value1 and value2, including values 1 and 2 (a <= v <= b )
0x20 - "EXCLUDE" - Excluding between value1 and value2, values 1 and 2 are excluded also. (v < a OR v > b )
Example: 0x03 - same as less or equal, makes a check (v <= a)
"BETWEEN" and "EXCLUDE" methods overwrite anything else, "EXCLUDE" will take precedence over all other methods.

<value1> - value1 to compare too, used in all compare methods.

<value2> - value2, used in "BETWEEN" and "EXCLUDE" modes. Optional parameter, if it won't be provided
while using "BETWEEN" or "EXCLUDE" methods, those methods will be skipped.

<new size> - size masking, defaults to medium size.

<new name> - name masking, if not provided will use NPC's original name.

<npc name> - NPC name to use masking on. If not provided, will be used on NPC script is running from.

This plugin appeared from the idea of hiding NPCs from some players, while it still being visible to others. It's just added in functionality.

You can download the file here.

OR

You can copy it from here.

 
Last edited by a moderator:
Oh this would be very useful for quest type scripts where a player completes a certain phase and such. Like also making a player have access to a shop based on whether or not the did X or Y. Instead of just having the NPC be unresponsive or say something like you can't use this. Nice work.

 
Mhmmm... Quick question without having the plugin installed yet. Can you make the NPC look as if it was gone by masking as the -1 sprite and rendering it unclickable?

 
Last edited by a moderator:
Maybe not -1 sprite, but you could go with the ( i think 111? or 139 *think this is the hidden warp portal* ). But the difference would be your hiding it to ALL players by just simply changing the sprite. With the masking it'd be only certain players.

But yes, it would be possible to simulate this effect somewhat using sprite id 111 and variable check to just end the script.

Edit: Oh lol, i see your asking about using the sprite in combination with the plugin (you just didn't install it yet -.-; feel like an idiot now lol !!) but the same methods should still apply by simply using 111 as the sprite id if -1 doesn't work.

 
Last edited by a moderator:
Yes, you can hide it, but by using 139 as sprite, not 111. 111 is invisible NPC with speech bubble, 139 is completely invisible
default_smile.png


 
So this seems like a nice addition to quests, to make people look like they "left" and are no longer available... /me grins

 
Added in upaste mirror. And it's a plugin, used with HPM. If there will be requests of such I might make a source mod diff for it, but not today.

 
Added in upaste mirror. And it's a plugin, used with HPM. If there will be requests of such I might make a source mod diff for it, but not today.
I got these compile warnings
Code:
1>d:hercsrcpluginspscript.c(1273): error C2065: 'CM_LESS' : undeclared identifier1>d:hercsrcpluginspscript.c(1275): error C2065: 'CM_EQU' : undeclared identifier1>d:hercsrcpluginspscript.c(1277): error C2065: 'CM_MORE' : undeclared identifier1>d:hercsrcpluginspscript.c(1279): error C2065: 'CM_BETWEEN' : undeclared identifier1>d:hercsrcpluginspscript.c(1281): error C2065: 'CM_EXCLUDE' : undeclared identifier1>d:hercsrcpluginspscript.c(1375): error C2065: 'CM_LESS' : undeclared identifier1>d:hercsrcpluginspscript.c(1377): error C2065: 'CM_EQU' : undeclared identifier1>d:hercsrcpluginspscript.c(1379): error C2065: 'CM_MORE' : undeclared identifier1>d:hercsrcpluginspscript.c(1381): error C2065: 'CM_BETWEEN' : undeclared identifier1>d:hercsrcpluginspscript.c(1383): error C2065: 'CM_EXCLUDE' : undeclared identifier1>d:hercsrcpluginspscript.c(1431): error C2065: 'CM_LESS' : undeclared identifier1>d:hercsrcpluginspscript.c(1431): error C2065: 'CM_LESS' : undeclared identifier1>d:hercsrcpluginspscript.c(1432): error C2065: 'CM_EQU' : undeclared identifier1>d:hercsrcpluginspscript.c(1432): error C2065: 'CM_EQU' : undeclared identifier1>d:hercsrcpluginspscript.c(1433): error C2065: 'CM_MORE' : undeclared identifier1>d:hercsrcpluginspscript.c(1433): error C2065: 'CM_MORE' : undeclared identifier1>d:hercsrcpluginspscript.c(1434): error C2065: 'CM_BETWEEN' : undeclared identifier1>d:hercsrcpluginspscript.c(1436): error C2065: 'CM_BETWEEN' : undeclared identifier1>d:hercsrcpluginspscript.c(1441): error C2065: 'CM_EXCLUDE' : undeclared identifier1>d:hercsrcpluginspscript.c(1443): error C2065: 'CM_EXCLUDE' : undeclared identifier1>d:hercsrcpluginspscript.c(1493): error C2065: 'CM_LESS' : undeclared identifier1>d:hercsrcpluginspscript.c(1493): error C2065: 'CM_LESS' : undeclared identifier1>d:hercsrcpluginspscript.c(1494): error C2065: 'CM_EQU' : undeclared identifier1>d:hercsrcpluginspscript.c(1494): error C2065: 'CM_EQU' : undeclared identifier1>d:hercsrcpluginspscript.c(1495): error C2065: 'CM_MORE' : undeclared identifier1>d:hercsrcpluginspscript.c(1495): error C2065: 'CM_MORE' : undeclared identifier1>d:hercsrcpluginspscript.c(1496): error C2065: 'CM_BETWEEN' : undeclared identifier1>d:hercsrcpluginspscript.c(1498): error C2065: 'CM_BETWEEN' : undeclared identifier1>d:hercsrcpluginspscript.c(1503): error C2065: 'CM_EXCLUDE' : undeclared identifier1>d:hercsrcpluginspscript.c(1505): error C2065: 'CM_EXCLUDE' : undeclared identifier========== Rebuild All: 0 succeeded, 1 failed, 0 skipped ==========
 
Last edited by a moderator:
I see that you copied it into some kind of bigger plugin for scripting, maybe you missed the enum part? Make sure it's there:

enum compare_method { CM_NONE = 0x00, CM_LESS = 0x01, CM_EQU = 0x02, CM_MORE = 0x04, CM_BETWEEN = 0x10, CM_EXCLUDE = 0x20, CM_MAX = 0x37,} c_m;
Otherwise I'm somewhat at a loss why it'd throw that at you.

 
I see that you copied it into some kind of bigger plugin for scripting, maybe you missed the enum part? Make sure it's there:

enum compare_method { CM_NONE = 0x00, CM_LESS = 0x01, CM_EQU = 0x02, CM_MORE = 0x04, CM_BETWEEN = 0x10, CM_EXCLUDE = 0x20, CM_MAX = 0x37,} c_m;Otherwise I'm somewhat at a loss why it'd throw that at you.
Nope,I'm pretty sure that enum exists....

I try to replace CM_  with CMP ,then those compile warnings dispear ,but still have another warnings

enum compare_method { CM_NONE = 0x00, CM_LESS = 0x01, CM_EQU = 0x02, CM_MORE = 0x04, CM_BETWEEN = 0x10, CM_EXCLUDE = 0x20, CM_MAX = 0x37,} c_m;
Code:
enum compare_method {    CMP_NONE = 0x00,    CMP_LESS = 0x01,    CMP_EQU = 0x02,    CMP_MORE = 0x04,    CMP_BETWEEN = 0x10,    CMP_EXCLUDE = 0x20,    CMP_MAX = 0x37,} ;
another warnings :

1>------ Rebuild All started: Project: plugin-script, Configuration: Debug Win32 ------

1> pscript.c

1> Creating library ..pluginsplugin-script.lib and object ..pluginsplugin-script.exp

1>pscript.obj : error LNK2019: unresolved external symbol _assert_report referenced in function _clif_set_unit_idle_hooked

1>..pluginsplugin-script.dll : fatal error LNK1120: 1 unresolved externals

========== Rebuild All: 0 succeeded, 1 failed, 0 skipped ==========

 
Last edited by a moderator:
Hmm, try adding this

#define pcdb_checkid_sub(class_) ( ( (class_) < JOB_MAX_BASIC ) || ( (class_) >= JOB_NOVICE_HIGH && (class_) <= JOB_DARK_COLLECTOR ) || ( (class_) >= JOB_RUNE_KNIGHT && (class_) <= JOB_MECHANIC_T2 ) || ( (class_) >= JOB_BABY_RUNE && (class_) <= JOB_BABY_MECHANIC2 ) || ( (class_) >= JOB_SUPER_NOVICE_E && (class_) <= JOB_SUPER_BABY_E ) || ( (class_) >= JOB_KAGEROU && (class_) <= JOB_OBORO ) || ( (class_) >= JOB_REBELLION && (class_) < JOB_MAX ) )#define pcdb_checkid(class_) pcdb_checkid_sub((unsigned int)(class_))
inside. What version are you using to compile?

 
Hmm, try adding this

#define pcdb_checkid_sub(class_) ( ( (class_) < JOB_MAX_BASIC ) || ( (class_) >= JOB_NOVICE_HIGH && (class_) <= JOB_DARK_COLLECTOR ) || ( (class_) >= JOB_RUNE_KNIGHT && (class_) <= JOB_MECHANIC_T2 ) || ( (class_) >= JOB_BABY_RUNE && (class_) <= JOB_BABY_MECHANIC2 ) || ( (class_) >= JOB_SUPER_NOVICE_E && (class_) <= JOB_SUPER_BABY_E ) || ( (class_) >= JOB_KAGEROU && (class_) <= JOB_OBORO ) || ( (class_) >= JOB_REBELLION && (class_) < JOB_MAX ) )#define pcdb_checkid(class_) pcdb_checkid_sub((unsigned int)(class_))inside. What version are you using to compile?
my git version is 9ab4f84 and compiling under MSVC 2010

I comment out all the nullpo_retv(bl) lines , compiling is successful now

edit :

report a bug

<new name> - name masking, if not provided will use empty name.

my test script

Code:
npcmask 1002,"abc",0x02,1,2,2;
 
Last edited by a moderator:
That's odd, I thought it counts null string as a null and shouldn't pull this off. Find:

if (flag && nm->nmask ) { memcpy(WBUFP(buf,6), nm->nmask, NAME_LENGTH); } else { memcpy(WBUFP(buf,6), ((TBL_NPC*)bl)->name, NAME_LENGTH); }
And replace with

  if (flag && nm->nmask != "0") {    memcpy(WBUFP(buf,6), nm->nmask, NAME_LENGTH);  } else {    memcpy(WBUFP(buf,6), ((TBL_NPC*)bl)->name, NAME_LENGTH);  }


EDIT: Updated upaste link in opening post.

 
Last edited by a moderator:
That's odd, I thought it counts null string as a null and shouldn't pull this off. Find:

if (flag && nm->nmask ) { memcpy(WBUFP(buf,6), nm->nmask, NAME_LENGTH); } else { memcpy(WBUFP(buf,6), ((TBL_NPC*)bl)->name, NAME_LENGTH); }And replace with
Code:
    if (flag && nm->nmask != "0") {        memcpy(WBUFP(buf,6), nm->nmask, NAME_LENGTH);    } else {        memcpy(WBUFP(buf,6), ((TBL_NPC*)bl)->name, NAME_LENGTH);    }
 
EDIT: Updated upaste link in opening post.
Thanks, but still display empty name if you dont provide param <new name>
 my method is to use nd->name

if ( script_hasdata(st,8) ) {if ( script_isstringtype(st,8) ) {varn2 = script_getstr(st,8);safestrncpy(nm->nmask, varn2, NAME_LENGTH);}} else {safestrncpy(nm->nmask, nd->name, NAME_LENGTH);} then
Code:
			if (flag && nm->nmask ) 				memcpy(WBUFP(buf,6), nm->nmask, NAME_LENGTH);			else				memcpy(WBUFP(buf,6), nd->name, NAME_LENGTH);
 
,and then I m a little bit nosy, and think it would be better if just use removeFromNPCD , hope you dont mind
default_smile.png


BUILDIN(npcunmask) { struct npc_mask *nm; struct npc_data *nd; if( script_hasdata(st,2) ) nd = npc->name2id(script_getstr(st,2)); else nd = map->id2nd(st->oid); if( nd == NULL ) { script_pushint(st,-1); //No such NPC; return true; } if((nm = getFromNPCD(nd,0))) removeFromNPCD(nd,0); script_pushint(st,1); return true;}
btw,hookstop must be inside an if-condition or you will cause unnecessary trouble

if ((nm = getFromNPCD(nd,0))) {............hookStop();}

for example

Code:
	if (bl->type == BL_NPC){		struct npc_data *nd = (TBL_NPC*)bl;		struct npc_mask *nm;		if ((nm = getFromNPCD(nd,0))) {			unsigned char buf[103];			int var;			bool flag = false;			WBUFW(buf,0) = 0x95;			WBUFL(buf,2) = bl->id;			var = pc_readglobalreg(sd, script->add_str(nm->varname));			if ( nm->masked && nm->compare) { //Not checking var or nm->value1/2 to make usage of variables resulting in 0 possible, or to compare with 0.				if (nm->compare&CMP_LESS && var < nm->value1)					flag = true;				if (nm->compare&CMP_EQU && var == nm->value1)					flag = true;				if (nm->compare&CMP_MORE && var > nm->value1)					flag = true;				if ( nm->compare&CMP_BETWEEN && var >= nm->value1 && var <= nm->value2 )					flag = true;				if ( nm->compare&CMP_EXCLUDE && (var < nm->value1 || var > nm->value2) )					flag = true;			}			if (flag && nm->nmask ) 				memcpy(WBUFP(buf,6), nm->nmask, NAME_LENGTH);			else				memcpy(WBUFP(buf,6), nd->name, NAME_LENGTH);				WFIFOHEAD(sd->fd, 30);			memcpy(WFIFOP(sd->fd, 0), buf, 30);			WFIFOSET(sd->fd, 30);			hookStop();				}	}
 
Last edited by a moderator:
Updated links with your suggestions, thank you very much. It's first time I ever I make a plugin, not to mention I never really worked with C++ or C before. So had to go with guessing game sometimes.
 
Also, about last suggestion with it being inside if, won't the ifs before that prevent it from triggering by returning to main function before the hookStop()?
 
Because this:

if ( bl->type == BL_NPC ) { ...code with hookStop()...}return;
Seems same with:

if (bl->type != BL_NPC) return;...code with hookStop()...
 
Also, found a solution for nullpo not linking:
RMB on project, Properties , and change Configuration to "Release" for this plugin.

2lmozsh.jpg


 
I'd like report a  small typo bug ,That's the duplicate  'case 0x088A'  ,but it won't show any compile warnings

if your PACKETVER  <=20140402 ,or it will...

 
Back
Top