Compare commits

...

4 Commits

Author SHA1 Message Date
Atemo
30a33ac7b5
Apply suggestions from code review
Co-authored-by: Aleos <aleos89@users.noreply.github.com>
2024-06-14 21:28:14 +02:00
Atemo
aceeb97126 Added support for sc_display on BL_HOM, BL_MER, BL_ELEM, BL_PET 2024-06-13 16:15:07 +02:00
Atemo
da034f11d9 Corrected status_display_add val1, val2, val3
Corrected the docs
2024-06-09 01:13:02 +02:00
Atemo
89327d2b67 Clean-up sc_display
* Statuses can now also be saved for monsters
* Updated the status.txt docs
* Added missing BL_NPC to BL_SCEFFECT
* Corrected conditions for saving statuses depending on the unit type affected
* Corrected conditions for displaying status depending on the unit type affected when the status is given
2024-06-09 00:57:33 +02:00
12 changed files with 62 additions and 253 deletions

View File

@ -6076,6 +6076,7 @@ Body:
NoBanishingBuster: true
NoClearance: true
NoForcedEnd: true
SendVal1: true
EndReturn:
All_Riding: true
- Status: Teargas_Sob

View File

@ -196,9 +196,14 @@ Options: Special option/client effect state when status is active.
Flags: Various status flags for specific status change events.
None - No special flag. (Default)
BlEffect - Status should have BL_SCEFFECT as relevant effect, must have an EFST (displays on BL_PC, BL_HOM, BL_MER, BL_MOB, BL_ELEM). BL_PC is the default value.
DisplayPc - Displays status effect when player logs in.
DislpayNpc - Displays status effect on a NPC.
BlEffect - Flag to send a visual effect to clients around if the affected unit is BL_PC, BL_HOM, BL_MER, BL_MOB, BL_ELEM or BL_NPC when the status is given.
The status must have an EFST defined in Icon - other than EFST_BLANK.
When not defined (default) the status is displayed to clients around when the affected unit is BL_PC (player) only.
DisplayPc - Whether the status is displayed (again) to client around when the affected unit (BL_PC) appears in the client's range.
DisplayNpc - Whether the status is displayed (again) to client around when the affected unit (BL_NPC) appears in the client's range.
DisplayMob - Whether the status is displayed (again) to client around when the affected unit (BL_MOB) appears in the client's range.
DisplayAll - Whether the status is displayed (again) to client around when the affected unit (BL_PC, BL_HOM, BL_MER, BL_MOB, BL_ELEM, BL_NPC or BL_PET) appears in the client's range.
When defined, other display flags are ignored.
Debuff - Status is considered a debuff. Used in combination with 'battle_config.debuff_on_logout'.
SetStand - Sets player to standing state.
OverlapIgnoreLevel - The status will successfully activate for any level if the status is already active.
@ -208,9 +213,9 @@ Flags: Various status flags for specific status change events.
MobLoseTarget - When active on a monster it will lose the target.
RestartOnMapWarp - Restarts the timer of a status when warping to another map.
SpreadEffect - Passes the status onto a target when SC_DEADLYINFECT is active.
SendVal1 - Notifies the client of a status change (val1).
SendVal2 - Notifies the client of a status change (val2).
SendVal3 - Notifies the client of a status change (val3).
SendVal1 - Whether val1 shouldn't be ignored.
SendVal2 - Whether val2 shouldn't be ignored.
SendVal3 - Whether val3 shouldn't be ignored.
NoClearbuff - Cannot be removed by 'status_change_clear_buffs()', 'sc_end SC_ALL', 'status_change_clear(3)', etc.
NoForcedEnd - Cannot be removed by sc_end.

View File

@ -1721,7 +1721,7 @@ int clif_spawn( struct block_list *bl, bool walking ){
clif_spiritcharm(sd);
if (sd->status.robe)
clif_refreshlook(bl,bl->id,LOOK_ROBE,sd->status.robe,AREA);
clif_efst_status_change_sub(bl, bl, AREA);
clif_efst_status_change_sub( *bl, *bl, AREA, !sd->state.connect_new );
clif_hat_effects( *sd, sd->bl, AREA );
}
break;
@ -1734,6 +1734,7 @@ int clif_spawn( struct block_list *bl, bool walking ){
clif_specialeffect(&md->bl,EF_BABYBODY2,AREA);
if ( md->special_state.ai == AI_ABR || md->special_state.ai == AI_BIONIC )
clif_summon_init(*md);
clif_efst_status_change_sub( *bl, *bl, AREA_WOS );
}
break;
case BL_NPC:
@ -1743,13 +1744,18 @@ int clif_spawn( struct block_list *bl, bool walking ){
clif_specialeffect(&nd->bl,EF_GIANTBODY2,AREA);
else if( nd->size == SZ_MEDIUM )
clif_specialeffect(&nd->bl,EF_BABYBODY2,AREA);
clif_efst_status_change_sub(bl, bl, AREA);
clif_efst_status_change_sub( *bl, *bl, AREA_WOS );
clif_progressbar_npc_area(nd);
}
break;
case BL_PET:
if (vd->head_bottom)
clif_pet_equip_area((TBL_PET*)bl); // needed to display pet equip properly
[[fallthrough]];
case BL_HOM:
case BL_MER:
case BL_ELEM:
clif_efst_status_change_sub( *bl, *bl, AREA_WOS );
break;
}
return 0;
@ -5062,7 +5068,7 @@ void clif_getareachar_unit( map_session_data* sd,struct block_list *bl ){
clif_sendbgemblem_single(sd->fd,tsd);
if ( tsd->status.robe )
clif_refreshlook(&sd->bl,bl->id,LOOK_ROBE,tsd->status.robe,SELF);
clif_efst_status_change_sub(&sd->bl, bl, SELF);
clif_efst_status_change_sub( sd->bl, *bl, SELF, !sd->state.connect_new );
clif_hat_effects( *sd, tsd->bl, SELF );
}
break;
@ -5079,7 +5085,7 @@ void clif_getareachar_unit( map_session_data* sd,struct block_list *bl ){
clif_specialeffect_single(bl,EF_GIANTBODY2,sd->fd);
else if( nd->size == SZ_MEDIUM )
clif_specialeffect_single(bl,EF_BABYBODY2,sd->fd);
clif_efst_status_change_sub(&sd->bl, bl, SELF);
clif_efst_status_change_sub( sd->bl, *bl, SELF );
clif_progressbar_npc(nd, sd);
}
break;
@ -5098,11 +5104,16 @@ void clif_getareachar_unit( map_session_data* sd,struct block_list *bl ){
clif_monster_hp_bar(md, sd->fd);
}
#endif
clif_efst_status_change_sub( sd->bl, *bl, SELF );
}
break;
case BL_PET:
if (vd->head_bottom)
clif_pet_equip(sd, (TBL_PET*)bl); // needed to display pet equip properly
[[fallthrough]];
case BL_HOM:
case BL_ELEM:
clif_efst_status_change_sub( sd->bl, *bl, SELF );
break;
}
}
@ -6553,42 +6564,23 @@ void clif_status_change(struct block_list *bl, int type, int flag, t_tick tick,
* @param bl: Objects walking into view
* @param target: Client send type
*/
void clif_efst_status_change_sub(struct block_list *tbl, struct block_list *bl, enum send_target target) {
unsigned char i;
struct sc_display_entry **sc_display;
unsigned char sc_display_count;
bool spheres_sent;
void clif_efst_status_change_sub( block_list& tbl, block_list& src, enum send_target target, bool spheres_sent ){
status_change *sc = status_get_sc( &src );
nullpo_retv(bl);
if (sc == nullptr || sc->sc_display.empty())
return;
switch( bl->type ){
case BL_PC: {
map_session_data* sd = (map_session_data*)bl;
for ( const auto &type : sc->sc_display ) {
struct status_change_entry* sce = sc->getSCE(type);
std::shared_ptr<s_status_change_db> scdb = status_db.find(type);
sc_display = sd->sc_display;
sc_display_count = sd->sc_display_count;
spheres_sent = !sd->state.connect_new;
}
break;
case BL_NPC: {
struct npc_data* nd = (struct npc_data*)bl;
if (sce == nullptr || scdb == nullptr)
continue;
sc_display = nd->sc_display;
sc_display_count = nd->sc_display_count;
spheres_sent = true;
}
break;
default:
return;
}
for (i = 0; i < sc_display_count; i++) {
enum sc_type type = sc_display[i]->type;
status_change *sc = status_get_sc(bl);
const struct TimerData *td = (sc && sc->getSCE(type) ? get_timer(sc->getSCE(type)->timer) : nullptr);
const struct TimerData *td = get_timer(sc->getSCE(type)->timer);
t_tick tick = 0;
if (td)
if (td != nullptr)
tick = DIFF_TICK(td->tick, gettick());
// Status changes that need special handling
@ -6599,20 +6591,23 @@ void clif_efst_status_change_sub(struct block_list *tbl, struct block_list *bl,
case SC_SPHERE_4:
case SC_SPHERE_5:
if( spheres_sent ){
target = AREA_WOS;
target = AREA_WOS; // area without self
// check me : target should stay AREA_WOS ?
}
break;
case SC_HELLS_PLANT:
if( sc && sc->getSCE(type) ){
tick = sc->getSCE(type)->val4;
}
tick = sce->val4;
break;
}
int dval1 = scdb->flag[SCF_SENDVAL1] ? sce->val1 : 0;
int dval2 = scdb->flag[SCF_SENDVAL2] ? sce->val2 : 0;
int dval3 = scdb->flag[SCF_SENDVAL3] ? sce->val3 : 0;
#if PACKETVER > 20120418
clif_efst_status_change(tbl, bl->id, target, status_db.getIcon(type), tick, sc_display[i]->val1, sc_display[i]->val2, sc_display[i]->val3);
clif_efst_status_change( &tbl, src.id, target, status_db.getIcon(type), tick, dval1, dval2, dval3 );
#else
clif_status_change_sub(tbl, bl->id, status_db.getIcon(type), 1, tick, sc_display[i]->val1, sc_display[i]->val2, sc_display[i]->val3, target);
clif_status_change_sub( &tbl, src.id, status_db.getIcon(type), 1, tick, dval1, dval2, dval3, target );
#endif
}
}
@ -9882,7 +9877,7 @@ void clif_refresh(map_session_data *sd)
clif_clearunit_single( sd->bl.id, CLR_DEAD, *sd );
else
clif_changed_dir(&sd->bl, SELF);
clif_efst_status_change_sub(&sd->bl,&sd->bl,SELF);
clif_efst_status_change_sub( sd->bl, sd->bl, SELF, !sd->state.connect_new );
//Issue #2143
//Cancel Trading State

View File

@ -947,7 +947,7 @@ void clif_changemapcell(int fd, int16 m, int x, int y, int type, enum send_targe
#define clif_status_load(bl, type, flag) clif_status_change((bl), (type), (flag), 0, 0, 0, 0)
void clif_status_change(struct block_list *bl, int type, int flag, t_tick tick, int val1, int val2, int val3);
void clif_efst_status_change(struct block_list *bl, int tid, enum send_target target, int type, t_tick tick, int val1, int val2, int val3);
void clif_efst_status_change_sub(struct block_list *tbl, struct block_list *bl, enum send_target target);
void clif_efst_status_change_sub( block_list& tbl, block_list& src, enum send_target target, bool spheres_sent = true );
void clif_wis_message(map_session_data* sd, const char* nick, const char* mes, size_t mes_len, int gmlvl);
void clif_wis_end( map_session_data& sd, e_ack_whisper result );

View File

@ -50,8 +50,6 @@ static int npc_mob=0;
static int npc_delay_mob=0;
static int npc_cache_mob=0;
struct eri *npc_sc_display_ers;
// Market Shop
#if PACKETVER >= 20131223
struct s_npc_market {
@ -3527,15 +3525,6 @@ int npc_unload(struct npc_data* nd, bool single) {
}
if( nd->u.scr.guild_id )
guild_flag_remove(nd);
if( nd->sc_display_count ){
unsigned char i;
for( i = 0; i < nd->sc_display_count; i++ )
ers_free(npc_sc_display_ers, nd->sc_display[i]);
nd->sc_display_count = 0;
aFree(nd->sc_display);
nd->sc_display = nullptr;
}
}
nd->qi_data.clear();
@ -3772,8 +3761,6 @@ struct npc_data *npc_create_npc(int16 m, int16 x, int16 y){
nd->bl.m = m;
nd->bl.x = x;
nd->bl.y = y;
nd->sc_display = nullptr;
nd->sc_display_count = 0;
nd->progressbar.timeout = 0;
nd->vd = npc_viewdb[0]; // Default to JT_INVISIBLE
nd->dynamicnpc.owner_char_id = 0;
@ -6146,7 +6133,6 @@ void do_final_npc(void) {
stylist_db.clear();
barter_db.clear();
ers_destroy(timer_event_ers);
ers_destroy(npc_sc_display_ers);
npc_src_files.clear();
}
@ -6212,7 +6198,6 @@ void do_init_npc(void){
#endif
timer_event_ers = ers_new(sizeof(struct timer_event_data),"npc.cpp::timer_event_ers",ERS_OPT_NONE);
npc_sc_display_ers = ers_new(sizeof(struct sc_display_entry), "npc.cpp:npc_sc_display_ers", ERS_OPT_NONE);
npc_loadsrcfiles();

View File

@ -216,9 +216,6 @@ struct npc_data {
} barter;
} u;
struct sc_display_entry **sc_display;
unsigned char sc_display_count;
std::vector<std::shared_ptr<s_questinfo>> qi_data;
struct {
@ -239,9 +236,6 @@ struct npc_data {
bool is_invisible;
};
struct eri;
extern struct eri *npc_sc_display_ers;
#define START_NPC_NUM 110000000
enum e_job_types

View File

@ -84,7 +84,6 @@ SkillTreeDatabase skill_tree_db;
int day_timer_tid = INVALID_TIMER;
int night_timer_tid = INVALID_TIMER;
struct eri *pc_sc_display_ers = nullptr;
struct eri *num_reg_ers;
struct eri *str_reg_ers;
int pc_expiration_tid = INVALID_TIMER;
@ -2209,10 +2208,6 @@ bool pc_authok(map_session_data *sd, uint32 login_id2, time_t expiration_time, i
pc_validate_skill(sd);
/* [Ind] */
sd->sc_display = nullptr;
sd->sc_display_count = 0;
// Player has not yet received the CashShop list
sd->status.cashshop_sent = false;
@ -15847,7 +15842,6 @@ void do_final_pc(void) {
db_destroy(itemcd_db);
do_final_pc_groups();
ers_destroy(pc_sc_display_ers);
ers_destroy(num_reg_ers);
ers_destroy(str_reg_ers);
@ -15906,11 +15900,9 @@ void do_init_pc(void) {
do_init_pc_groups();
pc_sc_display_ers = ers_new(sizeof(struct sc_display_entry), "pc.cpp:pc_sc_display_ers", ERS_OPT_FLEX_CHUNK);
num_reg_ers = ers_new(sizeof(struct script_reg_num), "pc.cpp:num_reg_ers", (ERSOptions)(ERS_OPT_CLEAN|ERS_OPT_FLEX_CHUNK));
str_reg_ers = ers_new(sizeof(struct script_reg_str), "pc.cpp:str_reg_ers", (ERSOptions)(ERS_OPT_CLEAN|ERS_OPT_FLEX_CHUNK));
ers_chunk_size(pc_sc_display_ers, 150);
ers_chunk_size(num_reg_ers, 300);
ers_chunk_size(str_reg_ers, 50);
}

View File

@ -863,10 +863,6 @@ public:
unsigned char fontcolor;
t_tick *channel_tick;
/* [Ind] */
struct sc_display_entry **sc_display;
unsigned char sc_display_count;
unsigned char delayed_damage; //[Ind]
/**
@ -944,7 +940,6 @@ public:
std::vector<uint32> party_booking_requests;
};
extern struct eri *pc_sc_display_ers; /// Player's SC display table
/**
* ERS for the bulk of pc vars

View File

@ -11230,6 +11230,8 @@
export_constant(SCF_REMOVEONUNEQUIPARMOR);
export_constant(SCF_REMOVEONHERMODE);
export_constant(SCF_REQUIRENOWEAPON);
export_constant(SCF_DISPLAYMOB);
export_constant(SCF_DISPLAYALL);
/* enchantgrades */
export_constant(ENCHANTGRADE_NONE);

View File

@ -9821,139 +9821,6 @@ t_tick status_get_sc_def(struct block_list *src, struct block_list *bl, enum sc_
return i64max(tick, scdb->min_duration);
}
/**
* Applies SC effect
* @param bl: Source to apply effect
* @param type: Status change (SC_*)
* @param dval1~3: Depends on type of status change
* Author: Ind
*/
void status_display_add(struct block_list *bl, enum sc_type type, int dval1, int dval2, int dval3) {
struct eri *eri;
struct sc_display_entry **sc_display;
struct sc_display_entry ***sc_display_ptr;
struct sc_display_entry *entry;
int i;
unsigned char sc_display_count;
unsigned char *sc_display_count_ptr;
nullpo_retv(bl);
switch( bl->type ){
case BL_PC: {
map_session_data* sd = (map_session_data*)bl;
sc_display_ptr = &sd->sc_display;
sc_display_count_ptr = &sd->sc_display_count;
eri = pc_sc_display_ers;
}
break;
case BL_NPC: {
struct npc_data* nd = (struct npc_data*)bl;
sc_display_ptr = &nd->sc_display;
sc_display_count_ptr = &nd->sc_display_count;
eri = npc_sc_display_ers;
}
break;
default:
return;
}
sc_display = *sc_display_ptr;
sc_display_count = *sc_display_count_ptr;
ARR_FIND(0, sc_display_count, i, sc_display[i]->type == type);
if( i != sc_display_count ) {
sc_display[i]->val1 = dval1;
sc_display[i]->val2 = dval2;
sc_display[i]->val3 = dval3;
return;
}
entry = ers_alloc(eri, struct sc_display_entry);
entry->type = type;
entry->val1 = dval1;
entry->val2 = dval2;
entry->val3 = dval3;
RECREATE(sc_display, struct sc_display_entry *, ++sc_display_count);
sc_display[sc_display_count - 1] = entry;
*sc_display_ptr = sc_display;
*sc_display_count_ptr = sc_display_count;
}
/**
* Removes SC effect
* @param bl: Source to remove effect
* @param type: Status change (SC_*)
* Author: Ind
*/
void status_display_remove(struct block_list *bl, enum sc_type type) {
struct eri *eri;
struct sc_display_entry **sc_display;
struct sc_display_entry ***sc_display_ptr;
int i;
unsigned char sc_display_count;
unsigned char *sc_display_count_ptr;
nullpo_retv(bl);
switch( bl->type ){
case BL_PC: {
map_session_data* sd = (map_session_data*)bl;
sc_display_ptr = &sd->sc_display;
sc_display_count_ptr = &sd->sc_display_count;
eri = pc_sc_display_ers;
}
break;
case BL_NPC: {
struct npc_data* nd = (struct npc_data*)bl;
sc_display_ptr = &nd->sc_display;
sc_display_count_ptr = &nd->sc_display_count;
eri = npc_sc_display_ers;
}
break;
default:
return;
}
sc_display = *sc_display_ptr;
sc_display_count = *sc_display_count_ptr;
ARR_FIND(0, sc_display_count, i, sc_display[i]->type == type);
if( i != sc_display_count ) {
int cursor;
ers_free(eri, sc_display[i]);
sc_display[i] = nullptr;
/* The all-mighty compact-o-matic */
for( i = 0, cursor = 0; i < sc_display_count; i++ ) {
if( sc_display[i] == nullptr )
continue;
if( i != cursor )
sc_display[cursor] = sc_display[i];
cursor++;
}
if( !(sc_display_count = cursor) ) {
aFree(sc_display);
sc_display = nullptr;
}
*sc_display_ptr = sc_display;
*sc_display_count_ptr = sc_display_count;
}
}
/**
* Applies SC defense to a given status change
* This function also determines whether or not the status change will be applied
@ -12831,24 +12698,10 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
return 0;
}
/* [Ind] */
if (scdb->flag[SCF_DISPLAYPC] || scdb->flag[SCF_DISPLAYNPC]) {
int dval1 = 0, dval2 = 0, dval3 = 0;
switch (type) {
case SC_ALL_RIDING:
dval1 = 1;
break;
case SC_CLAN_INFO:
dval1 = val1;
dval2 = val2;
dval3 = val3;
break;
default: /* All others: just copy val1 */
dval1 = val1;
break;
}
status_display_add(bl,type,dval1,dval2,dval3);
// Save sc to display it again later
if (scdb->flag[SCF_DISPLAYALL] || (scdb->flag[SCF_DISPLAYPC] && bl->type == BL_PC || scdb->flag[SCF_DISPLAYNPC] && bl->type == BL_NPC || scdb->flag[SCF_DISPLAYMOB] && bl->type == BL_MOB)) {
if (!util::vector_exists(sc->sc_display, type))
sc->sc_display.push_back(type);
}
//SC that force player to stand if is sitting
@ -12935,7 +12788,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
calc_flag.reset(SCB_BODY);
}*/
if (!(flag&SCSTART_NOICON) && !(flag&SCSTART_LOADED && scdb->flag[SCF_DISPLAYPC] || scdb->flag[SCF_DISPLAYNPC])) {
if (!(flag&SCSTART_NOICON) && !(flag&SCSTART_LOADED)) {
int status_icon = scdb->icon;
#if PACKETVER < 20151104
@ -13252,8 +13105,8 @@ int status_change_end(struct block_list* bl, enum sc_type type, int tid)
sc->clearSCE(type);
if (scdb->flag[SCF_DISPLAYPC] || scdb->flag[SCF_DISPLAYNPC])
status_display_remove(bl,type);
if (scdb->flag[SCF_DISPLAYALL] || (scdb->flag[SCF_DISPLAYPC] && bl->type == BL_PC || scdb->flag[SCF_DISPLAYNPC] && bl->type == BL_NPC || scdb->flag[SCF_DISPLAYMOB] && bl->type == BL_MOB))
util::vector_erase_if_exists(sc->sc_display, type);
vd = status_get_viewdata(bl);
std::bitset<SCB_MAX> calc_flag = scdb->calc_flag;

View File

@ -3057,6 +3057,8 @@ enum e_status_change_flag : uint16 {
SCF_REMOVEONUNEQUIPARMOR,
SCF_REMOVEONHERMODE,
SCF_REQUIRENOWEAPON,
SCF_DISPLAYMOB,
SCF_DISPLAYALL,
SCF_MAX
};
@ -3140,7 +3142,7 @@ enum e_refine_chance_type {
///Define to determine who has regen
#define BL_REGEN (BL_PC|BL_HOM|BL_MER|BL_ELEM)
///Define to determine who will receive a clif_status_change packet for effects that require one to display correctly
#define BL_SCEFFECT (BL_PC|BL_HOM|BL_MER|BL_MOB|BL_ELEM)
#define BL_SCEFFECT (BL_PC|BL_HOM|BL_MER|BL_MOB|BL_ELEM|BL_NPC|BL_PET)
/** Basic damage info of a weapon
* Required because players have two of these, one in status_data
@ -3241,12 +3243,6 @@ struct regen_data {
struct regen_data_sub *sregen, *ssregen;
};
///Status display entry
struct sc_display_entry {
enum sc_type type;
int val1, val2, val3;
};
///Status change entry
struct status_change_entry {
int timer;
@ -3280,6 +3276,7 @@ public:
} cant;/* status change state flags */
//int sg_id; //ID of the previous Storm gust that hit you
short comet_x, comet_y; // Point where src casted Comet - required to calculate damage from this point
std::vector<sc_type> sc_display;
/**
* The Storm Gust counter was dropped in renewal
**/

View File

@ -3439,7 +3439,6 @@ int unit_free(struct block_list *bl, clr_type clrtype)
switch( bl->type ) {
case BL_PC: {
map_session_data *sd = (map_session_data*)bl;
int i;
if( status_isdead(bl) )
pc_setrestartvalue(sd,2);
@ -3495,15 +3494,6 @@ int unit_free(struct block_list *bl, clr_type clrtype)
sd->combos.clear();
if( sd->sc_display_count ) { /* [Ind] */
for( i = 0; i < sd->sc_display_count; i++ )
ers_free(pc_sc_display_ers, sd->sc_display[i]);
sd->sc_display_count = 0;
aFree(sd->sc_display);
sd->sc_display = nullptr;
}
if( sd->quest_log != nullptr ) {
aFree(sd->quest_log);
sd->quest_log = nullptr;