@partybuff / @spb

cumbe11

New member
Messages
46
Points
0
Here is this change?
 
 
 
@partybuff (@spb) can display party member's special buffs in party list (Alt+Z)
Buffs are:
Quote

B - Blessing
A - Agility Up
F - Full Chemical Protection
S - Soul Link
+ - Devotion
Look like
[BAFS+]Player name

 
Last edited by a moderator:
even if this is possible, there is a client restriction which disallow to display player name longer than 23 characters ...
and the color has to be client reverse engineer ...
 
means, no, this also has to do client side modification
 
but if not display in the Alt+Z, but with a message command
then this can even done with scripting alone, with getstatus script command

-  script  jsfkjsdf  FAKE_NPC,{OnInit:  bindatcmd "psc", strnpcinfo(0)+"::Onaaa";  end;Onaaa:  .@pid = getcharid(1);  if ( !.@pid ) {    dispbottom "you don't have a party to use this command";    end;  }  getpartymember .@pid, 1;  getpartymember .@pid, 2;  .@origin = getcharid(3);  for ( .@i = 0; .@i < $@partymembercount; ++.@i ) {    if ( isloggedin( $@partymemberaid[.@i] , $@partymembercid[.@i] ) ) {      attachrid $@partymemberaid[.@i];      .@buff$ = "";      if ( getstatus(SC_BLESSING) ) .@buff$ += "B";      if ( getstatus(SC_INC_AGI) ) .@buff$ += "A";      if ( getstatus(SC_PROTECTWEAPON) && getstatus(SC_PROTECTSHIELD) && getstatus(SC_PROTECTARMOR) && getstatus(SC_PROTECTHELM) ) .@buff$ += "F";      if ( getstatus(SC_SOULLINK) ) .@buff$ += "S";      if ( getstatus(SC_DEVOTION) ) .@buff$ += "+";      .@display$[.@c++] = "["+ .@buff$ +"] "+ strcharinfo(0);    }  }  attachrid .@origin;  for ( .@i = 0; .@i < .@c; ++.@i )    dispbottom .@display$[.@i];  end;}
screenRuru_Server018.jpg

 
Last edited by a moderator:
There's a mod like this from rAthena which is from Lilit's Mod.

 
@@Vlync

now I'm very very interested, show meh !
default_biggrin.png


EDIT: even a video is fine, I can guess how they did it

 
Last edited by a moderator:
@@Vlync

now I'm very very interested, show meh !
default_biggrin.png


EDIT: even a video is fine, I can guess how they did it
Name can be modified via clif.c, hooking appropriate functions..(And trimming names if they reach > 23 char, thats what they do)

 
Last edited by a moderator:
ok, let's analyze the packet

clif_party_member_info

/// Adds new member to a party.

/// 0104 <account id>.L <role>.L <x>.W <y>.W <state>.B <party name>.24B <char name>.24B <map name>.16B (ZC_ADD_MEMBER_TO_GROUP)

23 characters for name, 23 characters for map name

hmm ... if we replace the map name with buff ... hehe ... sounds fun

clif_party_info

/// Sends party information (ZC_GROUP_LIST).

/// 00fb <packet len>.W <party name>.24B { <account id>.L <nick>.24B <map name>.16B <role>.B <state>.B }*

/// role:

/// 0 = leader

/// 1 = normal

/// state:

/// 0 = connected

/// 1 = disconnected

clif_party_xy

/// Updates the position of a party member on the minimap (ZC_NOTIFY_POSITION_TO_GROUPM).

/// 0107 <account id>.L <x>.W <y>.W

clif_party_hp

/// Updates HP bar of a party member.

/// 0106 <account id>.L <hp>.W <max hp>.W (ZC_NOTIFY_HP_TO_GROUPM)

so ... there is no packet to update the party member's status in Alt+Z bar

clif_parse_LeaveParty

/// Request to leave party (CZ_REQ_LEAVE_GROUP).

clif_parse_RemovePartyMember

/// Request to expel a party member (CZ_REQ_EXPEL_GROUP_MEMBER).

the one trick that I can think off, is sending a packet to leave player's party and invite back with a fake name

but I wonder doing this will have message on the chat log ?

... hmm ... ask a client translation team, maybe they know where is the english file at

 
void clif_party_info -> memcpy(WBUFP(buf,28+c*46+4), m->name, NAME_LENGTH); 
Just modify m->name before using memcpy.. and that will show change in party window.
default_smile.png


Edit: In chat log, they will have normal name, just party window will be edited.

 
Hmm. But that will also need additional calls to this if status will get changed. Because iirc by default party info changes when player either logs off/on or changes map. Also, may change character name limit to 17 to avoid name cutting (most nicknames are under 12~15 characters anyway).

 
Last edited by a moderator:
#include "common/hercules.h"#include <stdio.h>#include <string.h>#include <stdlib.h>#include "map/pc.h"#include "map/clif.h"#include "map/party.h"#include "common/nullpo.h"#include "common/socket.h"#include "common/HPMDataCheck.h" // should always be the last file included! (if you don't make it last, it'll intentionally break compile time)HPExport struct hplugin_info pinfo = { "test123", // Plugin name SERVER_TYPE_MAP,// Which server types this plugin works with? "0.0", // Plugin version HPM_VERSION, // HPM Version (don't change, macro is automatically updated)};struct player_data { int buff;};int status_change_start_post( int retVal, struct block_list *src, struct block_list *bl, enum sc_type *type, int *rate, int *val1, int *val2, int *val3, int *val4, int *tick, int *flag) { if ( bl->type == BL_PC && retVal > 0 ) { ShowDebug( "PC" ); if ( *type == SC_BLESSING ) ShowDebug( "Yes" ); } return retVal;} void clif_party_info_pre(struct party_data* p, struct map_session_data *sd) { unsigned char buf[2+2+NAME_LENGTH+(4+NAME_LENGTH+MAP_NAME_LENGTH_EXT+1+1)*MAX_PARTY]; struct map_session_data* party_sd = NULL; int i, c; char aaa[NAME_LENGTH]; nullpo_retv(p); WBUFW(buf,0) = 0xfb; memcpy(WBUFP(buf,4), p->party.name, NAME_LENGTH); for (i = 0, c = 0; i < MAX_PARTY; i++) { struct party_member* m = &p->party.member; if(!m->account_id) continue; if(party_sd == NULL) party_sd = p->data.sd; WBUFL(buf,28+c*46) = m->account_id; safesnprintf( aaa, NAME_LENGTH, "[ASDF]%s", m->name ); memcpy(WBUFP(buf,28+c*46+4), aaa, NAME_LENGTH); mapindex->getmapname_ext(mapindex_id2name(m->map), (char*)WBUFP(buf,28+c*46+28)); WBUFB(buf,28+c*46+44) = (m->leader) ? 0 : 1; WBUFB(buf,28+c*46+45) = (m->online) ? 0 : 1; c++; } WBUFW(buf,2) = 28+c*46; if(sd) clif->send(buf, WBUFW(buf,2), &sd->bl, SELF); else if (party_sd) clif->send(buf, WBUFW(buf,2), &party_sd->bl, PARTY); hookStop(); return;} HPExport void plugin_init (void) { addHookPre( "clif->party_info", clif_party_info_pre ); addHookPost( "status->change_start", status_change_start_post );}@@cumbe11is it normal to show [ASDF]<name> in the chat log like this ?

screenRuru_Server019.jpg

EDIT:

@@Garr

I thought about that,

but Dastgir said just have to put clif_party_info function in status_change_start and status_change_end,

and it will update itself

 
Last edited by a moderator:
yup, currently look like this now

#include "common/hercules.h"

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "map/pc.h"
#include "map/clif.h"
#include "map/party.h"

#include "common/nullpo.h"
#include "common/socket.h"
#include "common/memmgr.h"
#include "common/HPMDataCheck.h" // should always be the last file included! (if you don't make it last, it'll intentionally break compile time)

HPExport struct hplugin_info pinfo = {
    "test123",    // Plugin name
    SERVER_TYPE_MAP,// Which server types this plugin works with?
    "0.0",            // Plugin version
    HPM_VERSION,    // HPM Version (don't change, macro is automatically updated)
};
struct player_data {
    int buff;
};

int status_change_start_post( int retVal, struct block_list *src, struct block_list *bl, enum sc_type *type, int *rate, int *val1, int *val2, int *val3, int *val4, int *tick, int *flag) {
    if ( bl->type == BL_PC && retVal > 0 ) {
        TBL_PC *sd = BL_CAST(BL_PC, bl);
        struct party_data *p;
        if ( p = party->search(sd->status.party_id )) {
            struct player_data *ssd = getFromMSD( sd, 0 );
            int before_buff = ssd->buff;
            if ( *type == SC_BLESSING )
                ssd->buff |= 0x1;
            if ( *type == SC_INC_AGI )
                ssd->buff |= 0x2;
            if ( *type == SC_PROTECTWEAPON || *type == SC_PROTECTSHIELD || *type == SC_PROTECTARMOR || *type == SC_PROTECTHELM )
                if ( sd->sc.data[SC_PROTECTWEAPON] && sd->sc.data[SC_PROTECTSHIELD] && sd->sc.data[SC_PROTECTARMOR] && sd->sc.data[SC_PROTECTHELM] )
                    ssd->buff |= 0x4;
            if ( *type == SC_SOULLINK )
                ssd->buff |= 0x8;
            if ( *type == SC_DEVOTION )
                ssd->buff |= 0x10;
            if ( before_buff != ssd->buff ) // only send the packet if update the status is newly apply, no need to resend if just renew the status
                clif->party_info( p, NULL );
        }
    }
    return retVal;
}

int status_change_end_post( int retVal, struct block_list *bl, enum sc_type *type, int *tid, const char *file, int *line ) {
    if ( bl->type == BL_PC && retVal > 0 ) {
        TBL_PC *sd = BL_CAST(BL_PC, bl);
        struct party_data *p;
        if ( sd->state.active == 1 ) { // fix map-server crash when player logout
        if (( p = party->search(sd->status.party_id ))) {
            struct player_data *ssd = getFromMSD( sd, 0 );
                int before_buff = ssd->buff;
                if ( *type == SC_BLESSING )
                    ssd->buff &= ~0x1;
                if ( *type == SC_INC_AGI )
                    ssd->buff &= ~0x2;
                if ( *type == SC_PROTECTWEAPON || *type == SC_PROTECTSHIELD || *type == SC_PROTECTARMOR || *type == SC_PROTECTHELM )
                    if ( sd->sc.data[SC_PROTECTWEAPON] && sd->sc.data[SC_PROTECTSHIELD] && sd->sc.data[SC_PROTECTARMOR] && sd->sc.data[SC_PROTECTHELM] )
                        ssd->buff &= ~0x4;
                if ( *type == SC_SOULLINK )
                    ssd->buff &= ~0x8;
                if ( *type == SC_DEVOTION )
                    ssd->buff &= ~0x10;
                if ( before_buff != ssd->buff ) // only send the packet if update the status is newly apply, no need to resend if just renew the status
                    clif->party_info( p, NULL );
            }
        }
    }
    return retVal;
}

void clif_party_info_overload( struct party_data* p, struct map_session_data *sd ) {
    unsigned char buf[2+2+NAME_LENGTH+(4+NAME_LENGTH+MAP_NAME_LENGTH_EXT+1+1)*MAX_PARTY];
    struct map_session_data* party_sd = NULL;
    int i, c;
    nullpo_retv(p);
    WBUFW(buf,0) = 0xfb;
    memcpy( WBUFP(buf,4), p->party.name, NAME_LENGTH );
    for ( i = 0, c = 0; i < MAX_PARTY; i++ ) {
        struct party_member* m = &p->party.member;
        if(!m->account_id) continue;
        if(party_sd == NULL) party_sd = p->data.sd;
        WBUFL(buf,28+c*46) = m->account_id;
        if ( m->online && p->data.sd != NULL ) {
            struct player_data *ssd = getFromMSD( p->data.sd, 0 );
            char temp[NAME_LENGTH];
            safesnprintf( temp, NAME_LENGTH, "[%s%s%s%s%s]%s",
                                                            ( ssd->buff & 0x1 )? "B" : "_",
                                                            ( ssd->buff & 0x2 )? "A" : "_",
                                                            ( ssd->buff & 0x4 )? "F" : "_",
                                                            ( ssd->buff & 0x8 )? "S" : "_",
                                                            ( ssd->buff & 0x10 )? "+" : "_",
                                                            m->name );
            memcpy(WBUFP(buf,28+c*46+4), temp, NAME_LENGTH);
        } else
            memcpy(WBUFP(buf,28+c*46+4), m->name, NAME_LENGTH);
        mapindex->getmapname_ext(mapindex_id2name(m->map), (char*)WBUFP(buf,28+c*46+28));
        WBUFB(buf,28+c*46+44) = (m->leader) ? 0 : 1;
        WBUFB(buf,28+c*46+45) = (m->online) ? 0 : 1;
        c++;
    }
    WBUFW(buf,2) = 28+c*46;
    if (sd)
        clif->send(buf, WBUFW(buf,2), &sd->bl, SELF);
    else if (party_sd)
        clif->send(buf, WBUFW(buf,2), &party_sd->bl, PARTY);
    return;
}
bool pc_authok_pre( struct map_session_data *sd, int *login_id2, time_t *expiration_time, int *group_id, struct mmo_charstatus *st, bool *changing_mapservers ) {
    struct player_data *ssd;
    CREATE( ssd, struct player_data, true );
    ssd->buff = 0;
    addToMSD( sd, ssd, 0, true );
    return 0;
}
int map_quit_post( int retVal, struct map_session_data *sd ) {
    struct player_data *ssd = getFromMSD( sd, 0 );
    removeFromMSD( sd, 0 );
    return retVal;
}

HPExport void plugin_init (void) {    addHookPre( "pc->authok", pc_authok_pre );
    addHookPost( "map->quit", map_quit_post );
    clif->party_info = &clif_party_info_overload;
    addHookPost( "status->change_start", status_change_start_post );
    addHookPost( "status->change_end_", status_change_end_post );
}
there is a bug, when the player JUST login for the 1st time in that party ( party just loaded )
your name will appear twice in the party window
screenRuru_Server021.jpg
but will disappear when apply a buff ... or another party member login

and, when apply a buff, it really does show the [b____] for the party member name
screenRuru_Server020.jpg

I guess, have to do something like @showbuff atcommand, to make this bug disappear
it also has the advantage to show it or not to show it
... and this is harder to do than I thought
try continue tomorrow, I have to sleep now =.=

 
Last edited by a moderator:
@@Dastgir can you adapt this too on ur hercules plugin collection please? and check the bugs that annies talking about.

Edit: In chat log, they will have normal name, just party window will be edited.
and this
default_biggrin.png


 
Last edited by a moderator:
there is a bug, when the player JUST login for the 1st time in that party ( party just loaded )

your name will appear twice in the party window
Also we can see this bug, when someone enters to the party.
 
It is caused by sending of 0x1E9 packet, which adds one specific party member to the list on the client side.
 
To fix bug of this plugin, we can disable sending of this packet.
 
Because in any case server always sends full list of party members in 0xFB packet.
before:

HPExport void plugin_init (void) {

add:

void clif_party_member_info_overload(struct party_data* p, struct map_session_data* sd)
{
return;
}


after:

HPExport void plugin_init (void) {

add:

Code:
clif->party_member_info = &clif_party_member_info_overload;
 
Last edited by a moderator:
http://upaste.me/aa5e49917485b4900

I need some people to comment on my script
I just bam bam and google here and there and it works on VS2015, but not sure if it is work on others though

1. need help how to really optimize this code
2.not really sure about using this kind of function

Code:
char *showing_buff( struct map_session_data *sd ) {
@meko

@4144

http://upaste.me/75d049918e2088402

no idea how I get this error message, only pop up once

Code:
[Error]: --- nullpo info --------------------------------------------
[Error]: ..\src\plugins\showbuff.c:115: 'p' in function `unknown'
[Error]: --- end nullpo info ----------------------------------------
@xVec

 
Last edited by a moderator:
in ACMD(showbuff) in line 275 you show error message and p is NULL, and after call clif->party_info(p), this call your overloaded function clif_party_info_overload, and here it validate parameter for NULL and show error message.

 
Back
Top