Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions src/map/map.c
Original file line number Diff line number Diff line change
Expand Up @@ -5764,6 +5764,24 @@ static bool map_zone_mf_cache(int m, char *flag, char *params)
map_zone_mf_cache_add(m, rflag);
}
}
} else if (strcmpi(flag, "noviewid") == 0) {
if (state && map->list[m].flag.noviewid == (uint32)strtoull(params, NULL, 0)) {
/* nothing to do */
} else {
sprintf(rflag, "noviewid\t%u", map->list[m].flag.noviewid);
map_zone_mf_cache_add(m, rflag);
}
} else if (strcmpi(flag, "src4instance") == 0) {
if (state && map->list[m].flag.src4instance)
;/* nothing to do */
else {
if (state)
map_zone_mf_cache_add(m, "src4instance\toff");
else if (map->list[m].flag.src4instance)
map_zone_mf_cache_add(m, "src4instance");
}
} else {
ShowError("map_zone_mf_cache: unsupported flag '%s' in '%s'\n", flag, map->list[m].name);
}

return false;
Expand Down
251 changes: 170 additions & 81 deletions src/map/pc.c
Original file line number Diff line number Diff line change
Expand Up @@ -6384,7 +6384,7 @@ static int pc_checkequip(struct map_session_data *sd, int pos)
nullpo_retr(-1, sd);

for(i=0;i<EQI_MAX;i++){
if(pos & pc->equip_pos[i])
if ((pos & pc->equip_pos[i]) != 0 && sd->equip_index[i] != -1)
return sd->equip_index[i];
}

Expand Down Expand Up @@ -10060,6 +10060,38 @@ static int pc_load_combo(struct map_session_data *sd)
return ret;
}

/**
* Returns the position mask overlapping (costume vs regular equipment) with
* the given equip's position mask.
*
* @param pos The equip position mask to check.
* @return The overlapping position mask.
*/
static uint32 pc_equip_costume_overlap(uint32 pos)
{
uint32 ret = EQP_NONE;

if ((pos & EQP_HEAD_TOP) != 0)
ret |= EQP_COSTUME_HEAD_TOP;
if ((pos & EQP_HEAD_MID) != 0)
ret |= EQP_COSTUME_HEAD_MID;
if ((pos & EQP_HEAD_LOW) != 0)
ret |= EQP_COSTUME_HEAD_LOW;
if ((pos & EQP_GARMENT) != 0)
ret |= EQP_COSTUME_GARMENT;

if ((pos & EQP_COSTUME_HEAD_TOP) != 0)
ret |= EQP_HEAD_TOP;
if ((pos & EQP_COSTUME_HEAD_MID) != 0)
ret |= EQP_HEAD_MID;
if ((pos & EQP_COSTUME_HEAD_LOW) != 0)
ret |= EQP_HEAD_LOW;
if ((pos & EQP_COSTUME_GARMENT) != 0)
ret |= EQP_GARMENT;

return ret;
}

/**
* Equip item at given position.
* @param sd the affected player structure. Must be checked before.
Expand Down Expand Up @@ -10104,60 +10136,93 @@ static void pc_equipitem_pos(struct map_session_data *sd, struct item_data *id,
}
//Added check to prevent sending the same look on multiple slots ->
//causes client to redraw item on top of itself. (suggested by Lupus)
if (!map_no_view(sd->bl.m,EQP_HEAD_LOW) && pos & EQP_HEAD_LOW && pc->checkequip(sd,EQP_COSTUME_HEAD_LOW) == -1) {
if (id && !(pos&(EQP_HEAD_TOP|EQP_HEAD_MID)))
sd->status.look.head_bottom = id->view_sprite;
else
sd->status.look.head_bottom = 0;
clif->changelook(&sd->bl, LOOK_HEAD_BOTTOM, sd->status.look.head_bottom);
}
if (!map_no_view(sd->bl.m,EQP_HEAD_TOP) && pos & EQP_HEAD_TOP && pc->checkequip(sd,EQP_COSTUME_HEAD_TOP) == -1) {
if (id)
sd->status.look.head_top = id->view_sprite;
else
sd->status.look.head_top = 0;
clif->changelook(&sd->bl, LOOK_HEAD_TOP, sd->status.look.head_top);
}
if (!map_no_view(sd->bl.m,EQP_HEAD_MID) && pos & EQP_HEAD_MID && pc->checkequip(sd,EQP_COSTUME_HEAD_MID) == -1) {
if (id && !(pos&EQP_HEAD_TOP))
sd->status.look.head_mid = id->view_sprite;
else
sd->status.look.head_mid = 0;
clif->changelook(&sd->bl, LOOK_HEAD_MID, sd->status.look.head_mid);
}
if (!map_no_view(sd->bl.m,EQP_COSTUME_HEAD_TOP) && pos & EQP_COSTUME_HEAD_TOP) {
if (id){
sd->status.look.head_top = id->view_sprite;
} else
sd->status.look.head_top = 0;
clif->changelook(&sd->bl, LOOK_HEAD_TOP, sd->status.look.head_top);
}
if (!map_no_view(sd->bl.m,EQP_COSTUME_HEAD_MID) && pos & EQP_COSTUME_HEAD_MID) {
if(id && !(pos&EQP_HEAD_TOP)){
sd->status.look.head_mid = id->view_sprite;
} else
sd->status.look.head_mid = 0;
clif->changelook(&sd->bl, LOOK_HEAD_MID, sd->status.look.head_mid);
}
if (!map_no_view(sd->bl.m,EQP_COSTUME_HEAD_LOW) && pos & EQP_COSTUME_HEAD_LOW) {
if (id && !(pos&(EQP_HEAD_TOP|EQP_HEAD_MID))){
sd->status.look.head_bottom = id->view_sprite;
} else
sd->status.look.head_bottom = 0;
clif->changelook(&sd->bl, LOOK_HEAD_BOTTOM, sd->status.look.head_bottom);
if ((pos & EQP_VISIBLE) != 0 && !map_no_view(sd->bl.m, pos)) {
struct {
int head_top, head_mid, head_bottom, robe;
} old_view = { sd->status.look.head_top, sd->status.look.head_mid, sd->status.look.head_bottom, sd->status.look.robe };
uint32 overlap_mask = pc->equip_costume_overlap(pos);
if (itemdb_is_costumeequip(pos)) {
if (pc->checkequip(sd, overlap_mask) != -1) {
for (int i = 0; i < EQI_MAX; i++) {
int index = sd->equip_index[i];
if (index == n)
continue;
if ((pc->equip_pos[i] & overlap_mask) == 0)
continue;
if (sd->equip_index[i] == -1)
continue;

/*
* Unset the view ids related to the overlapping non-costume items,
* if it extends to other slots that don't have a costume in them
*/
if ((sd->inventory_data[index]->equip & EQP_HEAD_TOP) != 0
&& ((pos & EQP_COSTUME_HEAD_TOP) != 0 || pc->checkequip(sd, EQP_COSTUME_HEAD_TOP) == -1)
) {
sd->status.look.head_top = 0;
}
if ((sd->inventory_data[index]->equip & EQP_HEAD_MID) != 0
&& ((pos & EQP_COSTUME_HEAD_MID) != 0 || pc->checkequip(sd, EQP_COSTUME_HEAD_MID) == -1)
) {
sd->status.look.head_mid = 0;
}
if ((sd->inventory_data[index]->equip & EQP_HEAD_LOW) != 0
&& ((pos & EQP_COSTUME_HEAD_LOW) != 0 || pc->checkequip(sd, EQP_COSTUME_HEAD_LOW) == -1)
) {
sd->status.look.head_bottom = 0;
}
if ((sd->inventory_data[index]->equip & EQP_GARMENT) != 0
&& ((pos & EQP_COSTUME_GARMENT) != 0 || pc->checkequip(sd, EQP_COSTUME_GARMENT) == -1)
) {
sd->status.look.robe = 0;
}
}
}
// Overwrite with the costume's
if ((pos & EQP_COSTUME_HEAD_TOP) != 0) {
sd->status.look.head_top = id->view_sprite;
} else if ((pos & EQP_COSTUME_HEAD_MID) != 0) {
// Ignored if EQP_COSTUME_HEAD_TOP is also set
sd->status.look.head_mid = id->view_sprite;
} else if ((pos & EQP_COSTUME_HEAD_LOW) != 0) {
// Ignored if EQP_COSTUME_HEAD_TOP or EQP_COSTUME_HEAD_MID are also set
sd->status.look.head_bottom = id->view_sprite;
}

if ((pos & EQP_COSTUME_GARMENT) != 0) {
sd->status.look.robe = id->view_sprite;
}
} else {
overlap_mask &= ~map->list[sd->bl.m].flag.noviewid;
if (pc->checkequip(sd, overlap_mask) == -1) {
// Only apply if there isn't a costume that would partly cover the item
if ((pos & EQP_HEAD_TOP) != 0) {
sd->status.look.head_top = id->view_sprite;
} else if ((pos & EQP_HEAD_MID) != 0) {
// Ignored if EQP_HEAD_TOP is also set
sd->status.look.head_mid = id->view_sprite;
} else if ((pos & EQP_HEAD_LOW) != 0) {
// Ignored if EQP_HEAD_TOP or EQP_HEAD_MID are also set
sd->status.look.head_bottom = id->view_sprite;
}

if ((pos & EQP_GARMENT) != 0) {
sd->status.look.robe = id->view_sprite;
}
}
}
if (old_view.head_top != sd->status.look.head_top)
clif->changelook(&sd->bl, LOOK_HEAD_TOP, sd->status.look.head_top);
if (old_view.head_mid != sd->status.look.head_mid)
clif->changelook(&sd->bl, LOOK_HEAD_MID, sd->status.look.head_mid);
if (old_view.head_bottom != sd->status.look.head_bottom)
clif->changelook(&sd->bl, LOOK_HEAD_BOTTOM, sd->status.look.head_bottom);
if (old_view.robe != sd->status.look.robe)
clif->changelook(&sd->bl, LOOK_ROBE, sd->status.look.robe);
}

if (!map_no_view(sd->bl.m,EQP_SHOES) && pos & EQP_SHOES)
clif->changelook(&sd->bl,LOOK_SHOES,0);
if (!map_no_view(sd->bl.m,EQP_GARMENT) && pos&EQP_GARMENT && pc->checkequip(sd,EQP_COSTUME_GARMENT) == -1) {
sd->status.look.robe = id ? id->view_sprite : 0;
clif->changelook(&sd->bl, LOOK_ROBE, sd->status.look.robe);
}

if (!map_no_view(sd->bl.m,EQP_COSTUME_GARMENT) && pos & EQP_COSTUME_GARMENT) {
sd->status.look.robe = id ? id->view_sprite : 0;
clif->changelook(&sd->bl, LOOK_ROBE, sd->status.look.robe);
}
}

/**
Expand Down Expand Up @@ -10322,6 +10387,40 @@ static int pc_equipitem(struct map_session_data *sd, int n, int req_pos)
return 1;
}

/**
* Compares position of the to be unequipped item and overlapping equips
* if overlapping exists, checks if overlapping equip can now be displayed.
*
* @param sd the affected player structure. Must be checked before.
* @param pos_combination slot position. Must be checked before.
* @param look pointer of look that will be replaced.
* @param look_type type of look.
* @param pos position to check if contained in pos_combination
* @param pos_costume equivalent costume position to param pos.
*/
static void pc_unequipitem_pos_sub(struct map_session_data *sd, int pos_combination, int *look, int look_type, int pos, int pos_costume)
{
nullpo_retv(sd);
nullpo_retv(look);

pos_costume &= ~map->list[sd->bl.m].flag.noviewid;
if ((pos_combination & pos) != 0 && pc->checkequip(sd, pos_costume) == -1) {
*look = 0;
clif->changelook(&sd->bl, look_type, 0);
}
if ((pos_combination & pos_costume) != 0 || pos_costume == 0) {
*look = 0;
clif->changelook(&sd->bl, look_type, 0);

int equipped_item = pc->checkequip(sd, pos); // Item that was overlapped by unequipped costume
if (equipped_item >= 0) { // There might still be costumes overlapping
struct item_data *id = sd->inventory_data[equipped_item];
if (id != NULL)
pc->equipitem_pos(sd, id, equipped_item, id->equip);
}
}
}

/**
* Unequip an item at the given position.
* @param sd the affected player structure. Must be checked before.
Expand All @@ -10346,36 +10445,9 @@ static void pc_unequipitem_pos(struct map_session_data *sd, int n, int pos)
pc->calcweapontype(sd);
clif->changelook(&sd->bl, LOOK_SHIELD, sd->status.look.shield);
}
if (pos & EQP_HEAD_LOW && pc->checkequip(sd,EQP_COSTUME_HEAD_LOW) == -1) {
sd->status.look.head_bottom = 0;
clif->changelook(&sd->bl, LOOK_HEAD_BOTTOM, sd->status.look.head_bottom);
}
if (pos & EQP_HEAD_TOP && pc->checkequip(sd,EQP_COSTUME_HEAD_TOP) == -1) {
sd->status.look.head_top = 0;
clif->changelook(&sd->bl, LOOK_HEAD_TOP, sd->status.look.head_top);
}
if (pos & EQP_HEAD_MID && pc->checkequip(sd,EQP_COSTUME_HEAD_MID) == -1) {
sd->status.look.head_mid = 0;
clif->changelook(&sd->bl, LOOK_HEAD_MID, sd->status.look.head_mid);
}

if (pos & EQP_COSTUME_HEAD_TOP) {
int equip = pc->checkequip(sd, EQP_HEAD_TOP);
sd->status.look.head_top = (equip >= 0 && sd->inventory_data[equip] != NULL) ? sd->inventory_data[equip]->view_sprite : 0;
clif->changelook(&sd->bl, LOOK_HEAD_TOP, sd->status.look.head_top);
}

if (pos & EQP_COSTUME_HEAD_MID) {
int equip = pc->checkequip(sd, EQP_HEAD_MID);
sd->status.look.head_mid = (equip >= 0 && sd->inventory_data[equip] != NULL) ? sd->inventory_data[equip]->view_sprite : 0;
clif->changelook(&sd->bl, LOOK_HEAD_MID, sd->status.look.head_mid);
}

if (pos & EQP_COSTUME_HEAD_LOW) {
int equip = pc->checkequip(sd, EQP_HEAD_LOW);
sd->status.look.head_bottom = (equip >= 0 && sd->inventory_data[equip] != NULL) ? sd->inventory_data[equip]->view_sprite : 0;
clif->changelook(&sd->bl, LOOK_HEAD_BOTTOM, sd->status.look.head_bottom);
}
pc->unequipitem_pos_sub(sd, pos, &sd->status.look.head_top, LOOK_HEAD_TOP, EQP_HEAD_TOP, EQP_COSTUME_HEAD_TOP);
pc->unequipitem_pos_sub(sd, pos, &sd->status.look.head_mid, LOOK_HEAD_MID, EQP_HEAD_MID, EQP_COSTUME_HEAD_MID);
pc->unequipitem_pos_sub(sd, pos, &sd->status.look.head_bottom, LOOK_HEAD_BOTTOM, EQP_HEAD_LOW, EQP_COSTUME_HEAD_LOW);

if (pos & EQP_SHOES)
clif->changelook(&sd->bl,LOOK_SHOES,0);
Expand Down Expand Up @@ -10685,6 +10757,21 @@ static int pc_checkitem(struct map_session_data *sd)

}

if (sd->bl.m >= 0) {
for (i = 0; i < EQI_MAX; i++) {
if ((pc->equip_pos[i] & EQP_VISIBLE) == 0)
continue;
int index = sd->equip_index[i];
if (index == -1)
continue;
if (map_no_view(sd->bl.m, pc->equip_pos[i]))
pc->unequipitem_pos(sd, index, sd->status.inventory[index].equip);
else
pc->equipitem_pos(sd, sd->inventory_data[index], index, sd->status.inventory[index].equip);
}
}


if (calc_flag != 0 && sd->state.active == 1) {
pc->checkallowskill(sd);
status_calc_pc(sd, SCO_NONE);
Expand Down Expand Up @@ -12926,10 +13013,12 @@ void pc_defaults(void)
pc->resetskill_job = pc_resetskill_job;
pc->resetfeel = pc_resetfeel;
pc->resethate = pc_resethate;
pc->equip_costume_overlap = pc_equip_costume_overlap;
pc->equipitem = pc_equipitem;
pc->equipitem_pos = pc_equipitem_pos;
pc->unequipitem = pc_unequipitem;
pc->unequipitem_pos = pc_unequipitem_pos;
pc->unequipitem_pos_sub = pc_unequipitem_pos_sub;
pc->checkitem = pc_checkitem;
pc->useitem = pc_useitem;
pc->autocast_clear_current = pc_autocast_clear_current;
Expand Down
2 changes: 2 additions & 0 deletions src/map/pc.h
Original file line number Diff line number Diff line change
Expand Up @@ -1085,10 +1085,12 @@ END_ZEROED_BLOCK; /* End */
bool (*resetskill_job) (struct map_session_data *sd, int index);
int (*resetfeel) (struct map_session_data *sd);
int (*resethate) (struct map_session_data *sd);
uint32 (*equip_costume_overlap) (uint32 pos);
int (*equipitem) (struct map_session_data *sd,int n,int req_pos);
void (*equipitem_pos) (struct map_session_data *sd, struct item_data *id, int n, int pos);
int (*unequipitem) (struct map_session_data *sd,int n,int flag);
void (*unequipitem_pos) (struct map_session_data *sd, int n, int pos);
void (*unequipitem_pos_sub) (struct map_session_data *sd, int pos_combination, int *look, int look_type, int pos, int pos_costume);
int (*checkitem) (struct map_session_data *sd);
int (*useitem) (struct map_session_data *sd,int n);
void (*autocast_clear_current) (struct map_session_data *sd);
Expand Down
Loading
Loading