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.c109
1 files changed, 63 insertions, 46 deletions
diff --git a/src/map/clif.c b/src/map/clif.c
index 7be5c6978..409889f90 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);
@@ -6766,7 +6777,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;
@@ -10389,7 +10400,8 @@ static const char *clif_process_chat_message(struct map_session_data *sd, const
* @param[in] sd The source character.
* @param[in] packet The packet data.
* @param[out] out_name The parsed target name buffer (must be a valid
- * buffer of size NAME_LENGTH).
+ * buffer of size NAME_LENGTH + 1 because the client
+ * can send 24 characters without NULL terminator).
* @param[out] out_message The output message buffer (must be a valid buffer).
* @param[in] out_messagelen The size of out_message.
* @retval true if the validation succeeded and the message is a chat message.
@@ -10399,7 +10411,7 @@ static const char *clif_process_chat_message(struct map_session_data *sd, const
*/
static bool clif_process_whisper_message(struct map_session_data *sd, const struct packet_whisper_message *packet, char *out_name, char *out_message, int out_messagelen)
{
- int namelen = 0, messagelen = 0;
+ int messagelen = 0;
nullpo_retr(false, sd);
nullpo_retr(false, packet);
@@ -10412,15 +10424,6 @@ static bool clif_process_whisper_message(struct map_session_data *sd, const stru
return false;
}
- // validate name
- namelen = (int)strnlen(packet->name, NAME_LENGTH-1); // name length (w/o zero byte)
-
- if (packet->name[namelen] != '\0') {
- // only restriction is that the name must be zero-terminated
- ShowWarning("clif_process_whisper_message: Player '%s' sent an unterminated name!\n", sd->status.name);
- return false;
- }
-
#if PACKETVER >= 20151001
// Packet doesn't include a NUL terminator
messagelen = packet->packet_len - NAME_LENGTH - 4;
@@ -10439,7 +10442,7 @@ static bool clif_process_whisper_message(struct map_session_data *sd, const stru
return false;
}
- safestrncpy(out_name, packet->name, namelen+1); // [!] packet->name is not NUL terminated
+ safestrncpy(out_name, packet->name, NAME_LENGTH + 1); // [!] packet->name is not NUL terminated
safestrncpy(out_message, packet->message, messagelen+1); // [!] packet->message is not necessarily NUL terminated
if (!pc->process_chat_message(sd, out_message))
@@ -11778,7 +11781,8 @@ static void clif_parse_WisMessage(int fd, struct map_session_data *sd)
struct map_session_data* dstsd;
int i;
- char target[NAME_LENGTH], message[CHAT_SIZE_MAX + 1];
+ char target[NAME_LENGTH + 1]; // Client can send 24 characters without NULL terminator.
+ char message[CHAT_SIZE_MAX + 1];
const struct packet_whisper_message *packet = RP2PTR(fd);
if (!clif->process_whisper_message(sd, packet, target, message, sizeof message))
@@ -11794,7 +11798,7 @@ static void clif_parse_WisMessage(int fd, struct map_session_data *sd)
char *str = target + 4; // Skip the NPC: string part.
struct npc_data *nd;
if ((nd = npc->name2id(str))) {
- char split_data[NUM_WHISPER_VAR][CHAT_SIZE_MAX];
+ char split_data[NUM_WHISPER_VAR][SCRIPT_STRING_VAR_LENGTH + 1];
char *split;
char output[256];
@@ -12038,7 +12042,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
@@ -12083,7 +12087,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
@@ -12804,13 +12808,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]
@@ -12832,7 +12838,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
@@ -12841,7 +12851,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
@@ -12862,10 +12872,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;
}
@@ -12883,9 +12893,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);
@@ -12953,6 +12963,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,
@@ -12961,7 +12973,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.
@@ -12976,7 +12988,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
@@ -12999,11 +13012,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;
}
@@ -13024,9 +13037,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;
@@ -13046,7 +13059,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;
@@ -13067,7 +13080,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;
@@ -13096,10 +13109,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.
@@ -15475,6 +15491,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;
@@ -19928,9 +19945,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++;
}
@@ -22300,7 +22317,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
@@ -24193,7 +24210,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