summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Changelog-Trunk.txt9
-rw-r--r--src/map/atcommand.c6
-rw-r--r--src/map/clif.c175
-rw-r--r--src/map/log.c84
-rw-r--r--src/map/log.h2
-rw-r--r--src/map/map.h13
-rw-r--r--src/map/script.c40
-rw-r--r--src/map/skill.c7
8 files changed, 164 insertions, 172 deletions
diff --git a/Changelog-Trunk.txt b/Changelog-Trunk.txt
index 2ecc91c19..8c61484e8 100644
--- a/Changelog-Trunk.txt
+++ b/Changelog-Trunk.txt
@@ -3,6 +3,13 @@ Date Added
AS OF SVN REV. 5091, WE ARE NOW USING TRUNK. ALL UNTESTED BUGFIXES/FEATURES GO INTO TRUNK.
IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK.
+2007/10/09
+ * Corrected string lengths according to bugreport:198 [ultramage]
+ - CHATBOX_SIZE: 70 -> 70+1
+ - removed some too aggressive checks in clif_parse_globalmessage()
+ - removed CHAT_SIZE define as it actually doesn't apply anywhere
+ - added CHAT_SIZE_MAX to serve as a custom limit to input string lengths
+ - added length/contents checks to /b and /lb (against fake names)
2007/10/08
* Delayed the check for required items when a skill is cast to when they
are consumed. Now skills only fail due to lack of items after being cast.
@@ -20,7 +27,7 @@ IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK.
* Removed that ridiculous spinner that displays during map/npc loading
- and added a more informative progress indicator (idea from jA/eapp)
* Removed loads of code that supported these functions
- - -100b per npc => -1,5MB of wasted memory
+ - -230b per npc => -3MB of wasted memory
* Fixed related npcs that erroneously used 'stoptimer'
* Checked/fixed/removed some old script and npc commands
+ cmdothernpc
diff --git a/src/map/atcommand.c b/src/map/atcommand.c
index bfb20570a..1d05e915f 100644
--- a/src/map/atcommand.c
+++ b/src/map/atcommand.c
@@ -906,7 +906,7 @@ int atcommand_config_read(const char *cfgName)
*------------------------------------------*/
int atcommand_commands(const int fd, struct map_session_data* sd, const char* command, const char* message)
{
- char cz_line_buff[CHATBOX_SIZE+1];
+ char cz_line_buff[CHATBOX_SIZE];
register char *lpcz_cur = cz_line_buff;
register unsigned int ui_slen;
@@ -914,7 +914,7 @@ int atcommand_commands(const int fd, struct map_session_data* sd, const char* co
int i_cur_cmd,gm_lvl = pc_isGM(sd), count = 0;
memset(cz_line_buff,' ',CHATBOX_SIZE);
- cz_line_buff[CHATBOX_SIZE] = 0;
+ cz_line_buff[CHATBOX_SIZE-1] = 0;
clif_displaymessage(fd, msg_txt(273));
@@ -932,7 +932,7 @@ int atcommand_commands(const int fd, struct map_session_data* sd, const char* co
clif_displaymessage(fd,(char*)cz_line_buff);
lpcz_cur = cz_line_buff;
memset(cz_line_buff,' ',CHATBOX_SIZE);
- cz_line_buff[CHATBOX_SIZE] = 0;
+ cz_line_buff[CHATBOX_SIZE-1] = 0;
}
memcpy(lpcz_cur,atcommand_info[i_cur_cmd].command,ui_slen);
diff --git a/src/map/clif.c b/src/map/clif.c
index 3e7919159..379f2829b 100644
--- a/src/map/clif.c
+++ b/src/map/clif.c
@@ -6923,12 +6923,11 @@ void clif_emotion(struct block_list *bl,int type)
void clif_talkiebox(struct block_list* bl, const char* talkie)
{
unsigned char buf[86];
-
nullpo_retv(bl);
- WBUFW(buf,0)=0x191;
- WBUFL(buf,2)=bl->id;
- memcpy(WBUFP(buf,6),talkie,MESSAGE_SIZE);
+ WBUFW(buf,0) = 0x191;
+ WBUFL(buf,2) = bl->id;
+ safestrncpy((char*)WBUFP(buf,6),talkie,MESSAGE_SIZE);
clif_send(buf,packet_len(0x191),bl,AREA);
}
@@ -8212,7 +8211,7 @@ void clif_parse_GetCharNameRequest(int fd, struct map_session_data *sd)
/*==========================================
* Validates and processes global messages
- * S 008c/00f3 <packet len>.w <text>.?B (<name> : <message>)
+ * S 008c/00f3 <packet len>.w <text>.?B (<name> : <message>) 00
*------------------------------------------*/
void clif_parse_GlobalMessage(int fd, struct map_session_data* sd)
{
@@ -8223,12 +8222,12 @@ void clif_parse_GlobalMessage(int fd, struct map_session_data* sd)
// basic structure checks
if( packetlen > RFIFOREST(fd) )
{ // there has to be enough data to read
- ShowWarning("clif_parse_GlobalMessage: Received malformed packet from player '%s' (length is incorrect)!", sd->status.name);
+ ShowWarning("clif_parse_GlobalMessage: Received malformed packet from player '%s' (length is incorrect)!\n", sd->status.name);
return;
}
if( packetlen < 4 + 1 )
{ // 4-byte header and at least an empty string is expected
- ShowWarning("clif_parse_GlobalMessage: Received malformed packet from player '%s' (no message data)!", sd->status.name);
+ ShowWarning("clif_parse_GlobalMessage: Received malformed packet from player '%s' (no message data)!\n", sd->status.name);
return;
}
@@ -8242,41 +8241,31 @@ void clif_parse_GlobalMessage(int fd, struct map_session_data* sd)
name[namelen] != ' ' || name[namelen+1] != ':' || name[namelen+2] != ' ' ) // followed by ' : '
{
//Hacked message, or infamous "client desynch" issue where they pick one char while loading another.
- ShowWarning("clif_parse_GlobalMessage: Player '%s' sent a message using an incorrect name! Forcing a relog...", sd->status.name);
+ ShowWarning("clif_parse_GlobalMessage: Player '%s' sent a message using an incorrect name! Forcing a relog...\n", sd->status.name);
clif_setwaitclose(fd); // Just kick them out to correct it.
return;
}
message = text + namelen + 3;
- messagelen = textlen - namelen - 3 - 1; // this should be the message length
+ messagelen = textlen - namelen - 3; // this should be the message length (w/ zero byte included)
// verify <message> part of the packet
- if( message[messagelen] != '\0' )
+ if( message[messagelen-1] != '\0' )
{ // message must be zero-terminated
- ShowWarning("clif_parse_GlobalMessage: Player '%s' sent an unterminated string!", sd->status.name);
+ ShowWarning("clif_parse_GlobalMessage: Player '%s' sent an unterminated string!\n", sd->status.name);
return;
}
- if( messagelen != strnlen(message, messagelen+1) )
+ if( messagelen != strnlen(message, messagelen)+1 )
{ // the declared length must match real length
- ShowWarning("clif_parse_GlobalMessage: Received malformed packet from player '%s' (length is incorrect)!", sd->status.name);
+ ShowWarning("clif_parse_GlobalMessage: Received malformed packet from player '%s' (length is incorrect)!\n", sd->status.name);
return;
}
- if( messagelen > CHATBOX_SIZE )
+ if( messagelen > CHAT_SIZE_MAX )
{ // messages mustn't be too long
- int i;
- // special case here - allow some more freedom for frost joke & dazzler
- // TODO:? You could use a state flag when FrostJoke/Scream is used, and unset it once the skill triggers. [Skotlex]
- ARR_FIND( 0, MAX_SKILLTIMERSKILL, i, sd->ud.skilltimerskill[i] == 0 || sd->ud.skilltimerskill[i]->skill_id == BA_FROSTJOKE || sd->ud.skilltimerskill[i]->skill_id == DC_SCREAM );
-
- if( i == MAX_SKILLTIMERSKILL || !sd->ud.skilltimerskill[i])
- { // normal message, too long
- ShowWarning("clif_parse_GlobalMessage: Player '%s' sent a message too long ('%.*s')!", sd->status.name, CHATBOX_SIZE, message);
- return;
- }
- if( messagelen > 255 )
- { // frost joke/dazzler, but still too long
- ShowWarning("clif_parse_GlobalMessage: Player '%s' sent a message too long ('%.*s')!", sd->status.name, 255, message);
- return;
- }
+ // Normally you can only enter CHATBOX_SIZE-1 chars into the chat box, but Frost Joke / Dazzler's text can be longer.
+ // Neither the official client nor server place any restriction on the length of the text in the packet,
+ // but we'll only allow reasonably long strings here. This also makes sure all strings fit into the `chatlog` table.
+ ShowWarning("clif_parse_GlobalMessage: Player '%s' sent a message too long ('%.*s')!\n", sd->status.name, CHAT_SIZE_MAX, message);
+ return;
}
if( is_atcommand(fd, sd, text) != AtCommand_None || is_charcommand(fd, sd, text) != CharCommand_None )
@@ -8771,26 +8760,40 @@ void clif_parse_Wis(int fd, struct map_session_data* sd)
/*==========================================
* /b
+ * S 0099 <packet len>.w <text>.?B (<name>: <message>) 00
*------------------------------------------*/
-void clif_parse_GMmessage(int fd, struct map_session_data *sd)
+void clif_parse_GMmessage(int fd, struct map_session_data* sd)
{
- char* mes;
- int size, lv;
+ char *text, *name, *message;
+ unsigned int textlen, namelen, messagelen;
+ int lv;
if (battle_config.atc_gmonly && !pc_isGM(sd))
return;
if (pc_isGM(sd) < (lv=get_atcommand_level(AtCommand_Broadcast)))
return;
- size = RFIFOW(fd,2)-4;
- mes = (char*)RFIFOP(fd,4);
- mes_len_check(mes, size, CHAT_SIZE);
+ text = (char*)RFIFOP(fd,4);
+ textlen = RFIFOW(fd,2) - 4;
+
+ name = text;
+ namelen = strnlen(sd->status.name, NAME_LENGTH - 1);
+ // verify <name> part of the packet
+ if( strncmp(name, sd->status.name, namelen) || // the text must start with the speaker's name
+ name[namelen] != ':' || name[namelen+1] != ' ' ) // followed by ': '
+ return;
+
+ // make sure the <message> part of the packet is safe to handle
+ message = text + namelen + 2;
+ messagelen = textlen - namelen - 2; // this should be the message length (w/ zero byte included)
+ mes_len_check(message, messagelen, CHATBOX_SIZE);
+
+ intif_GMmessage(text, textlen, 0);
- intif_GMmessage(mes, size, 0);
if(log_config.gm && lv >= log_config.gm) {
- char message[CHAT_SIZE+4];
- sprintf(message, "/b %s", mes);
- log_atcommand(sd, message);
+ char msg[CHATBOX_SIZE+4];
+ sprintf(msg, "/b %s", message);
+ log_atcommand(sd, msg);
}
}
@@ -9468,8 +9471,7 @@ void clif_parse_UseSkillToPosSub(int fd, struct map_session_data *sd, int skilll
return;
}
//You can't use Graffiti/TalkieBox AND have a vending open, so this is safe.
- memcpy(sd->message, RFIFOP(fd,skillmoreinfo), MESSAGE_SIZE);
- sd->message[MESSAGE_SIZE-1] = '\0'; //Overflow protection [Skotlex]
+ safestrncpy(sd->message, (char*)RFIFOP(fd,skillmoreinfo), MESSAGE_SIZE);
}
if (sd->ud.skilltimer != -1)
@@ -9649,34 +9651,30 @@ void clif_parse_NpcNextClicked(int fd,struct map_session_data *sd)
}
/*==========================================
- *
+ * Value entered into a NPC input box.
+ * S 0143 <npcID>.l <amount>.l
*------------------------------------------*/
void clif_parse_NpcAmountInput(int fd,struct map_session_data *sd)
{
- sd->npc_amount=(int)RFIFOL(fd,6);
- npc_scriptcont(sd,RFIFOL(fd,2));
+ int npcid = RFIFOL(fd,2);
+ int amount = (int)RFIFOL(fd,6);
+
+ sd->npc_amount = amount;
+ npc_scriptcont(sd, npcid);
}
/*==========================================
- *
+ * Text entered into a NPC input box.
+ * S 01d5 <len>.w <npcID>.l <input>.?B 00
*------------------------------------------*/
-void clif_parse_NpcStringInput(int fd,struct map_session_data *sd)
+void clif_parse_NpcStringInput(int fd, struct map_session_data* sd)
{
- short message_len;
- message_len = RFIFOW(fd,2)-7;
-
- if(message_len < 1)
- return; //Blank message?
-
- if(message_len >= sizeof(sd->npc_str)){
- ShowWarning("clif: input string too long !\n");
- message_len = sizeof(sd->npc_str);
- }
+ int message_len = RFIFOW(fd,2)-8;
+ int npcid = RFIFOL(fd,4);
+ const char* message = (char*)RFIFOP(fd,8);
- // Exploit prevention if crafted packets (without null) is being sent. [Lance]
- memcpy(sd->npc_str,RFIFOP(fd,8),message_len);
- sd->npc_str[message_len-1]=0;
- npc_scriptcont(sd,RFIFOL(fd,4));
+ safestrncpy(sd->npc_str, message, min(message_len,CHATBOX_SIZE));
+ npc_scriptcont(sd, npcid);
}
/*==========================================
@@ -9775,31 +9773,46 @@ void clif_parse_ResetChar(int fd, struct map_session_data *sd)
}
/*==========================================
- * 019c /lb“™
+ * /lb
+ * S 019c <packet len>.w <text>.?B (<name>: <message>) 00
*------------------------------------------*/
-void clif_parse_LGMmessage(int fd, struct map_session_data *sd)
+void clif_parse_LGMmessage(int fd, struct map_session_data* sd)
{
- unsigned char buf[CHAT_SIZE+4];
- char *mes;
- int len, lv;
+ char *text, *name, *message;
+ unsigned int textlen, namelen, messagelen;
+
+ unsigned char buf[CHATBOX_SIZE+4];
+ int lv;
if (battle_config.atc_gmonly && !pc_isGM(sd))
return;
if (pc_isGM(sd) < (lv=get_atcommand_level(AtCommand_LocalBroadcast)))
return;
- len = RFIFOW(fd,2) - 4;
- mes = (char*)RFIFOP(fd,4);
- mes_len_check(mes, len, CHAT_SIZE);
+ text = (char*)RFIFOP(fd,4);
+ textlen = RFIFOW(fd,2) - 4;
+
+ name = text;
+ namelen = strnlen(sd->status.name, NAME_LENGTH - 1);
+ // verify <name> part of the packet
+ if( strncmp(name, sd->status.name, namelen) || // the text must start with the speaker's name
+ name[namelen] != ':' || name[namelen+1] != ' ' ) // followed by ': '
+ return;
+
+ // make sure the <message> part of the packet is safe to handle
+ message = text + namelen + 2;
+ messagelen = textlen - namelen - 2; // this should be the message length (w/ zero byte included)
+ mes_len_check(message, messagelen, CHATBOX_SIZE);
WBUFW(buf,0) = 0x9a;
- WBUFW(buf,2) = len+4;
- memcpy(WBUFP(buf,4), mes, len);
+ WBUFW(buf,2) = textlen+4;
+ memcpy(WBUFP(buf,4), text, textlen);
clif_send(buf, WBUFW(buf,2), &sd->bl, ALL_SAMEMAP);
+
if(log_config.gm && lv >= log_config.gm) {
- char message[CHAT_SIZE+5];
- sprintf(message, "/lb %s", mes);
- log_atcommand(sd, message);
+ char msg[CHATBOX_SIZE+5];
+ sprintf(msg, "/lb %s", message);
+ log_atcommand(sd, msg);
}
}
@@ -10040,12 +10053,10 @@ void clif_parse_PartyChangeOption(int fd, struct map_session_data *sd)
*------------------------------------------*/
void clif_parse_PartyMessage(int fd, struct map_session_data* sd)
{
- char* message;
- int len;
+ int len = RFIFOW(fd,2) - 4;
+ char* message = (char*)RFIFOP(fd,4);
- len = RFIFOW(fd,2) - 4;
- message = (char*)RFIFOP(fd,4);
- mes_len_check(message, len, CHAT_SIZE);
+ mes_len_check(message, len, CHATBOX_SIZE);
if (is_charcommand(fd, sd, message) != CharCommand_None || is_atcommand(fd, sd, message) != AtCommand_None)
return;
@@ -10309,12 +10320,10 @@ void clif_parse_GuildExpulsion(int fd,struct map_session_data *sd)
*------------------------------------------*/
void clif_parse_GuildMessage(int fd, struct map_session_data* sd)
{
- char* message;
- int len;
+ int len = RFIFOW(fd,2) - 4;
+ char* message = (char*)RFIFOP(fd,4);
- len = RFIFOW(fd,2) - 4;
- message = (char*)RFIFOP(fd,4);
- mes_len_check(message, len, CHAT_SIZE);
+ mes_len_check(message, len, CHATBOX_SIZE);
if (is_charcommand(fd, sd, message) != CharCommand_None || is_atcommand(fd, sd, message) != AtCommand_None)
return;
diff --git a/src/map/log.c b/src/map/log.c
index 97a802a0c..b50bcfb70 100644
--- a/src/map/log.c
+++ b/src/map/log.c
@@ -66,7 +66,7 @@ int log_branch(struct map_session_data *sd)
nullpo_retr(0, sd);
#ifndef TXT_ONLY
- if(log_config.sql_logs > 0)
+ if( log_config.sql_logs )
{
SqlStmt* stmt;
stmt = SqlStmt_Malloc(logmysql_handle);
@@ -104,18 +104,16 @@ int log_pick_pc(struct map_session_data *sd, const char *type, int nameid, int a
return 0; //we skip logging this item set - it doesn't meet our logging conditions [Lupus]
#ifndef TXT_ONLY
- if(log_config.sql_logs > 0)
+ if( log_config.sql_logs )
{
- if (itm == NULL) {
- //We log common item
+ if( itm == NULL ) { //We log common item
if (SQL_ERROR == Sql_Query(logmysql_handle, "INSERT DELAYED INTO `%s` (`time`, `char_id`, `type`, `nameid`, `amount`, `map`) VALUES (NOW(), '%d', '%s', '%d', '%d', '%s')",
log_config.log_pick_db, sd->status.char_id, type, nameid, amount, mapindex_id2name(sd->mapindex)) )
{
Sql_ShowDebug(logmysql_handle);
return 0;
}
- } else {
- //We log Extended item
+ } else { //We log Extended item
if (SQL_ERROR == Sql_Query(logmysql_handle, "INSERT DELAYED INTO `%s` (`time`, `char_id`, `type`, `nameid`, `amount`, `refine`, `card0`, `card1`, `card2`, `card3`, `map`) VALUES (NOW(), '%d', '%s', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%s')",
log_config.log_pick_db, sd->status.char_id, type, itm->nameid, amount, itm->refine, itm->card[0], itm->card[1], itm->card[2], itm->card[3], mapindex_id2name(sd->mapindex)) )
{
@@ -134,15 +132,10 @@ int log_pick_pc(struct map_session_data *sd, const char *type, int nameid, int a
time(&curtime);
strftime(timestring, 254, "%m/%d/%Y %H:%M:%S", localtime(&curtime));
- if (itm == NULL) {
- //We log common item
- fprintf(logfp,"%s - %d\t%s\t%d,%d,%s\n",
- timestring, sd->status.char_id, type, nameid, amount, mapindex_id2name(sd->mapindex));
-
- } else {
- //We log Extended item
- fprintf(logfp,"%s - %d\t%s\t%d,%d,%d,%d,%d,%d,%d,%s\n",
- timestring, sd->status.char_id, type, itm->nameid, amount, itm->refine, itm->card[0], itm->card[1], itm->card[2], itm->card[3], mapindex_id2name(sd->mapindex));
+ if( itm == NULL ) { //We log common item
+ fprintf(logfp,"%s - %d\t%s\t%d,%d,%s\n", timestring, sd->status.char_id, type, nameid, amount, mapindex_id2name(sd->mapindex));
+ } else { //We log Extended item
+ fprintf(logfp,"%s - %d\t%s\t%d,%d,%d,%d,%d,%d,%d,%s\n", timestring, sd->status.char_id, type, itm->nameid, amount, itm->refine, itm->card[0], itm->card[1], itm->card[2], itm->card[3], mapindex_id2name(sd->mapindex));
}
fclose(logfp);
}
@@ -166,18 +159,16 @@ int log_pick_mob(struct mob_data *md, const char *type, int nameid, int amount,
mapname="";
#ifndef TXT_ONLY
- if(log_config.sql_logs > 0)
+ if( log_config.sql_logs )
{
- if (itm==NULL) {
- //We log common item
+ if( itm == NULL ) { //We log common item
if (SQL_ERROR == Sql_Query(logmysql_handle, "INSERT DELAYED INTO `%s` (`time`, `char_id`, `type`, `nameid`, `amount`, `map`) VALUES (NOW(), '%d', '%s', '%d', '%d', '%s')",
log_config.log_pick_db, md->class_, type, nameid, amount, mapname) )
{
Sql_ShowDebug(logmysql_handle);
return 0;
}
- } else {
- //We log Extended item
+ } else { //We log Extended item
if (SQL_ERROR == Sql_Query(logmysql_handle, "INSERT DELAYED INTO `%s` (`time`, `char_id`, `type`, `nameid`, `amount`, `refine`, `card0`, `card1`, `card2`, `card3`, `map`) VALUES (NOW(), '%d', '%s', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%s')",
log_config.log_pick_db, md->class_, type, itm->nameid, amount, itm->refine, itm->card[0], itm->card[1], itm->card[2], itm->card[3], mapname) )
{
@@ -196,15 +187,10 @@ int log_pick_mob(struct mob_data *md, const char *type, int nameid, int amount,
time(&curtime);
strftime(timestring, 254, "%m/%d/%Y %H:%M:%S", localtime(&curtime));
- if (itm==NULL) {
- //We log common item
- fprintf(logfp,"%s - %d\t%s\t%d,%d,%s\n",
- timestring, md->class_, type, nameid, amount, mapname);
-
- } else {
- //We log Extended item
- fprintf(logfp,"%s - %d\t%s\t%d,%d,%d,%d,%d,%d,%d,%s\n",
- timestring, md->class_, type, itm->nameid, amount, itm->refine, itm->card[0], itm->card[1], itm->card[2], itm->card[3], mapname);
+ if( itm == NULL ) { //We log common item
+ fprintf(logfp,"%s - %d\t%s\t%d,%d,%s\n", timestring, md->class_, type, nameid, amount, mapname);
+ } else { //We log Extended item
+ fprintf(logfp,"%s - %d\t%s\t%d,%d,%d,%d,%d,%d,%d,%s\n", timestring, md->class_, type, itm->nameid, amount, itm->refine, itm->card[0], itm->card[1], itm->card[2], itm->card[3], mapname);
}
fclose(logfp);
}
@@ -220,7 +206,7 @@ int log_zeny(struct map_session_data *sd, char *type, struct map_session_data *s
nullpo_retr(0, sd);
#ifndef TXT_ONLY
- if(log_config.sql_logs > 0)
+ if( log_config.sql_logs )
{
if (SQL_ERROR == Sql_Query(logmysql_handle, "INSERT DELAYED INTO `%s` (`time`, `char_id`, `src_id`, `type`, `amount`, `map`) VALUES (NOW(), '%d', '%d', '%s', '%d', '%s')",
log_config.log_zeny_db, sd->status.char_id, src_sd->status.char_id, type, amount, mapindex_id2name(sd->mapindex)) )
@@ -252,7 +238,7 @@ int log_mvpdrop(struct map_session_data *sd, int monster_id, int *log_mvp)
nullpo_retr(0, sd);
#ifndef TXT_ONLY
- if(log_config.sql_logs > 0)
+ if( log_config.sql_logs )
{
if (SQL_ERROR == Sql_Query(logmysql_handle, "INSERT DELAYED INTO `%s` (`mvp_date`, `kill_char_id`, `monster_id`, `prize`, `mvpexp`, `map`) VALUES (NOW(), '%d', '%d', '%d', '%d', '%s') ",
log_config.log_mvpdrop_db, sd->status.char_id, monster_id, log_mvp[0], log_mvp[1], mapindex_id2name(sd->mapindex)) )
@@ -285,16 +271,10 @@ int log_atcommand(struct map_session_data* sd, const char* message)
nullpo_retr(0, sd);
#ifndef TXT_ONLY
- if(log_config.sql_logs > 0)
+ if( log_config.sql_logs )
{
SqlStmt* stmt;
- if (strlen(message) > CHAT_SIZE) {
- if (battle_config.error_log)
- ShowError("log atcommand: Received message too long from player %s (%d:%d)!\n", sd->status.name, sd->status.account_id, sd->status.char_id);
- return 0;
- }
-
stmt = SqlStmt_Malloc(logmysql_handle);
if( SQL_SUCCESS != SqlStmt_Prepare(stmt, "INSERT DELAYED INTO `%s` (`atcommand_date`, `account_id`, `char_id`, `char_name`, `map`, `command`) VALUES (NOW(), '%d', '%d', ?, '%s', ?)", log_config.log_gm_db, sd->status.account_id, sd->status.char_id, mapindex_id2name(sd->mapindex) )
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, sd->status.name, strnlen(sd->status.name, NAME_LENGTH))
@@ -330,7 +310,7 @@ int log_npc(struct map_session_data* sd, const char* message)
nullpo_retr(0, sd);
#ifndef TXT_ONLY
- if(log_config.sql_logs > 0)
+ if( log_config.sql_logs )
{
SqlStmt* stmt;
stmt = SqlStmt_Malloc(logmysql_handle);
@@ -380,20 +360,14 @@ int log_chat(const char* type, int type_id, int src_charid, int src_accid, const
return 0; //Deactivated
#ifndef TXT_ONLY
- if(log_config.sql_logs > 0)
+ if( log_config.sql_logs )
{
SqlStmt* stmt;
- if (strlen(message) > CHAT_SIZE) {
- if (battle_config.error_log)
- ShowError("log chat: Received message too long from type %d (%d:%d)!\n", type_id, src_accid, src_charid);
- return 0;
- }
-
stmt = SqlStmt_Malloc(logmysql_handle);
if( SQL_SUCCESS != SqlStmt_Prepare(stmt, "INSERT DELAYED INTO `%s` (`time`, `type`, `type_id`, `src_charid`, `src_accountid`, `src_map`, `src_map_x`, `src_map_y`, `dst_charname`, `message`) VALUES (NOW(), '%s', '%d', '%d', '%d', '%s', '%d', '%d', ?, ?)", log_config.log_chat_db, type, type_id, src_charid, src_accid, map, x, y)
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, (char*)dst_charname, safestrnlen(dst_charname, NAME_LENGTH))
- || SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, (char*)message, safestrnlen(message, CHAT_SIZE))
+ || SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, (char*)message, safestrnlen(message, CHAT_SIZE_MAX))
|| SQL_SUCCESS != SqlStmt_Execute(stmt) )
{
SqlStmt_ShowDebug(stmt);
@@ -456,7 +430,7 @@ int log_config_read(char *cfgName)
if (log_config.enable_logs&1) //Log everything.
log_config.enable_logs=0xFFFFFFFF;
} else if(strcmpi(w1,"sql_logs") == 0) {
- log_config.sql_logs = (atoi(w2));
+ log_config.sql_logs = (bool)atoi(w2);
//start of common filter settings
} else if(strcmpi(w1,"rare_items_log") == 0) {
log_config.rare_items_log = (atoi(w2));
@@ -517,31 +491,31 @@ int log_config_read(char *cfgName)
else if(strcmpi(w1, "log_branch_file") == 0) {
strcpy(log_config.log_branch, w2);
- if(log_config.branch > 0 && log_config.sql_logs < 1)
+ if(log_config.branch > 0 && !log_config.sql_logs)
ShowNotice("Logging Dead Branch Usage to file `%s`.txt\n", w2);
} else if(strcmpi(w1, "log_pick_file") == 0) {
strcpy(log_config.log_pick, w2);
- if(log_config.filter > 0 && log_config.sql_logs < 1)
+ if(log_config.filter > 0 && !log_config.sql_logs)
ShowNotice("Logging Item Picks to file `%s`.txt\n", w2);
} else if(strcmpi(w1, "log_zeny_file") == 0) {
strcpy(log_config.log_zeny, w2);
- if(log_config.zeny > 0 && log_config.sql_logs < 1)
+ if(log_config.zeny > 0 && !log_config.sql_logs)
ShowNotice("Logging Zeny to file `%s`.txt\n", w2);
} else if(strcmpi(w1, "log_mvpdrop_file") == 0) {
strcpy(log_config.log_mvpdrop, w2);
- if(log_config.mvpdrop > 0 && log_config.sql_logs < 1)
+ if(log_config.mvpdrop > 0 && !log_config.sql_logs)
ShowNotice("Logging MVP Drops to file `%s`.txt\n", w2);
} else if(strcmpi(w1, "log_gm_file") == 0) {
strcpy(log_config.log_gm, w2);
- if(log_config.gm > 0 && log_config.sql_logs < 1)
+ if(log_config.gm > 0 && !log_config.sql_logs)
ShowNotice("Logging GM Level %d Commands to file `%s`.txt\n", log_config.gm, w2);
} else if(strcmpi(w1, "log_npc_file") == 0) {
strcpy(log_config.log_npc, w2);
- if(log_config.npc > 0 && log_config.sql_logs < 1)
+ if(log_config.npc > 0 && !log_config.sql_logs)
ShowNotice("Logging NPC 'logmes' to file `%s`.txt\n", w2);
} else if(strcmpi(w1, "log_chat_file") == 0) {
strcpy(log_config.log_chat, w2);
- if(log_config.chat > 0 && log_config.sql_logs < 1)
+ if(log_config.chat > 0 && !log_config.sql_logs)
ShowNotice("Logging CHAT to file `%s`.txt\n", w2);
//support the import command, just like any other config
} else if(strcmpi(w1,"import") == 0) {
diff --git a/src/map/log.h b/src/map/log.h
index 0065b77c0..758bebd71 100644
--- a/src/map/log.h
+++ b/src/map/log.h
@@ -41,7 +41,7 @@ enum log_what {
extern struct Log_Config {
enum log_what enable_logs;
int filter;
- int sql_logs;
+ bool sql_logs;
int rare_items_log,refine_items_log,price_items_log,amount_items_log; //for filter
int branch, drop, mvpdrop, zeny, gm, npc, chat;
char log_branch[64], log_pick[64], log_zeny[64], log_mvpdrop[64], log_gm[64], log_npc[64], log_chat[64];
diff --git a/src/map/map.h b/src/map/map.h
index 6887098d9..679fd8529 100644
--- a/src/map/map.h
+++ b/src/map/map.h
@@ -163,16 +163,15 @@ enum {
MAPID_BABY_SOUL_LINKER,
};
-//Max size when inputting a string with those 'npc input boxes'
-//(also used for Graffiti, Talkie Box, Vending, and Chatrooms)
-#define MESSAGE_SIZE 80
+//Max size for inputs to Graffiti, Talkie Box and Vending text prompts
+#define MESSAGE_SIZE (79 + 1)
//String length you can write in the 'talking box'
-#define CHATBOX_SIZE 70
-//Talk max size: <name> : <message of 70> [Skotlex]
-#define CHAT_SIZE (NAME_LENGTH + 3 + CHATBOX_SIZE)
+#define CHATBOX_SIZE (70 + 1)
//Chatroom-related string sizes
#define CHATROOM_TITLE_SIZE (36 + 1)
#define CHATROOM_PASS_SIZE (8 + 1)
+//Max allowed chat text length
+#define CHAT_SIZE_MAX 150
#define DEFAULT_AUTOSAVE_INTERVAL 5*60*1000
@@ -610,7 +609,7 @@ struct map_session_data {
int npc_menu;
int npc_amount;
struct script_state *st;
- char npc_str[256];
+ char npc_str[CHATBOX_SIZE]; // for passing npc input box text to script engine
int npc_timer_id; //For player attached npc timers. [Skotlex]
unsigned int chatID;
time_t idletime;
diff --git a/src/map/script.c b/src/map/script.c
index 90ecbb82e..d229b95ef 100644
--- a/src/map/script.c
+++ b/src/map/script.c
@@ -5334,29 +5334,29 @@ BUILDIN_FUNC(input)
return 1;
}
- if(sd->state.menu_or_input){
- sd->state.menu_or_input=0;
- if( postfix=='$' )
+ if( !sd->state.menu_or_input )
+ { // first invocation, display npc input box
+ sd->state.menu_or_input = 1;
+ st->state = RERUNLINE;
+ if( postfix == '$' )
+ clif_scriptinputstr(sd,st->oid);
+ else
+ clif_scriptinput(sd,st->oid);
+ }
+ else
+ { // take received text/value and store it in the designated variable
+ sd->state.menu_or_input = 0;
+ if( postfix == '$' )
{
- set_reg(st,sd,num,name,(void*)sd->npc_str,
- script_getref(st,2));
- return 0;
+ set_reg(st,sd,num,name,(void*)sd->npc_str,script_getref(st,2));
+ }
+ else
+ {
+ // limit the input to a non-negative value smaller than 'vending_max_value' (for scripts that didn't check this)
+ sd->npc_amount = cap_value(sd->npc_amount, 0, battle_config.vending_max_value);
+ set_reg(st,sd,num,name,(void*)sd->npc_amount,script_getref(st,2));
}
- // Yor, Lupus & Fritz have messed with this.
- // Basicly it prevents negative input since most scripts do not account for them.
- sd->npc_amount = cap_value(sd->npc_amount, 0, battle_config.vending_max_value);
-
- set_reg(st,sd,num,name,(void*)sd->npc_amount,
- script_getref(st,2));
- return 0;
}
- //state.menu_or_input = 0
- st->state=RERUNLINE;
- if( postfix=='$' )
- clif_scriptinputstr(sd,st->oid);
- else
- clif_scriptinput(sd,st->oid);
- sd->state.menu_or_input=1;
return 0;
}
diff --git a/src/map/skill.c b/src/map/skill.c
index 421ceb6a8..21266e148 100644
--- a/src/map/skill.c
+++ b/src/map/skill.c
@@ -2729,8 +2729,8 @@ int skill_addtimerskill (struct block_list *src, unsigned int tick, int target,
ud = unit_bl2ud(src);
nullpo_retr(1, ud);
- for(i=0;i<MAX_SKILLTIMERSKILL && ud->skilltimerskill[i]; i++);
- if (i==MAX_SKILLTIMERSKILL) return 1;
+ ARR_FIND( 0, MAX_SKILLTIMERSKILL, i, ud->skilltimerskill[i] == 0 );
+ if( i == MAX_SKILLTIMERSKILL ) return 1;
ud->skilltimerskill[i] = ers_alloc(skill_timer_ers, struct skill_timerskill);
ud->skilltimerskill[i]->timer = add_timer(tick, skill_timerskill, src->id, i);
@@ -4393,7 +4393,10 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
case DC_SCREAM:
clif_skill_nodamage(src,bl,skillid,skilllv,1);
skill_addtimerskill(src,tick+2000,bl->id,src->x,src->y,skillid,skilllv,0,flag);
+
if (md) {
+ // custom hack to make the mob display the skill, because these skills don't show the skill use text themselves
+ //NOTE: mobs don't have the sprite animation that is used when performing this skill (will cause glitches)
char temp[128];
if (strlen(md->name) + strlen(skill_db[skillid].desc) > 120)
break; //Message won't fit on buffer. [Skotlex]