summaryrefslogtreecommitdiff
path: root/src/map/clif.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/map/clif.c')
-rw-r--r--src/map/clif.c93
1 files changed, 57 insertions, 36 deletions
diff --git a/src/map/clif.c b/src/map/clif.c
index bc56d13c6..8688ee771 100644
--- a/src/map/clif.c
+++ b/src/map/clif.c
@@ -936,19 +936,25 @@ static void clif_clearunit_area(struct block_list *bl, enum clr_type type)
static int clif_clearunit_delayed_sub(int tid, int64 tick, int id, intptr_t data)
{
struct block_list *bl = (struct block_list *)data;
+ nullpo_ret(bl);
+ Assert_ret(bl->m >= 0 && bl->m < map->count);
+ if (map->list[bl->m].block == NULL) {
+ // avoid error report for missing/removed map
+ ers_free(clif->delay_clearunit_ers, bl);
+ return 0;
+ }
clif->clearunit_area(bl, (enum clr_type) id);
- ers_free(clif->delay_clearunit_ers,bl);
+ ers_free(clif->delay_clearunit_ers, bl);
return 0;
}
static void clif_clearunit_delayed(struct block_list *bl, enum clr_type type, int64 tick)
{
- struct block_list *tbl;
-
nullpo_retv(bl);
- tbl = ers_alloc(clif->delay_clearunit_ers, struct block_list);
- memcpy (tbl, bl, sizeof (struct block_list));
- timer->add(tick, clif->clearunit_delayed_sub, (int)type, (intptr_t)tbl);
+ Assert_retv(bl->type == BL_MOB);
+ struct mob_data *md = ers_alloc(clif->delay_clearunit_ers, struct mob_data);
+ memcpy (md, bl, sizeof (struct mob_data));
+ timer->add(tick, clif->clearunit_delayed_sub, (int)type, (intptr_t)md);
}
/// Gets weapon view info from sd's inventory_data and points (*rhand,*lhand)
@@ -1031,6 +1037,7 @@ static void clif_set_unit_idle2(struct block_list *bl, struct map_session_data *
int g_id = status->get_guild_id(bl);
nullpo_retv(bl);
+ nullpo_retv(vd);
sd = BL_CAST(BL_PC, bl);
p.PacketType = idle_unit2Type;
@@ -1087,6 +1094,7 @@ static void clif_set_unit_idle(struct block_list *bl, struct map_session_data *t
int g_id = status->get_guild_id(bl);
nullpo_retv(bl);
+ nullpo_retv(vd);
#if PACKETVER < 20091103
if (!pc->db_checkid(vd->class)) {
@@ -1197,6 +1205,7 @@ static void clif_spawn_unit2(struct block_list *bl, enum send_target target)
int g_id = status->get_guild_id(bl);
nullpo_retv(bl);
+ nullpo_retv(vd);
sd = BL_CAST(BL_PC, bl);
p.PacketType = spawn_unit2Type;
@@ -1244,6 +1253,7 @@ static void clif_spawn_unit(struct block_list *bl, enum send_target target)
int g_id = status->get_guild_id(bl);
nullpo_retv(bl);
+ nullpo_retv(vd);
#if PACKETVER < 20091103
if (!pc->db_checkid(vd->class)) {
@@ -1357,6 +1367,7 @@ static void clif_set_unit_walking(struct block_list *bl, struct map_session_data
nullpo_retv(bl);
nullpo_retv(ud);
+ nullpo_retv(vd);
sd = BL_CAST(BL_PC, bl);
@@ -6768,7 +6779,7 @@ static void clif_item_skill(struct map_session_data *sd, uint16 skill_id, uint16
struct PACKET_ZC_AUTORUN_SKILL *p = WFIFOP(fd, 0);
int type = skill->get_inf(skill_id);
- if (sd->autocast.itemskill_cast_on_self && sd->autocast.type == AUTOCAST_ITEM)
+ if (sd->auto_cast_current.itemskill_cast_on_self && sd->auto_cast_current.type == AUTOCAST_ITEM)
type = INF_SELF_SKILL;
p->packetType = HEADER_ZC_AUTORUN_SKILL;
@@ -12033,7 +12044,7 @@ static void clif_parse_EquipItem(int fd, struct map_session_data *sd)
return; //Out of bounds check.
if( sd->npc_id ) {
- if ( !sd->npc_item_flag )
+ if ((sd->npc_item_flag & ITEMENABLEDNPC_EQUIP) == 0)
return;
} else if (sd->state.storage_flag != STORAGE_FLAG_CLOSED || sd->sc.opt1)
; //You can equip/unequip stuff while storage is open/under status changes
@@ -12078,7 +12089,7 @@ static void clif_parse_UnequipItem(int fd, struct map_session_data *sd)
}
if( sd->npc_id ) {
- if ( !sd->npc_item_flag )
+ if ((sd->npc_item_flag & ITEMENABLEDNPC_EQUIP) == 0)
return;
} else if (sd->state.storage_flag != STORAGE_FLAG_CLOSED || sd->sc.opt1)
; //You can equip/unequip stuff while storage is open/under status changes
@@ -12799,13 +12810,15 @@ static void clif_useSkillToIdReal(int fd, struct map_session_data *sd, int skill
{
int64 tick = timer->gettick();
+ pc->autocast_set_current(sd, skill_id);
+
/**
* According to Skotlex' comment below, the client sometimes passes 0 for the skill level.
* Even though this seems to only affect guild skills, sd->autocast.skill_lv is used
* for the auto-cast data validation if skill_lv is 0.
*
**/
- skill->validate_autocast_data(sd, skill_id, (skill_lv == 0) ? sd->autocast.skill_lv : skill_lv);
+ skill->validate_autocast_data(sd, skill_id, (skill_lv == 0) ? sd->auto_cast_current.skill_lv : skill_lv);
if (skill_lv < 1)
skill_lv = 1; //No clue, I have seen the client do this with guild skills :/ [Skotlex]
@@ -12827,7 +12840,11 @@ static void clif_useSkillToIdReal(int fd, struct map_session_data *sd, int skill
// Whether skill fails or not is irrelevant, the char ain't idle. [Skotlex]
pc->update_idle_time(sd, BCIDLE_USESKILLTOID);
- if (sd->npc_id || sd->state.workinprogress & 1) {
+ bool allow_self_skill = ((tmp & INF_SELF_SKILL) != 0 && (skill->get_nk(skill_id) & NK_NO_DAMAGE) != 0);
+ allow_self_skill = (allow_self_skill && battle_config.skill_enabled_npc == SKILLENABLEDNPC_SELF);
+
+ if ((sd->npc_id != 0 && !allow_self_skill && battle_config.skill_enabled_npc != SKILLENABLEDNPC_ALL)
+ || (sd->state.workinprogress & 1) != 0) {
#if PACKETVER >= 20110308
clif->msgtable(sd, MSG_BUSY);
#else
@@ -12836,7 +12853,7 @@ static void clif_useSkillToIdReal(int fd, struct map_session_data *sd, int skill
return;
}
- if (pc_cant_act(sd)
+ if (pc_cant_act_except_npc(sd)
&& skill_id != RK_REFRESH
&& !(skill_id == SR_GENTLETOUCH_CURE && (sd->sc.opt1 == OPT1_STONE || sd->sc.opt1 == OPT1_FREEZE || sd->sc.opt1 == OPT1_STUN))
&& (sd->state.storage_flag != STORAGE_FLAG_CLOSED && !(tmp&INF_SELF_SKILL)) // SELF skills can be used with the storage open, issue: 8027
@@ -12857,10 +12874,10 @@ static void clif_useSkillToIdReal(int fd, struct map_session_data *sd, int skill
target_id = sd->bl.id;
if (sd->ud.skilltimer != INVALID_TIMER) {
- if (skill_id != SA_CASTCANCEL && skill_id != SO_SPELLFIST)
+ if (skill_id != SA_CASTCANCEL && skill_id != SO_SPELLFIST && sd->auto_cast_current.type == AUTOCAST_NONE)
return;
} else if (DIFF_TICK(tick, sd->ud.canact_tick) < 0) {
- if (sd->autocast.type == AUTOCAST_NONE) {
+ if (sd->auto_cast_current.type == AUTOCAST_NONE) {
clif->skill_fail(sd, skill_id, USESKILL_FAIL_SKILLINTERVAL, 0, 0);
return;
}
@@ -12878,9 +12895,9 @@ static void clif_useSkillToIdReal(int fd, struct map_session_data *sd, int skill
} else if (sd->menuskill_id != SA_AUTOSPELL)
return; //Can't use skills while a menu is open.
}
- if (sd->autocast.type != AUTOCAST_NONE) {
- if (skill_lv != sd->autocast.skill_lv)
- skill_lv = sd->autocast.skill_lv;
+ if (sd->auto_cast_current.type != AUTOCAST_NONE) {
+ if (skill_lv != sd->auto_cast_current.skill_lv)
+ skill_lv = sd->auto_cast_current.skill_lv;
if (!(tmp&INF_SELF_SKILL))
pc->delinvincibletimer(sd); // Target skills through items cancel invincibility. [Inkfish]
unit->skilluse_id(&sd->bl, target_id, skill_id, skill_lv);
@@ -12948,6 +12965,8 @@ static void clif_parse_UseSkillToPosSub(int fd, struct map_session_data *sd, uin
int64 tick = timer->gettick();
nullpo_retv(sd);
+
+ pc->autocast_set_current(sd, skill_id);
/**
* When using clif_item_skill() to initiate the execution of ground skills,
@@ -12956,7 +12975,7 @@ static void clif_parse_UseSkillToPosSub(int fd, struct map_session_data *sd, uin
* since clif_item_skill() is only used for auto-cast skills.
*
**/
- skill->validate_autocast_data(sd, skill_id, (skill_lv == 0) ? sd->autocast.skill_lv : skill_lv);
+ skill->validate_autocast_data(sd, skill_id, (skill_lv == 0) ? sd->auto_cast_current.skill_lv : skill_lv);
if( !(skill->get_inf(skill_id)&INF_GROUND_SKILL) )
return; //Using a target skill on the ground? WRONG.
@@ -12971,7 +12990,8 @@ static void clif_parse_UseSkillToPosSub(int fd, struct map_session_data *sd, uin
return;
}
- if (sd->state.workinprogress & 1) {
+ if ((sd->npc_id != 0 && battle_config.skill_enabled_npc != SKILLENABLEDNPC_ALL)
+ || (sd->state.workinprogress & 1) != 0) {
#if PACKETVER >= 20110308
clif->msgtable(sd, MSG_BUSY);
#else
@@ -12994,11 +13014,11 @@ static void clif_parse_UseSkillToPosSub(int fd, struct map_session_data *sd, uin
safestrncpy(sd->message, RFIFOP(fd, skillmoreinfo), TALKBOX_MESSAGE_SIZE);
}
- if( sd->ud.skilltimer != INVALID_TIMER )
+ if (sd->ud.skilltimer != INVALID_TIMER && sd->auto_cast_current.type == AUTOCAST_NONE)
return;
if( DIFF_TICK(tick, sd->ud.canact_tick) < 0 ) {
- if (sd->autocast.type == AUTOCAST_NONE) {
+ if (sd->auto_cast_current.type == AUTOCAST_NONE) {
clif->skill_fail(sd, skill_id, USESKILL_FAIL_SKILLINTERVAL, 0, 0);
return;
}
@@ -13019,9 +13039,9 @@ static void clif_parse_UseSkillToPosSub(int fd, struct map_session_data *sd, uin
pc->delinvincibletimer(sd);
- if (sd->autocast.type != AUTOCAST_NONE) {
- if (skill_lv != sd->autocast.skill_lv)
- skill_lv = sd->autocast.skill_lv;
+ if (sd->auto_cast_current.type != AUTOCAST_NONE) {
+ if (skill_lv != sd->auto_cast_current.skill_lv)
+ skill_lv = sd->auto_cast_current.skill_lv;
unit->skilluse_pos(&sd->bl, x, y, skill_id, skill_lv);
} else {
int lv;
@@ -13041,7 +13061,7 @@ static void clif_parse_UseSkillToPos(int fd, struct map_session_data *sd) __attr
/// There are various variants of this packet, some of them have padding between fields.
static void clif_parse_UseSkillToPos(int fd, struct map_session_data *sd)
{
- if (pc_cant_act(sd))
+ if (pc_cant_act_except_npc(sd))
return;
if (pc_issit(sd))
return;
@@ -13062,7 +13082,7 @@ static void clif_parse_UseSkillToPosMoreInfo(int fd, struct map_session_data *sd
/// There are various variants of this packet, some of them have padding between fields.
static void clif_parse_UseSkillToPosMoreInfo(int fd, struct map_session_data *sd)
{
- if (pc_cant_act(sd))
+ if (pc_cant_act_except_npc(sd))
return;
if (pc_issit(sd))
return;
@@ -13091,10 +13111,13 @@ static void clif_parse_UseSkillMap(int fd, struct map_session_data *sd)
return;
// It is possible to use teleport with the storage window open issue:8027
- if (pc_cant_act(sd) && (sd->state.storage_flag == STORAGE_FLAG_CLOSED && skill_id != AL_TELEPORT)) {
+ if ((pc_cant_act_except_npc(sd) && sd->state.storage_flag == STORAGE_FLAG_CLOSED && skill_id != AL_TELEPORT)
+ || (sd->npc_id != 0 && battle_config.skill_enabled_npc != SKILLENABLEDNPC_ALL)) {
clif_menuskill_clear(sd);
return;
}
+
+ pc->autocast_set_current(sd, skill_id);
/**
* Since no skill level was passed use 0 to notify skill_validate_autocast_data() of this special case.
@@ -15470,6 +15493,7 @@ static void clif_parse_GMKick(int fd, struct map_session_data *sd)
}
npc->unload_duplicates(nd, true);
npc->unload(nd, true, true);
+ npc->motd = npc->name2id("HerculesMOTD");
npc->read_event_script();
}
break;
@@ -19923,9 +19947,9 @@ static int clif_autoshadowspell_list(struct map_session_data *sd)
WFIFOHEAD(fd, 2 * 6 + 4);
WFIFOW(fd,0) = 0x442;
for (i = 0, c = 0; i < MAX_SKILL_DB; i++)
- if( sd->status.skill[i].flag == SKILL_FLAG_PLAGIARIZED && sd->status.skill[i].id > 0 &&
- sd->status.skill[i].id < GS_GLITTERING && skill->get_type(sd->status.skill[i].id) == BF_MAGIC )
- { // Can't auto cast both Extended class and 3rd class skills.
+ if (sd->status.skill[i].flag == SKILL_FLAG_PLAGIARIZED && sd->status.skill[i].id > 0 && sd->status.skill[i].id < GS_GLITTERING
+ && skill->get_type(sd->status.skill[i].id, sd->status.skill[i].lv) == BF_MAGIC) {
+ // Can't auto cast both Extended class and 3rd class skills.
WFIFOW(fd,8+c*2) = sd->status.skill[i].id;
c++;
}
@@ -20431,17 +20455,14 @@ static void clif_maptypeproperty2(struct block_list *bl, enum send_target t)
{
#if PACKETVER >= 20121010
struct packet_maptypeproperty2 p;
- struct map_session_data *sd = NULL;
nullpo_retv(bl);
- sd = BL_CAST(BL_PC, bl);
-
p.PacketType = maptypeproperty2Type;
p.type = 0x28;
p.flag.party = map->list[bl->m].flag.pvp ? 1 : 0; //PARTY
p.flag.guild = (map->list[bl->m].flag.battleground || map_flag_gvg(bl->m)) ? 1 : 0; // GUILD
p.flag.siege = (map->list[bl->m].flag.battleground || map_flag_gvg2(bl->m)) ? 1: 0; // SIEGE
- p.flag.mineffect = map_flag_gvg(bl->m) ? 1 : ( (sd && sd->state.lesseffect) ? 1 : 0); // USE_SIMPLE_EFFECT - Forcing /mineffect in castles during WoE (probably redundant? I'm not sure)
+ p.flag.mineffect = map_flag_gvg2(bl->m) ? 1 : 0; // USE_SIMPLE_EFFECT - Automatically enable /mineffect in guild arenas and castles.
p.flag.nolockon = 0; // DISABLE_LOCKON - TODO
p.flag.countpk = map->list[bl->m].flag.pvp ? 1 : 0; // COUNT_PK
p.flag.nopartyformation = map->list[bl->m].flag.partylock ? 1 : 0; // NO_PARTY_FORMATION
@@ -22295,7 +22316,7 @@ static void clif_rodex_checkname_result(struct map_session_data *sd, int char_id
sPacket->Class = class_;
sPacket->BaseLevel = base_level;
#if PACKETVER >= 20160316
- strncpy(sPacket->Name, name, NAME_LENGTH);
+ safestrncpy(sPacket->Name, name, NAME_LENGTH);
#endif
WFIFOSET(fd, sizeof(*sPacket));
#endif
@@ -24188,7 +24209,7 @@ static int do_init_clif(bool minimal)
timer->add_func_list(clif->clearunit_delayed_sub, "clif_clearunit_delayed_sub");
timer->add_func_list(clif->delayquit, "clif_delayquit");
- clif->delay_clearunit_ers = ers_new(sizeof(struct block_list),"clif.c::delay_clearunit_ers",ERS_OPT_CLEAR);
+ clif->delay_clearunit_ers = ers_new(sizeof(struct mob_data), "clif.c::delay_clearunit_ers", ERS_OPT_CLEAR);
clif->delayed_damage_ers = ers_new(sizeof(struct cdelayed_damage),"clif.c::delayed_damage_ers",ERS_OPT_CLEAR);
#if PACKETVER_MAIN_NUM >= 20190403 || PACKETVER_RE_NUM >= 20190320