diff options
Diffstat (limited to 'src/map')
57 files changed, 2670 insertions, 1918 deletions
diff --git a/src/map/Makefile.in b/src/map/Makefile.in index b5a3d4461..3c6a3f806 100644 --- a/src/map/Makefile.in +++ b/src/map/Makefile.in @@ -1,7 +1,7 @@ # This file is part of Hercules. # http://herc.ws - http://github.com/HerculesWS/Hercules # -# Copyright (C) 2012-2015 Hercules Dev Team +# Copyright (C) 2012-2016 Hercules Dev Team # Copyright (C) Athena Dev Teams # # Hercules is free software: you can redistribute it and/or modify @@ -23,7 +23,7 @@ CONFIG_D = ../config CONFIG_H = $(wildcard $(CONFIG_D)/*.h) $(wildcard $(CONFIG_D)/*/*.h) COMMON_D = ../common -COMMON_H = $(wildcard $(COMMON_D)/*.h) +COMMON_H = $(filter-out %.p.h, $(wildcard $(COMMON_D)/*.h)) ../plugins/HPMHooking.h SYSINFO_INC = $(COMMON_D)/sysinfo.inc COMMON_INCLUDE = -I.. @@ -53,6 +53,7 @@ MAP_H = atcommand.h battle.h battleground.h buyingstore.h channel.h chat.h \ mercenary.h mob.h npc.h packets.h packets_struct.h party.h path.h \ pc.h pc_groups.h pet.h quest.h script.h searchstore.h skill.h \ status.h storage.h trade.h unit.h vending.h +MAP_PH = HAVE_MYSQL=@HAVE_MYSQL@ ifeq ($(HAVE_MYSQL),yes) @@ -95,7 +96,7 @@ help: Makefile: Makefile.in @$(MAKE) -C ../.. src/map/Makefile -$(SYSINFO_INC): $(MAP_C) $(MAP_H) $(COMMON_H) $(CONFIG_H) $(MT19937AR_H) $(LIBCONFIG_H) +$(SYSINFO_INC): $(MAP_C) $(MAP_PH) $(MAP_H) $(COMMON_H) $(CONFIG_H) $(MT19937AR_H) $(LIBCONFIG_H) @echo " MAKE $@" @$(MAKE) -C ../.. sysinfo @@ -118,12 +119,6 @@ map-server: ../../map-server@EXEEXT@ @$(CC) @STATIC@ @LDFLAGS@ -o ../../map-server@EXEEXT@ $(MAP_OBJ) $(COMMON_D)/obj_sql/common_sql.a \ $(COMMON_D)/obj_all/common.a $(MT19937AR_OBJ) $(LIBCONFIG_OBJ) @LIBS@ @MYSQL_LIBS@ -# map object files - -obj_sql/%.o: %.c $(MAP_H) $(COMMON_H) $(CONFIG_H) $(MT19937AR_H) $(LIBCONFIG_H) | obj_sql - @echo " CC $<" - @$(CC) @CFLAGS@ @DEFS@ $(COMMON_INCLUDE) $(THIRDPARTY_INCLUDE) @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< - # missing object files $(COMMON_D)/obj_all/common.a: @echo " MAKE $@" @@ -140,3 +135,11 @@ $(MT19937AR_OBJ): $(LIBCONFIG_OBJ): @echo " MAKE $@" @$(MAKE) -C $(LIBCONFIG_D) + +.SECONDEXPANSION: + +# map object files + +obj_sql/%.o: %.c $$(filter %.p.h, $(MAP_PH)) $(MAP_H) $(COMMON_H) $(CONFIG_H) $(MT19937AR_H) $(LIBCONFIG_H) | obj_sql + @echo " CC $<" + @$(CC) @CFLAGS@ @DEFS@ $(COMMON_INCLUDE) $(THIRDPARTY_INCLUDE) @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< diff --git a/src/map/atcommand.c b/src/map/atcommand.c index f28c24dcb..841cf855d 100644 --- a/src/map/atcommand.c +++ b/src/map/atcommand.c @@ -547,7 +547,7 @@ ACMD(jumpto) { return false; } - if((pl_sd=map->nick2sd((const char *)message)) == NULL && (pl_sd=map->charid2sd(atoi(message))) == NULL) { + if ((pl_sd=map->nick2sd(message)) == NULL && (pl_sd=map->charid2sd(atoi(message))) == NULL) { clif->message(fd, msg_fd(fd,3)); // Character not found. return false; } @@ -1091,9 +1091,9 @@ ACMD(kami) sscanf(message, "%199[^\n]", atcmd_output); if (stristr(info->command, "l") != NULL) - clif->broadcast(&sd->bl, atcmd_output, strlen(atcmd_output) + 1, BC_DEFAULT, ALL_SAMEMAP); + clif->broadcast(&sd->bl, atcmd_output, (int)strlen(atcmd_output) + 1, BC_DEFAULT, ALL_SAMEMAP); else - intif->broadcast(atcmd_output, strlen(atcmd_output) + 1, (*(info->command + 4) == 'b' || *(info->command + 4) == 'B') ? BC_BLUE : BC_YELLOW); + intif->broadcast(atcmd_output, (int)strlen(atcmd_output) + 1, (*(info->command + 4) == 'b' || *(info->command + 4) == 'B') ? BC_BLUE : BC_YELLOW); } else { if(!*message || (sscanf(message, "%10u %199[^\n]", &color, atcmd_output) < 2)) { clif->message(fd, msg_fd(fd,981)); // Please enter color and message (usage: @kamic <color> <message>). @@ -1104,7 +1104,7 @@ ACMD(kami) clif->message(fd, msg_fd(fd,982)); // Invalid color. return false; } - intif->broadcast2(atcmd_output, strlen(atcmd_output) + 1, color, 0x190, 12, 0, 0); + intif->broadcast2(atcmd_output, (int)strlen(atcmd_output) + 1, color, 0x190, 12, 0, 0); } return true; } @@ -1511,7 +1511,7 @@ ACMD(help) { clif->message(fd, atcmd_output); { // Display aliases - DBIterator* iter; + struct DBIterator *iter; AtCommandInfo *command_info; AliasInfo *alias_info = NULL; StringBuf buf; @@ -2747,7 +2747,7 @@ ACMD(recall) { return false; } - if((pl_sd=map->nick2sd((const char *)message)) == NULL && (pl_sd=map->charid2sd(atoi(message))) == NULL) { + if ((pl_sd=map->nick2sd(message)) == NULL && (pl_sd=map->charid2sd(atoi(message))) == NULL) { clif->message(fd, msg_fd(fd,3)); // Character not found. return false; } @@ -3072,7 +3072,7 @@ ACMD(kick) return false; } - if((pl_sd=map->nick2sd((const char *)message)) == NULL && (pl_sd=map->charid2sd(atoi(message))) == NULL) { + if ((pl_sd=map->nick2sd(message)) == NULL && (pl_sd=map->charid2sd(atoi(message))) == NULL) { clif->message(fd, msg_fd(fd,3)); // Character not found. return false; } @@ -3643,6 +3643,8 @@ ACMD(reloadbattleconf) memcpy(&prev_config, &battle_config, sizeof(prev_config)); battle->config_read(map->BATTLE_CONF_FILENAME); + if (prev_config.feature_roulette == 0 && battle_config.feature_roulette == 1 && !clif->parse_roulette_db()) + battle_config.feature_roulette = 0; if( prev_config.item_rate_mvp != battle_config.item_rate_mvp || prev_config.item_rate_common != battle_config.item_rate_common @@ -3791,7 +3793,7 @@ ACMD(mapinfo) if( pl_sd->mapindex == m_index ) { if( pl_sd->state.vending ) vend_num++; - else if ((cd = map->id2cd(pl_sd->chatID)) != NULL && cd->usersd[0] == pl_sd) + else if ((cd = map->id2cd(pl_sd->chat_id)) != NULL && cd->usersd[0] == pl_sd) chat_num++; } } @@ -3970,7 +3972,7 @@ ACMD(mapinfo) clif->message(fd, msg_fd(fd,1113)); // ----- Chats in Map ----- iter = mapit_getallusers(); for (pl_sd = BL_UCCAST(BL_PC, mapit->first(iter)); mapit->exists(iter); pl_sd = BL_UCCAST(BL_PC, mapit->next(iter))) { - if ((cd = map->id2cd(pl_sd->chatID)) != NULL && pl_sd->mapindex == m_index && cd->usersd[0] == pl_sd) { + if ((cd = map->id2cd(pl_sd->chat_id)) != NULL && pl_sd->mapindex == m_index && cd->usersd[0] == pl_sd) { safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd,1114), // Chat: %s | Player: %s | Location: %d %d cd->title, pl_sd->status.name, cd->bl.x, cd->bl.y); clif->message(fd, atcmd_output); @@ -4909,7 +4911,7 @@ ACMD(broadcast) } safesnprintf(atcmd_output, sizeof(atcmd_output), "%s: %s", sd->status.name, message); - intif->broadcast(atcmd_output, strlen(atcmd_output) + 1, BC_DEFAULT); + intif->broadcast(atcmd_output, (int)strlen(atcmd_output) + 1, BC_DEFAULT); return true; } @@ -4928,7 +4930,7 @@ ACMD(localbroadcast) safesnprintf(atcmd_output, sizeof(atcmd_output), "%s: %s", sd->status.name, message); - clif->broadcast(&sd->bl, atcmd_output, strlen(atcmd_output) + 1, BC_DEFAULT, ALL_SAMEMAP); + clif->broadcast(&sd->bl, atcmd_output, (int)strlen(atcmd_output) + 1, BC_DEFAULT, ALL_SAMEMAP); return true; } @@ -5123,8 +5125,7 @@ ACMD(follow) { return true; } - if ((pl_sd = map->nick2sd((const char *)message)) == NULL) - { + if ((pl_sd = map->nick2sd(message)) == NULL) { clif->message(fd, msg_fd(fd,3)); // Character not found. return false; } @@ -5262,7 +5263,7 @@ ACMD(clearcart) for( i = 0; i < MAX_CART; i++ ) if(sd->status.cart[i].nameid > 0) - pc->cart_delitem(sd, i, sd->status.cart[i].amount, 1, LOG_TYPE_OTHER); + pc->cart_delitem(sd, i, sd->status.cart[i].amount, 1, LOG_TYPE_COMMAND); clif->clearcart(fd); clif->updatestatus(sd,SP_CARTINFO); @@ -5277,12 +5278,13 @@ ACMD(clearcart) *------------------------------------------*/ #define MAX_SKILLID_PARTIAL_RESULTS 5 #define MAX_SKILLID_PARTIAL_RESULTS_LEN 74 /* "skill " (6) + "%d:" (up to 5) + "%s" (up to 30) + " (%s)" (up to 33) */ -ACMD(skillid) { +ACMD(skillid) +{ int i, found = 0; size_t skillen; - DBIterator* iter; - DBKey key; - DBData *data; + struct DBIterator *iter; + union DBKey key; + struct DBData *data; char partials[MAX_SKILLID_PARTIAL_RESULTS][MAX_SKILLID_PARTIAL_RESULTS_LEN]; if (!*message) { @@ -5601,7 +5603,7 @@ ACMD(changegm) { return false; } - if ((pl_sd=map->nick2sd((const char *) message)) == NULL || pl_sd->status.guild_id != sd->status.guild_id) { + if ((pl_sd=map->nick2sd(message)) == NULL || pl_sd->status.guild_id != sd->status.guild_id) { clif->message(fd, msg_fd(fd,1184)); // Target character must be online and be a guild member. return false; } @@ -5621,7 +5623,7 @@ ACMD(changeleader) { return false; } - if (party->changeleader(sd, map->nick2sd((const char *) message))) + if (party->changeleader(sd, map->nick2sd(message))) return true; return false; } @@ -6380,7 +6382,7 @@ ACMD(trade) { return false; } - if ( (pl_sd = map->nick2sd((const char *)message)) == NULL ) { + if ((pl_sd = map->nick2sd(message)) == NULL) { clif->message(fd, msg_fd(fd,3)); // Character not found. return false; } @@ -6423,8 +6425,7 @@ ACMD(unmute) { return false; } - if ((pl_sd = map->nick2sd((const char *)message)) == NULL) - { + if ((pl_sd = map->nick2sd(message)) == NULL) { clif->message(fd, msg_fd(fd,3)); // Character not found. return false; } @@ -6778,7 +6779,7 @@ ACMD(showmobs) clif->message(fd, atcmd_output); it = mapit_geteachmob(); - for (md = BL_UCCAST(BL_MOB, mapit->first(it)); mapit->next(it); md = BL_UCCAST(BL_MOB, mapit->next(it))) { + for (md = BL_UCCAST(BL_MOB, mapit->first(it)); mapit->exists(it); md = BL_UCCAST(BL_MOB, mapit->next(it))) { if( md->bl.m != sd->bl.m ) continue; if( mob_id != -1 && md->class_ != mob_id ) @@ -7665,9 +7666,10 @@ ACMD(showdelay) * @reject - reject invitation * @leave - leave duel *------------------------------------------*/ -ACMD(invite) { +ACMD(invite) +{ unsigned int did = sd->duel_group; - struct map_session_data *target_sd = map->nick2sd((const char *)message); + struct map_session_data *target_sd = map->nick2sd(message); if (did == 0) { @@ -7739,8 +7741,7 @@ ACMD(duel) { } duel->create(sd, maxpl); } else { - struct map_session_data *target_sd; - target_sd = map->nick2sd((const char *)message); + struct map_session_data *target_sd = map->nick2sd(message); if (target_sd != NULL) { unsigned int newduel; if ((newduel = duel->create(sd, 2)) != -1) { @@ -7835,7 +7836,7 @@ ACMD(cash) // If this option is set, the message is already sent by pc function if( !battle_config.cashshop_show_points ){ sprintf(output, msg_fd(fd,505), ret, sd->cashPoints); - clif_disp_onlyself(sd, output, strlen(output)); + clif_disp_onlyself(sd, output); clif->message(fd, output); } } else @@ -7843,7 +7844,7 @@ ACMD(cash) } else { if( (ret=pc->paycash(sd, -value, 0)) >= 0){ sprintf(output, msg_fd(fd,410), ret, sd->cashPoints); - clif_disp_onlyself(sd, output, strlen(output)); + clif_disp_onlyself(sd, output); clif->message(fd, output); } else clif->message(fd, msg_fd(fd,41)); // Unable to decrease the number/value. @@ -7854,7 +7855,7 @@ ACMD(cash) // If this option is set, the message is already sent by pc function if( !battle_config.cashshop_show_points ){ sprintf(output, msg_fd(fd,506), ret, sd->kafraPoints); - clif_disp_onlyself(sd, output, strlen(output)); + clif_disp_onlyself(sd, output); clif->message(fd, output); } } else @@ -7862,7 +7863,7 @@ ACMD(cash) } else { if( (ret=pc->paycash(sd, -value, -value)) >= 0){ sprintf(output, msg_fd(fd,411), ret, sd->kafraPoints); - clif_disp_onlyself(sd, output, strlen(output)); + clif_disp_onlyself(sd, output); clif->message(fd, output); } else clif->message(fd, msg_fd(fd,41)); // Unable to decrease the number/value. @@ -7882,7 +7883,7 @@ ACMD(clone) { return false; } - if ((pl_sd=map->nick2sd((const char *)message)) == NULL && (pl_sd=map->charid2sd(atoi(message))) == NULL) { + if ((pl_sd=map->nick2sd(message)) == NULL && (pl_sd=map->charid2sd(atoi(message))) == NULL) { clif->message(fd, msg_fd(fd,3)); // Character not found. return false; } @@ -7957,7 +7958,7 @@ ACMD(request) safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd,278), message); // (@request): %s intif->wis_message_to_gm(sd->status.name, PC_PERM_RECEIVE_REQUESTS, atcmd_output); - clif_disp_onlyself(sd, atcmd_output, strlen(atcmd_output)); + clif_disp_onlyself(sd, atcmd_output); clif->message(sd->fd,msg_fd(fd,279)); // @request sent. return true; } @@ -8352,7 +8353,7 @@ void atcommand_commands_sub(struct map_session_data* sd, const int fd, AtCommand char line_buff[CHATBOX_SIZE]; char* cur = line_buff; AtCommandInfo* cmd; - DBIterator *iter = db_iterator(atcommand->db); + struct DBIterator *iter = db_iterator(atcommand->db); int count = 0; memset(line_buff,' ',CHATBOX_SIZE); @@ -8498,30 +8499,34 @@ ACMD(set) CREATE(data, struct script_data,1); - if( is_str ) {// string variable - switch( reg[0] ) { + if (is_str) { + // string variable + const char *str = NULL; + switch (reg[0]) { case '@': - data->u.str = pc->readregstr(sd, script->add_str(reg)); + str = pc->readregstr(sd, script->add_str(reg)); break; case '$': - data->u.str = mapreg->readregstr(script->add_str(reg)); + str = mapreg->readregstr(script->add_str(reg)); break; case '#': - if( reg[1] == '#' ) - data->u.str = pc_readaccountreg2str(sd, script->add_str(reg));// global + if (reg[1] == '#') + str = pc_readaccountreg2str(sd, script->add_str(reg));// global else - data->u.str = pc_readaccountregstr(sd, script->add_str(reg));// local + str = pc_readaccountregstr(sd, script->add_str(reg));// local break; default: - data->u.str = pc_readglobalreg_str(sd, script->add_str(reg)); + str = pc_readglobalreg_str(sd, script->add_str(reg)); break; } - if( data->u.str == NULL || data->u.str[0] == '\0' ) {// empty string + if (str == NULL || str[0] == '\0') { + // empty string data->type = C_CONSTSTR; data->u.str = ""; - } else {// duplicate string + } else { + // duplicate string data->type = C_STR; - data->u.str = aStrdup(data->u.str); + data->u.mutstr = aStrdup(str); } } else {// integer variable data->type = C_INT; @@ -8549,7 +8554,7 @@ ACMD(set) safesnprintf(atcmd_output, sizeof(atcmd_output),msg_fd(fd,1373),reg,data->u.num); // %s value is now :%d break; case C_STR: - safesnprintf(atcmd_output, sizeof(atcmd_output),msg_fd(fd,1374),reg,data->u.str); // %s value is now :%s + safesnprintf(atcmd_output, sizeof(atcmd_output),msg_fd(fd,1374),reg,data->u.mutstr); // %s value is now :%s break; case C_CONSTSTR: safesnprintf(atcmd_output, sizeof(atcmd_output),msg_fd(fd,1375),reg); // %s is empty @@ -8822,7 +8827,7 @@ ACMD(channel) { clif->messagecolor_self(fd, channel->config->colors[k], atcmd_output); } } else { - DBIterator *iter = db_iterator(channel->db); + struct DBIterator *iter = db_iterator(channel->db); bool show_all = pc_has_permission(sd, PC_PERM_HCHSYS_ADMIN) ? true : false; clif->message(fd, msg_fd(fd,1410)); // -- Public Channels if (channel->config->local) { @@ -9052,9 +9057,9 @@ ACMD(channel) { clif->message(fd, atcmd_output); } else if (strcmpi(subcmd,"banlist") == 0) { // sub1 = channel name; sub2 = unused; sub3 = unused - DBIterator *iter = NULL; - DBKey key; - DBData *data; + struct DBIterator *iter = NULL; + union DBKey key; + struct DBData *data; bool isA = pc_has_permission(sd, PC_PERM_HCHSYS_ADMIN)?true:false; if (sub1[0] != '#') { clif->message(fd, msg_fd(fd,1405));// Channel name must start with a '#' @@ -9729,8 +9734,7 @@ const char* atcommand_checkalias(const char *aliasname) { /// AtCommand suggestion void atcommand_get_suggestions(struct map_session_data* sd, const char *name, bool is_atcmd_cmd) { - DBIterator* atcommand_iter; - DBIterator* alias_iter; + struct DBIterator *atcommand_iter, *alias_iter; AtCommandInfo* command_info = NULL; AliasInfo* alias_info = NULL; AtCommandType type = is_atcmd_cmd ? COMMAND_ATCOMMAND : COMMAND_CHARCOMMAND; @@ -10116,7 +10120,7 @@ static inline int atcommand_command_type2idx(AtCommandType type) */ void atcommand_db_load_groups(GroupSettings **groups, struct config_setting_t **commands_, size_t sz) { - DBIterator *iter = db_iterator(atcommand->db); + struct DBIterator *iter = db_iterator(atcommand->db); AtCommandInfo *atcmd; nullpo_retv(groups); @@ -10218,7 +10222,8 @@ bool atcommand_hp_add(char *name, AtCommandFunc func) { /** * @see DBApply */ -int atcommand_db_clear_sub(DBKey key, DBData *data, va_list args) { +int atcommand_db_clear_sub(union DBKey key, struct DBData *data, va_list args) +{ AtCommandInfo *cmd = DB->data2ptr(data); aFree(cmd->at_groups); aFree(cmd->char_groups); diff --git a/src/map/atcommand.h b/src/map/atcommand.h index a4f9afce7..0e7895825 100644 --- a/src/map/atcommand.h +++ b/src/map/atcommand.h @@ -94,8 +94,8 @@ struct atcommand_interface { struct atcmd_binding_data** binding; int binding_count; /* other vars */ - DBMap* db; //name -> AtCommandInfo - DBMap* alias_db; //alias -> AtCommandInfo + struct DBMap *db; //name -> AtCommandInfo + struct DBMap *alias_db; //alias -> AtCommandInfo /** * msg_table[lang_id][msg_id] * Server messages (0-499 reserved for GM commands, 500-999 reserved for others) @@ -135,7 +135,7 @@ struct atcommand_interface { /* */ void (*commands_sub) (struct map_session_data* sd, const int fd, AtCommandType type); void (*cmd_db_clear) (void); - int (*cmd_db_clear_sub) (DBKey key, DBData *data, va_list args); + int (*cmd_db_clear_sub) (union DBKey key, struct DBData *data, va_list args); void (*doload) (void); void (*base_commands) (void); bool (*add) (char *name, AtCommandFunc func, bool replace); diff --git a/src/map/battle.c b/src/map/battle.c index a7a6f4719..09b99aa05 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -3512,8 +3512,6 @@ int battle_blewcount_bonus(struct map_session_data *sd, uint16 skill_id) { struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list *target,uint16 skill_id,uint16 skill_lv,int mflag) { int nk; short s_ele = 0; - unsigned int skillratio = 100; //Skill dmg modifiers. - struct map_session_data *sd = NULL; struct status_change *sc; struct Damage ad; @@ -3666,6 +3664,7 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list ad.damage = status->get_lv(src) * 10 + sstatus->int_; break; default: { + unsigned int skillratio = 100; //Skill dmg modifiers. MATK_ADD( status->get_matk(src, 2) ); #ifdef RENEWAL ad.damage = battle->calc_cardfix(BF_MAGIC, src, target, nk, s_ele, 0, ad.damage, 0, ad.flag); @@ -4276,7 +4275,6 @@ void battle_calc_misc_attack_unknown(struct block_list *src, struct block_list * // FIXME: wflag is undocumented struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list *target,uint16 skill_id,uint16 skill_lv,int wflag) { - unsigned int skillratio = 100; //Skill dmg modifiers. short temp=0; short s_ele, s_ele_; int i, nk; @@ -4775,6 +4773,7 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list } //End hit/miss calculation if (flag.hit && !flag.infdef) { //No need to do the math for plants + unsigned int skillratio = 100; //Skill dmg modifiers. //Hitting attack //Assuming that 99% of the cases we will not need to check for the flag.rh... we don't. diff --git a/src/map/battleground.c b/src/map/battleground.c index 311690ec3..5231ce3d2 100644 --- a/src/map/battleground.c +++ b/src/map/battleground.c @@ -171,7 +171,7 @@ int bg_team_leave(struct map_session_data *sd, enum bg_team_leave_type flag) { sprintf(output, "Server : %s has been afk-kicked from the battlefield...", sd->status.name); break; } - clif->bg_message(bgd, 0, "Server", output, strlen(output) + 1); + clif->bg_message(bgd, 0, "Server", output); } if( bgd->logout_event[0] && flag ) @@ -265,21 +265,23 @@ int bg_team_get_id(struct block_list *bl) { return 0; } -bool bg_send_message(struct map_session_data *sd, const char *mes, int len) { +bool bg_send_message(struct map_session_data *sd, const char *mes) +{ struct battleground_data *bgd; nullpo_ret(sd); nullpo_ret(mes); if( sd->bg_id == 0 || (bgd = bg->team_search(sd->bg_id)) == NULL ) return false; // Couldn't send message - clif->bg_message(bgd, sd->bl.id, sd->status.name, mes, len); + clif->bg_message(bgd, sd->bl.id, sd->status.name, mes); return true; } /** * @see DBApply */ -int bg_send_xy_timer_sub(DBKey key, DBData *data, va_list ap) { +int bg_send_xy_timer_sub(union DBKey key, struct DBData *data, va_list ap) +{ struct battleground_data *bgd = DB->data2ptr(data); struct map_session_data *sd; int i; @@ -925,7 +927,8 @@ void do_init_battleground(bool minimal) { /** * @see DBApply */ -int bg_team_db_final(DBKey key, DBData *data, va_list ap) { +int bg_team_db_final(union DBKey key, struct DBData *data, va_list ap) +{ struct battleground_data* bgd = DB->data2ptr(data); HPM->data_store_destroy(&bgd->hdata); diff --git a/src/map/battleground.h b/src/map/battleground.h index bb77db125..4c3d4878f 100644 --- a/src/map/battleground.h +++ b/src/map/battleground.h @@ -102,7 +102,7 @@ struct battleground_interface { struct bg_arena **arena; unsigned char arenas; /* */ - DBMap *team_db; // int bg_id -> struct battleground_data* + struct DBMap *team_db; // int bg_id -> struct battleground_data* unsigned int team_counter; // Next bg_id /* */ void (*init) (bool minimal); @@ -130,11 +130,11 @@ struct battleground_interface { bool (*member_respawn) (struct map_session_data *sd); int (*create) (unsigned short map_index, short rx, short ry, const char *ev, const char *dev); int (*team_get_id) (struct block_list *bl); - bool (*send_message) (struct map_session_data *sd, const char *mes, int len); - int (*send_xy_timer_sub) (DBKey key, DBData *data, va_list ap); + bool (*send_message) (struct map_session_data *sd, const char *mes); + int (*send_xy_timer_sub) (union DBKey key, struct DBData *data, va_list ap); int (*send_xy_timer) (int tid, int64 tick, int id, intptr_t data); int (*afk_timer) (int tid, int64 tick, int id, intptr_t data); - int (*team_db_final) (DBKey key, DBData *data, va_list ap); + int (*team_db_final) (union DBKey key, struct DBData *data, va_list ap); /* */ enum bg_queue_types (*str2teamtype) (const char *str); /* */ diff --git a/src/map/channel.c b/src/map/channel.c index 28ef854da..ee8242b23 100644 --- a/src/map/channel.c +++ b/src/map/channel.c @@ -127,9 +127,8 @@ void channel_delete(struct channel_data *chan) nullpo_retv(chan); if (db_size(chan->users) && !channel->config->closing) { - DBIterator *iter; struct map_session_data *sd; - iter = db_iterator(chan->users); + struct DBIterator *iter = db_iterator(chan->users); for (sd = dbi_first(iter); dbi_exists(iter); sd = dbi_next(iter)) { channel->leave_sub(chan, sd); } @@ -610,7 +609,10 @@ void read_channels_config(void) local_autojoin = 0, ally_autojoin = 0, allow_user_channel_creation = 0, irc_enabled = 0, - irc_autojoin = 0; + irc_autojoin = 0, + irc_flood_protection_rate = 0, + irc_flood_protection_burst = 0, + irc_flood_protection_enabled = 0; if( !libconfig->setting_lookup_string(settings, "map_local_channel_name", &local_name) ) local_name = "map"; @@ -641,58 +643,52 @@ void read_channels_config(void) const char *irc_server, *irc_channel, *irc_nick, *irc_nick_pw; int irc_use_ghost = 0; - if( libconfig->setting_lookup_string(settings, "irc_channel_network", &irc_server) ) { - if( !strstr(irc_server,":") ) { + if (!libconfig->setting_lookup_string(settings, "irc_channel_network", &irc_server)) { + channel->config->irc = false; + ShowWarning("channels.conf : irc channel enabled but irc_channel_network wasn't found, disabling irc channel...\n"); + } else { + char *server = aStrdup(irc_server); + char *port = strchr(server, ':'); + if (port == NULL) { channel->config->irc = false; - ShowWarning("channels.conf : network port wasn't found in 'irc_channel_network', disabling irc channel...\n"); + ShowWarning("channels.conf: network port wasn't found in 'irc_channel_network', disabling irc channel...\n"); + } else if ((size_t)(port-server) > sizeof channel->config->irc_server - 1) { + channel->config->irc = false; + ShowWarning("channels.conf: server name is too long in 'irc_channel_network', disabling irc channel...\n"); } else { - unsigned char d = 0, dlen = strlen(irc_server); - char server[40]; - if (dlen > 39) - dlen = 39; - memset(server, '\0', sizeof(server)); - - for(d = 0; d < dlen; d++) { - if(irc_server[d] == ':') { - memcpy(server, irc_server, d); - safestrncpy(channel->config->irc_server, server, 40); - memcpy(server, &irc_server[d+1], dlen - d - 1); - channel->config->irc_server_port = atoi(server); - break; - } - } + *port = '\0'; + port++; + safestrncpy(channel->config->irc_server, server, sizeof channel->config->irc_server); + channel->config->irc_server_port = atoi(port); } - } else { - channel->config->irc = false; - ShowWarning("channels.conf : irc channel enabled but irc_channel_network wasn't found, disabling irc channel...\n"); + aFree(server); } - if( libconfig->setting_lookup_string(settings, "irc_channel_channel", &irc_channel) ) + if (libconfig->setting_lookup_string(settings, "irc_channel_channel", &irc_channel)) { safestrncpy(channel->config->irc_channel, irc_channel, 50); - else { + } else { channel->config->irc = false; ShowWarning("channels.conf : irc channel enabled but irc_channel_channel wasn't found, disabling irc channel...\n"); } - if( libconfig->setting_lookup_string(settings, "irc_channel_nick", &irc_nick) ) { - if( strcmpi(irc_nick,"Hercules_chSysBot") == 0 ) { + if (libconfig->setting_lookup_string(settings, "irc_channel_nick", &irc_nick)) { + if (strcmpi(irc_nick,"Hercules_chSysBot") == 0) { sprintf(channel->config->irc_nick, "Hercules_chSysBot%d",rnd()%777); - } else + } else { safestrncpy(channel->config->irc_nick, irc_nick, 40); + } } else { channel->config->irc = false; ShowWarning("channels.conf : irc channel enabled but irc_channel_nick wasn't found, disabling irc channel...\n"); } - if( libconfig->setting_lookup_string(settings, "irc_channel_nick_pw", &irc_nick_pw) ) { + if (libconfig->setting_lookup_string(settings, "irc_channel_nick_pw", &irc_nick_pw)) { safestrncpy(channel->config->irc_nick_pw, irc_nick_pw, 30); config_setting_lookup_bool(settings, "irc_channel_use_ghost", &irc_use_ghost); channel->config->irc_use_ghost = irc_use_ghost; } - } libconfig->setting_lookup_bool(settings, "map_local_channel_autojoin", &local_autojoin); libconfig->setting_lookup_bool(settings, "ally_channel_autojoin", &ally_autojoin); libconfig->setting_lookup_bool(settings, "irc_channel_autojoin", &irc_autojoin); - if (local_autojoin) channel->config->local_autojoin = true; if (ally_autojoin) @@ -700,6 +696,26 @@ void read_channels_config(void) if (irc_autojoin) channel->config->irc_autojoin = true; + libconfig->setting_lookup_bool(settings, "irc_flood_protection_enabled", &irc_flood_protection_enabled); + + if (irc_flood_protection_enabled) { + ircbot->flood_protection_enabled = true; + + libconfig->setting_lookup_int(settings, "irc_flood_protection_rate", &irc_flood_protection_rate); + libconfig->setting_lookup_int(settings, "irc_flood_protection_burst", &irc_flood_protection_burst); + + if (irc_flood_protection_rate > 0) + ircbot->flood_protection_rate = irc_flood_protection_rate; + else + ircbot->flood_protection_rate = 1000; + if (irc_flood_protection_burst > 0) + ircbot->flood_protection_burst = irc_flood_protection_burst; + else + ircbot->flood_protection_burst = 3; + } else { + ircbot->flood_protection_enabled = false; + } + libconfig->setting_lookup_bool(settings, "allow_user_channel_creation", &allow_user_channel_creation); if( allow_user_channel_creation ) @@ -814,7 +830,7 @@ int do_init_channel(bool minimal) void do_final_channel(void) { - DBIterator *iter = db_iterator(channel->db); + struct DBIterator *iter = db_iterator(channel->db); struct channel_data *chan; unsigned char i; diff --git a/src/map/channel.h b/src/map/channel.h index ac1c8f0cb..e8696fd90 100644 --- a/src/map/channel.h +++ b/src/map/channel.h @@ -21,12 +21,12 @@ #define MAP_CHANNEL_H #include "common/hercules.h" -#include "common/db.h" #include "common/mmo.h" /** * Declarations **/ +struct DBMap; // common/db.h struct map_session_data; struct guild; @@ -83,8 +83,8 @@ struct channel_data { char name[HCS_NAME_LENGTH]; char password[HCS_NAME_LENGTH]; unsigned char color; - DBMap *users; - DBMap *banned; + struct DBMap *users; + struct DBMap *banned; unsigned int options; unsigned int owner; enum channel_types type; @@ -94,7 +94,7 @@ struct channel_data { struct channel_interface { /* vars */ - DBMap *db; + struct DBMap *db; struct Channel_Config *config; int (*init) (bool minimal); diff --git a/src/map/chat.c b/src/map/chat.c index d60b9bece..df48e1f2c 100644 --- a/src/map/chat.c +++ b/src/map/chat.c @@ -97,7 +97,7 @@ bool chat_createpcchat(struct map_session_data* sd, const char* title, const cha nullpo_ret(title); nullpo_ret(pass); - if( sd->chatID ) + if (sd->chat_id != 0) return false; //Prevent people abusing the chat system by creating multiple chats, as pointed out by End of Exam. [Skotlex] if( sd->state.vending || sd->state.buyingstore ) @@ -142,8 +142,10 @@ bool chat_joinchat(struct map_session_data* sd, int chatid, const char* pass) { nullpo_ret(pass); cd = map->id2cd(chatid); - if( cd == NULL || cd->bl.type != BL_CHAT || cd->bl.m != sd->bl.m || sd->state.vending || sd->state.buyingstore || sd->chatID || ((cd->owner->type == BL_NPC) ? cd->users+1 : cd->users) >= cd->limit ) - { + if (cd == NULL || cd->bl.type != BL_CHAT || cd->bl.m != sd->bl.m + || sd->state.vending || sd->state.buyingstore || sd->chat_id != 0 + || ((cd->owner->type == BL_NPC) ? cd->users+1 : cd->users) >= cd->limit + ) { clif->joinchatfail(sd,0); // room full return false; } @@ -204,8 +206,8 @@ int chat_leavechat(struct map_session_data* sd, bool kicked) { nullpo_retr(0, sd); - cd = map->id2cd(sd->chatID); - if( cd == NULL ) { + cd = map->id2cd(sd->chat_id); + if (cd == NULL) { pc_setchatid(sd, 0); return 0; } @@ -279,7 +281,7 @@ bool chat_changechatowner(struct map_session_data* sd, const char* nextownername nullpo_ret(sd); nullpo_ret(nextownername); - cd = map->id2cd(sd->chatID); + cd = map->id2cd(sd->chat_id); if (cd == NULL || &sd->bl != cd->owner) return false; @@ -324,7 +326,7 @@ bool chat_changechatstatus(struct map_session_data* sd, const char* title, const nullpo_ret(title); nullpo_ret(pass); - cd = map->id2cd(sd->chatID); + cd = map->id2cd(sd->chat_id); if (cd == NULL || &sd->bl != cd->owner) return false; @@ -352,7 +354,7 @@ bool chat_kickchat(struct map_session_data* sd, const char* kickusername) { nullpo_ret(sd); nullpo_ret(kickusername); - cd = map->id2cd(sd->chatID); + cd = map->id2cd(sd->chat_id); if (cd == NULL || &sd->bl != cd->owner) return false; diff --git a/src/map/chat.h b/src/map/chat.h index 603d8441f..59d61a46e 100644 --- a/src/map/chat.h +++ b/src/map/chat.h @@ -23,8 +23,9 @@ #include "map/map.h" // struct block_list, CHATROOM_TITLE_SIZE #include "common/hercules.h" -#include "common/db.h" +/* Forward Declarations */ +struct DBMap; // common/db.h struct chat_data; struct map_session_data; struct npc_data; @@ -46,7 +47,7 @@ struct chat_data { struct block_list* owner; char npc_event[EVENT_NAME_LENGTH]; /* isn't this a waste? there is a enormous overhead, wouldn't something like skill_blockpc_start be better here? [Ind] */ - DBMap* kick_list; ///< DBMap of users who were kicked from this chat + struct DBMap *kick_list; ///< DBMap of users who were kicked from this chat }; /*===================================== diff --git a/src/map/chrif.c b/src/map/chrif.c index 578942897..52af1137e 100644 --- a/src/map/chrif.c +++ b/src/map/chrif.c @@ -471,7 +471,8 @@ void chrif_connectack(int fd) { /** * @see DBApply */ -int chrif_reconnect(DBKey key, DBData *data, va_list ap) { +int chrif_reconnect(union DBKey key, struct DBData *data, va_list ap) +{ struct auth_node *node = DB->data2ptr(data); nullpo_ret(node); @@ -681,7 +682,8 @@ void chrif_authfail(int fd) {/* HELLO WORLD. ip in RFIFOL 15 is not being used ( * This can still happen (client times out while waiting for char to confirm auth data) * @see DBApply */ -int auth_db_cleanup_sub(DBKey key, DBData *data, va_list ap) { +int auth_db_cleanup_sub(union DBKey key, struct DBData *data, va_list ap) +{ struct auth_node *node = DB->data2ptr(data); nullpo_retr(1, node); @@ -933,14 +935,14 @@ bool chrif_divorceack(int char_id, int partner_id) { sd->status.partner_id = 0; for(i = 0; i < MAX_INVENTORY; i++) if (sd->status.inventory[i].nameid == WEDDING_RING_M || sd->status.inventory[i].nameid == WEDDING_RING_F) - pc->delitem(sd, i, 1, 0, DELITEM_NORMAL, LOG_TYPE_OTHER); + pc->delitem(sd, i, 1, 0, DELITEM_NORMAL, LOG_TYPE_DIVORCE); } if( ( sd = map->charid2sd(partner_id) ) != NULL && sd->status.partner_id == char_id ) { sd->status.partner_id = 0; for(i = 0; i < MAX_INVENTORY; i++) if (sd->status.inventory[i].nameid == WEDDING_RING_M || sd->status.inventory[i].nameid == WEDDING_RING_F) - pc->delitem(sd, i, 1, 0, DELITEM_NORMAL, LOG_TYPE_OTHER); + pc->delitem(sd, i, 1, 0, DELITEM_NORMAL, LOG_TYPE_DIVORCE); } return true; @@ -1617,7 +1619,8 @@ void chrif_del_scdata_single(int account_id, int char_id, short type) /** * @see DBApply */ -int auth_db_final(DBKey key, DBData *data, va_list ap) { +int auth_db_final(union DBKey key, struct DBData *data, va_list ap) +{ struct auth_node *node = DB->data2ptr(data); nullpo_ret(node); diff --git a/src/map/chrif.h b/src/map/chrif.h index 6a5ec36b6..4a1e1da47 100644 --- a/src/map/chrif.h +++ b/src/map/chrif.h @@ -72,7 +72,7 @@ struct chrif_interface { /* */ struct eri *auth_db_ers; //For re-utilizing player login structures. - DBMap* auth_db; // int id -> struct auth_node* + struct DBMap *auth_db; // int id -> struct auth_node* /* */ int packet_len_table[CHRIF_PACKET_LEN_TABLE_SIZE]; int fd; @@ -133,10 +133,10 @@ struct chrif_interface { int (*check_connect_char_server) (int tid, int64 tick, int id, intptr_t data); bool (*auth_logout) (struct map_session_data *sd, enum sd_state state); void (*save_ack) (int fd); - int (*reconnect) (DBKey key, DBData *data, va_list ap); - int (*auth_db_cleanup_sub) (DBKey key, DBData *data, va_list ap); + int (*reconnect) (union DBKey key, struct DBData *data, va_list ap); + int (*auth_db_cleanup_sub) (union DBKey key, struct DBData *data, va_list ap); bool (*char_ask_name_answer) (int acc, const char* player_name, uint16 type, uint16 answer); - int (*auth_db_final) (DBKey key, DBData *data, va_list ap); + int (*auth_db_final) (union DBKey key, struct DBData *data, va_list ap); int (*send_usercount_tochar) (int tid, int64 tick, int id, intptr_t data); int (*auth_db_cleanup) (int tid, int64 tick, int id, intptr_t data); diff --git a/src/map/clif.c b/src/map/clif.c index 07b0b323b..259bc7253 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -319,17 +319,17 @@ int clif_send_sub(struct block_list *bl, va_list ap) { return 0; break; case AREA_WOC: - if (sd->chatID || bl == src_bl) + if (sd->chat_id != 0 || bl == src_bl) return 0; break; case AREA_WOSC: { if (src_bl->type == BL_PC) { const struct map_session_data *ssd = BL_UCCAST(BL_PC, src_bl); - if (ssd != NULL && sd->chatID != 0 && (sd->chatID == ssd->chatID)) + if (ssd != NULL && sd->chat_id != 0 && (sd->chat_id == ssd->chat_id)) return 0; } else if (src_bl->type == BL_NPC) { const struct npc_data *nd = BL_UCCAST(BL_NPC, src_bl); - if (nd != NULL && sd->chatID != 0 && (sd->chatID == nd->chat_id)) + if (nd != NULL && sd->chat_id != 0 && (sd->chat_id == nd->chat_id)) return 0; } } @@ -435,7 +435,7 @@ bool clif_send(const void* buf, int len, struct block_list* bl, enum send_target { const struct chat_data *cd = NULL; if (sd != NULL) { - cd = map->id2cd(sd->chatID); + cd = map->id2cd(sd->chat_id); } else { cd = BL_CCAST(BL_CHAT, bl); } @@ -1049,6 +1049,7 @@ void clif_set_unit_idle(struct block_list* bl, struct map_session_data *tsd, enu #endif #if PACKETVER >= 20150513 p.body = vd->body_style; + safestrncpy(p.name, clif->get_bl_name(bl), NAME_LENGTH); #endif clif->send(&p,sizeof(p),tsd?&tsd->bl:bl,target); @@ -1189,6 +1190,7 @@ void clif_spawn_unit(struct block_list* bl, enum send_target target) { #endif #if PACKETVER >= 20150513 p.body = vd->body_style; + safestrncpy(p.name, clif->get_bl_name(bl), NAME_LENGTH); #endif if( disguised(bl) ) { nullpo_retv(sd); @@ -1280,6 +1282,7 @@ void clif_set_unit_walking(struct block_list* bl, struct map_session_data *tsd, #endif #if PACKETVER >= 20150513 p.body = vd->body_style; + safestrncpy(p.name, clif->get_bl_name(bl), NAME_LENGTH); #endif clif->send(&p,sizeof(p),tsd?&tsd->bl:bl,target); @@ -1954,20 +1957,23 @@ void clif_selllist(struct map_session_data *sd) /// - set npcid of dialog window (0 by default) /// - if set to clear on next mes, clear contents /// - append this text -void clif_scriptmes(struct map_session_data *sd, int npcid, const char *mes) { - int fd = sd->fd; - size_t slen; +void clif_scriptmes(struct map_session_data *sd, int npcid, const char *mes) +{ + int fd, slen; nullpo_retv(sd); nullpo_retv(mes); - slen = strlen(mes) + 9; + + fd = sd->fd; + slen = (int)strlen(mes) + 9; + Assert_retv(slen <= INT16_MAX); sd->state.dialog = 1; WFIFOHEAD(fd, slen); - WFIFOW(fd,0)=0xb4; - WFIFOW(fd,2)=slen; - WFIFOL(fd,4)=npcid; + WFIFOW(fd,0) = 0xb4; + WFIFOW(fd,2) = slen; + WFIFOL(fd,4) = npcid; memcpy(WFIFOP(fd,8), mes, slen-8); WFIFOSET(fd,WFIFOW(fd,2)); } @@ -2069,24 +2075,27 @@ void clif_sendfakenpc(struct map_session_data *sd, int npcid) { /// WARNING: the 'cancel' button closes other windows besides the dialog window and the menu window. /// Which suggests their have intertwined behavior. (probably the mouse targeting) /// TODO investigate behavior of other windows [FlavioJS] -void clif_scriptmenu(struct map_session_data* sd, int npcid, const char* mes) { - int fd; - size_t slen; +void clif_scriptmenu(struct map_session_data *sd, int npcid, const char *mes) +{ + int fd, slen; struct block_list *bl = NULL; nullpo_retv(sd); nullpo_retv(mes); + fd = sd->fd; - slen = strlen(mes) + 9; + slen = (int)strlen(mes) + 9; + Assert_retv(slen <= INT16_MAX); + if (!sd->state.using_fake_npc && (npcid == npc->fake_nd->bl.id || ((bl = map->id2bl(npcid)) != NULL && (bl->m!=sd->bl.m || bl->x<sd->bl.x-AREA_SIZE-1 || bl->x>sd->bl.x+AREA_SIZE+1 || bl->y<sd->bl.y-AREA_SIZE-1 || bl->y>sd->bl.y+AREA_SIZE+1)))) clif->sendfakenpc(sd, npcid); WFIFOHEAD(fd, slen); - WFIFOW(fd,0)=0xb7; - WFIFOW(fd,2)=slen; - WFIFOL(fd,4)=npcid; + WFIFOW(fd,0) = 0xb7; + WFIFOW(fd,2) = slen; + WFIFOL(fd,4) = npcid; memcpy(WFIFOP(fd,8), mes, slen-8); WFIFOSET(fd,WFIFOW(fd,2)); } @@ -3607,26 +3616,29 @@ void clif_createchat(struct map_session_data* sd, int flag) /// 1 = public /// 2 = arena (npc waiting room) /// 3 = PK zone (non-clickable) -void clif_dispchat(struct chat_data* cd, int fd) +void clif_dispchat(struct chat_data *cd, int fd) { unsigned char buf[128]; uint8 type; + int len; - if( cd == NULL || cd->owner == NULL ) + if (cd == NULL || cd->owner == NULL) return; type = (cd->owner->type == BL_PC ) ? (cd->pub) ? 1 : 0 : (cd->owner->type == BL_NPC) ? (cd->limit) ? 2 : 3 : 1; + len = (int)strlen(cd->title); + Assert_retv(len <= INT16_MAX - 17); WBUFW(buf, 0) = 0xd7; - WBUFW(buf, 2) = 17 + strlen(cd->title); + WBUFW(buf, 2) = 17 + len; WBUFL(buf, 4) = cd->owner->id; WBUFL(buf, 8) = cd->bl.id; WBUFW(buf,12) = cd->limit; WBUFW(buf,14) = (cd->owner->type == BL_NPC) ? cd->users+1 : cd->users; WBUFB(buf,16) = type; - memcpy(WBUFP(buf,17), cd->title, strlen(cd->title)); // not zero-terminated + memcpy(WBUFP(buf,17), cd->title, len); // not zero-terminated if( fd ) { WFIFOHEAD(fd,WBUFW(buf,2)); @@ -3644,10 +3656,11 @@ void clif_dispchat(struct chat_data* cd, int fd) /// 1 = public /// 2 = arena (npc waiting room) /// 3 = PK zone (non-clickable) -void clif_changechatstatus(struct chat_data* cd) +void clif_changechatstatus(struct chat_data *cd) { unsigned char buf[128]; uint8 type; + int len; if( cd == NULL || cd->usersd[0] == NULL ) return; @@ -3655,15 +3668,17 @@ void clif_changechatstatus(struct chat_data* cd) type = (cd->owner->type == BL_PC ) ? (cd->pub) ? 1 : 0 : (cd->owner->type == BL_NPC) ? (cd->limit) ? 2 : 3 : 1; + len = (int)strlen(cd->title); + Assert_retv(len <= INT16_MAX - 17); WBUFW(buf, 0) = 0xdf; - WBUFW(buf, 2) = 17 + strlen(cd->title); + WBUFW(buf, 2) = 17 + len; WBUFL(buf, 4) = cd->owner->id; WBUFL(buf, 8) = cd->bl.id; WBUFW(buf,12) = cd->limit; WBUFW(buf,14) = (cd->owner->type == BL_NPC) ? cd->users+1 : cd->users; WBUFB(buf,16) = type; - memcpy(WBUFP(buf,17), cd->title, strlen(cd->title)); // not zero-terminated + memcpy(WBUFP(buf,17), cd->title, len); // not zero-terminated clif->send(buf,WBUFW(buf,2),cd->owner,CHAT); } @@ -4112,8 +4127,8 @@ void clif_getareachar_pc(struct map_session_data* sd,struct map_session_data* ds nullpo_retv(sd); nullpo_retv(dstsd); - if( dstsd->chatID ) { - struct chat_data *cd = map->id2cd(dstsd->chatID); + if (dstsd->chat_id != 0) { + struct chat_data *cd = map->id2cd(dstsd->chat_id); if (cd != NULL && cd->usersd[0] == dstsd) clif->dispchat(cd,sd->fd); } else if( dstsd->state.vending ) @@ -4615,9 +4630,9 @@ int clif_outsight(struct block_list *bl,va_list ap) case BL_PC: if (sd->vd.class_ != INVISIBLE_CLASS) clif->clearunit_single(bl->id,CLR_OUTSIGHT,tsd->fd); - if (sd->chatID) { - struct chat_data *cd = map->id2cd(sd->chatID); - if(cd->usersd[0]==sd) + if (sd->chat_id != 0) { + struct chat_data *cd = map->id2cd(sd->chat_id); + if (cd != NULL && cd->usersd[0] == sd) clif->dispchat(cd,tsd->fd); } if( sd->state.vending ) @@ -5475,23 +5490,24 @@ void clif_status_change(struct block_list *bl,int type,int flag,int tick,int val /// Send message (modified by [Yor]) (ZC_NOTIFY_PLAYERCHAT). /// 008e <packet len>.W <message>.?B -void clif_displaymessage(const int fd, const char* mes) { +void clif_displaymessage(const int fd, const char *mes) +{ nullpo_retv(mes); - if( map->cpsd_active && fd == 0 ) { + if (map->cpsd_active && fd == 0) { ShowInfo("HCP: %s\n",mes); - } else if ( fd > 0 ) { + } else if (fd > 0) { #if PACKETVER == 20141022 /** for some reason game client crashes depending on message pattern (only for this packet) **/ /** so we redirect to ZC_NPC_CHAT **/ clif->messagecolor_self(fd, COLOR_DEFAULT, mes); #else - size_t len; + int len = (int)strnlen(mes, 255); - if ( ( len = strnlen(mes, 255) ) > 0 ) { // don't send a void message (it's not displaying on the client chat). @help can send void line. + if (len > 0) { // don't send a void message (it's not displaying on the client chat). @help can send void line. WFIFOHEAD(fd, 5 + len); WFIFOW(fd,0) = 0x8e; - WFIFOW(fd,2) = 5 + len; // 4 + len + NULL terminate + WFIFOW(fd,2) = 5 + len; // 4 + len + NUL terminate safestrncpy(WFIFOP(fd,4), mes, len + 1); WFIFOSET(fd, 5 + len); } @@ -5513,7 +5529,7 @@ void clif_displaymessage2(const int fd, const char* mes) { line = strtok(message, "\n"); while(line != NULL) { // Limit message to 255+1 characters (otherwise it causes a buffer overflow in the client) - size_t len = strnlen(line, 255); + int len = (int)strnlen(line, 255); if (len > 0) { // don't send a void message (it's not displaying on the client chat). @help can send void line. if( map->cpsd_active && fd == 0 ) { @@ -5567,7 +5583,7 @@ void clif_displaymessage_sprintf(const int fd, const char *mes, ...) { } /// Send broadcast message in yellow or blue without font formatting (ZC_BROADCAST). /// 009a <packet len>.W <message>.?B -void clif_broadcast(struct block_list *bl, const char *mes, size_t len, int type, enum send_target target) +void clif_broadcast(struct block_list *bl, const char *mes, int len, int type, enum send_target target) { int lp = (type&BC_COLOR_MASK) ? 4 : 0; unsigned char *buf = NULL; @@ -5591,38 +5607,38 @@ void clif_broadcast(struct block_list *bl, const char *mes, size_t len, int type * Displays a message on a 'bl' to all it's nearby clients * Used by npc_globalmessage *------------------------------------------*/ -void clif_GlobalMessage(struct block_list* bl, const char* message) { +void clif_GlobalMessage(struct block_list *bl, const char *message) +{ char buf[256]; - size_t len; + int len; nullpo_retv(bl); - if(!message) + if (message == NULL) return; - len = strlen(message)+1; + len = (int)strlen(message)+1; - if (len > sizeof(buf)-8) { - ShowWarning("clif_GlobalMessage: Truncating too long message '%s' (len=%"PRIuS").\n", message, len); - len = sizeof(buf)-8; + if (len > (int)sizeof(buf)-8) { + ShowWarning("clif_GlobalMessage: Truncating too long message '%s' (len=%d).\n", message, len); + len = (int)sizeof(buf)-8; } - WBUFW(buf,0)=0x8d; - WBUFW(buf,2)=len+8; - WBUFL(buf,4)=bl->id; + WBUFW(buf,0) = 0x8d; + WBUFW(buf,2) = len+8; + WBUFL(buf,4) = bl->id; safestrncpy(WBUFP(buf,8),message,len); - clif->send((unsigned char *) buf,WBUFW(buf,2),bl,ALL_CLIENT); - + clif->send(buf,WBUFW(buf,2),bl,ALL_CLIENT); } /// Send broadcast message with font formatting (ZC_BROADCAST2). /// 01c3 <packet len>.W <fontColor>.L <fontType>.W <fontSize>.W <fontAlign>.W <fontY>.W <message>.?B -void clif_broadcast2(struct block_list* bl, const char* mes, size_t len, unsigned int fontColor, short fontType, short fontSize, short fontAlign, short fontY, enum send_target target) +void clif_broadcast2(struct block_list *bl, const char *mes, int len, unsigned int fontColor, short fontType, short fontSize, short fontAlign, short fontY, enum send_target target) { unsigned char *buf; nullpo_retv(mes); - buf = (unsigned char*)aMalloc((16 + len)*sizeof(unsigned char)); + buf = aMalloc((16 + len)*sizeof(unsigned char)); WBUFW(buf,0) = 0x1c3; WBUFW(buf,2) = len + 16; WBUFL(buf,4) = fontColor; @@ -5790,7 +5806,7 @@ void clif_upgrademessage(int fd, int result, int item_id) /// Whisper is transmitted to the destination player (ZC_WHISPER). /// 0097 <packet len>.W <nick>.24B <message>.?B /// 0097 <packet len>.W <nick>.24B <isAdmin>.L <message>.?B (PACKETVER >= 20091104) -void clif_wis_message(int fd, const char *nick, const char *mes, size_t mes_len) +void clif_wis_message(int fd, const char *nick, const char *mes, int mes_len) { #if PACKETVER >= 20091104 struct map_session_data *ssd = NULL; @@ -5799,21 +5815,21 @@ void clif_wis_message(int fd, const char *nick, const char *mes, size_t mes_len) nullpo_retv(mes); #if PACKETVER < 20091104 - WFIFOHEAD(fd, mes_len + NAME_LENGTH + 4); + WFIFOHEAD(fd, mes_len + NAME_LENGTH + 5); WFIFOW(fd,0) = 0x97; - WFIFOW(fd,2) = mes_len + NAME_LENGTH + 4; + WFIFOW(fd,2) = mes_len + NAME_LENGTH + 5; safestrncpy(WFIFOP(fd,4), nick, NAME_LENGTH); - safestrncpy(WFIFOP(fd,28), mes, mes_len); + safestrncpy(WFIFOP(fd,28), mes, mes_len + 1); WFIFOSET(fd,WFIFOW(fd,2)); #else ssd = map->nick2sd(nick); - WFIFOHEAD(fd, mes_len + NAME_LENGTH + 8); + WFIFOHEAD(fd, mes_len + NAME_LENGTH + 9); WFIFOW(fd,0) = 0x97; - WFIFOW(fd,2) = mes_len + NAME_LENGTH + 8; + WFIFOW(fd,2) = mes_len + NAME_LENGTH + 9; safestrncpy(WFIFOP(fd,4), nick, NAME_LENGTH); WFIFOL(fd,28) = (ssd && pc_get_group_level(ssd) == 99) ? 1 : 0; // isAdmin; if nonzero, also displays text above char - safestrncpy(WFIFOP(fd,32), mes, mes_len); + safestrncpy(WFIFOP(fd,32), mes, mes_len + 1); WFIFOSET(fd,WFIFOW(fd,2)); #endif } @@ -6599,7 +6615,7 @@ void clif_party_withdraw(struct party_data* p, struct map_session_data* sd, int /// Party chat message (ZC_NOTIFY_CHAT_PARTY). /// 0109 <packet len>.W <account id>.L <message>.?B -void clif_party_message(struct party_data* p, int account_id, const char* mes, int len) +void clif_party_message(struct party_data *p, int account_id, const char *mes, int len) { struct map_session_data *sd; int i; @@ -6607,22 +6623,24 @@ void clif_party_message(struct party_data* p, int account_id, const char* mes, i nullpo_retv(p); nullpo_retv(mes); - for(i=0; i < MAX_PARTY && !p->data[i].sd;i++); - if(i < MAX_PARTY){ + ARR_FIND(0, MAX_PARTY, i, p->data[i].sd != NULL); + + if (i < MAX_PARTY) { unsigned char buf[1024]; + int maxlen = (int)sizeof(buf) - 9; - if (len > sizeof(buf)-8) { - ShowWarning("clif_party_message: Truncated message '%s' (len=%d, max=%"PRIuS", party_id=%d).\n", - mes, len, sizeof(buf)-8, p->party.party_id); - len = sizeof(buf)-8; + if (len > maxlen) { + ShowWarning("clif_party_message: Truncated message '%s' (len=%d, max=%d, party_id=%d).\n", + mes, len, maxlen, p->party.party_id); + len = maxlen; } sd = p->data[i].sd; - WBUFW(buf,0)=0x109; - WBUFW(buf,2)=len+8; - WBUFL(buf,4)=account_id; - safestrncpy(WBUFP(buf,8), mes, len); - clif->send(buf,len+8,&sd->bl,PARTY); + WBUFW(buf,0) = 0x109; + WBUFW(buf,2) = len+9; + WBUFL(buf,4) = account_id; + safestrncpy(WBUFP(buf,8), mes, len+1); + clif->send(buf, len+9, &sd->bl, PARTY); } } @@ -7934,19 +7952,21 @@ void clif_marriage_proposal(int fd, struct map_session_data *sd, struct map_sess /*========================================== * Displays a message using the guild-chat colors to the specified targets. [Skotlex] *------------------------------------------*/ -void clif_disp_message(struct block_list* src, const char* mes, size_t len, enum send_target target) +void clif_disp_message(struct block_list *src, const char *mes, enum send_target target) { unsigned char buf[256]; + int len; + + nullpo_retv(mes); + nullpo_retv(src); + len = (int)strlen(mes); if (len == 0) return; - nullpo_retv(src); - nullpo_retv(mes); - - if (len > sizeof(buf)-5) { - ShowWarning("clif_disp_message: Truncated message '%s' (len=%"PRIuS", max=%"PRIuS", aid=%d).\n", mes, len, sizeof(buf)-5, src->id); - len = sizeof(buf)-5; + if (len > (int)sizeof(buf)-5) { + ShowWarning("clif_disp_message: Truncated message '%s' (len=%d, max=%"PRIuS", aid=%d).\n", mes, len, sizeof(buf)-5, src->id); + len = (int)sizeof(buf)-5; } WBUFW(buf, 0) = 0x17f; @@ -8200,10 +8220,11 @@ void clif_specialeffect_value(struct block_list* bl, int effect_id, int num, sen */ void clif_messagecolor_self(int fd, uint32 color, const char *msg) { - size_t msg_len; + int msg_len; nullpo_retv(msg); - msg_len = strlen(msg) + 1; + msg_len = (int)strlen(msg) + 1; + Assert_retv(msg_len <= INT16_MAX - 12); WFIFOHEAD(fd,msg_len + 12); WFIFOW(fd,0) = 0x2C1; @@ -8223,17 +8244,19 @@ void clif_messagecolor_self(int fd, uint32 color, const char *msg) * @param color Message color (RGB format: 0xRRGGBB) * @param msg Message text */ -void clif_messagecolor(struct block_list* bl, uint32 color, const char *msg) +void clif_messagecolor(struct block_list *bl, uint32 color, const char *msg) { - size_t msg_len = strlen(msg) + 1; + int msg_len; uint8 buf[256]; nullpo_retv(bl); nullpo_retv(msg); - if (msg_len > sizeof(buf)-12) { - ShowWarning("clif_messagecolor: Truncating too long message '%s' (len=%"PRIuS").\n", msg, msg_len); - msg_len = sizeof(buf)-12; + msg_len = (int)strlen(msg) + 1; + + if (msg_len > (int)sizeof(buf)-12) { + ShowWarning("clif_messagecolor: Truncating too long message '%s' (len=%d).\n", msg, msg_len); + msg_len = (int)sizeof(buf)-12; } WBUFW(buf,0) = 0x2C1; @@ -8313,7 +8336,7 @@ void clif_refresh(struct map_session_data *sd) clif->elemental_info(sd); map->foreachinrange(clif->getareachar,&sd->bl,AREA_SIZE,BL_ALL,sd); clif->weather_check(sd); - if( sd->chatID ) + if (sd->chat_id != 0) chat->leave(sd, false); if( sd->state.vending ) clif->openvending(sd, sd->bl.id, sd->vending); @@ -8553,34 +8576,33 @@ void clif_slide(struct block_list *bl, int x, int y) /// Public chat message (ZC_NOTIFY_CHAT). lordalfa/Skotlex - used by @me as well /// 008d <packet len>.W <id>.L <message>.?B -void clif_disp_overhead(struct block_list *bl, const char* mes) +void clif_disp_overhead(struct block_list *bl, const char *mes) { unsigned char buf[256]; //This should be more than sufficient, the theoretical max is CHAT_SIZE + 8 (pads and extra inserted crap) - size_t len_mes; + int mes_len; nullpo_retv(bl); nullpo_retv(mes); - len_mes = strlen(mes)+1; //Account for \0 + mes_len = (int)strlen(mes)+1; //Account for \0 - if (len_mes > sizeof(buf)-8) { - ShowError("clif_disp_overhead: Message too long (length %"PRIuS")\n", len_mes); - len_mes = sizeof(buf)-8; //Trunk it to avoid problems. + if (mes_len > (int)sizeof(buf)-8) { + ShowError("clif_disp_overhead: Message too long (length %d)\n", mes_len); + mes_len = sizeof(buf)-8; //Trunk it to avoid problems. } // send message to others WBUFW(buf,0) = 0x8d; - WBUFW(buf,2) = len_mes + 8; // len of message + 8 (command+len+id) + WBUFW(buf,2) = mes_len + 8; // len of message + 8 (command+len+id) WBUFL(buf,4) = bl->id; - safestrncpy(WBUFP(buf,8), mes, len_mes); + safestrncpy(WBUFP(buf,8), mes, mes_len); clif->send(buf, WBUFW(buf,2), bl, AREA_CHAT_WOC); // send back message to the speaker - if( bl->type == BL_PC ) { + if (bl->type == BL_PC) { WBUFW(buf,0) = 0x8e; - WBUFW(buf, 2) = len_mes + 4; - safestrncpy(WBUFP(buf,4), mes, len_mes); + WBUFW(buf, 2) = mes_len + 4; + safestrncpy(WBUFP(buf,4), mes, mes_len); clif->send(buf, WBUFW(buf,2), bl, SELF); } - } /*========================== @@ -8864,120 +8886,153 @@ void clif_msgtable_skill(struct map_session_data* sd, uint16 skill_id, int msg_i WFIFOSET(fd, packet_len(0x7e6)); } -/// Validates one global/guild/party/whisper message packet and tries to recognize its components. -/// Returns true if the packet was parsed successfully. -/// Formats: 0 - <packet id>.w <packet len>.w (<name> : <message>).?B 00 -/// 1 - <packet id>.w <packet len>.w <name>.24B <message>.?B 00 -bool clif_process_message(struct map_session_data *sd, int format, const char **name_, size_t *namelen_, const char **message_, size_t *messagelen_) +/** + * Validates and processes a global/guild/party message packet. + * + * @param[in] sd The source character. + * @param[in] packet The packet data. + * @param[out] out_buf The output buffer (must be a valid buffer), that will + * be filled with "Name : Message". + * @param[in] out_buflen The size of out_buf (including the NUL terminator). + * @return a pointer to the "Message" part of out_buf. + * @retval NULL if the validation failed, the messages was a command or the + * character can't send chat messages. out_buf shan't be used. + */ +const char *clif_process_chat_message(struct map_session_data *sd, const struct packet_chat_message *packet, char *out_buf, int out_buflen) { - const char *text, *name, *message; - unsigned int packetlen, textlen; - size_t namelen, messagelen; - int fd = sd->fd; + const char *srcname = NULL, *srcmessage = NULL, *message = NULL; + int textlen = 0, namelen = 0, messagelen = 0; - nullpo_retr(false, sd); - nullpo_retr(false, name_); - nullpo_retr(false, namelen_); - nullpo_retr(false, message_); - nullpo_retr(false, messagelen_); - - *name_ = NULL; - *namelen_ = 0; - *message_ = NULL; - *messagelen_ = 0; - - packetlen = RFIFOW(fd,2); - // basic structure checks - if (packetlen < 4 + 1) { + nullpo_ret(sd); + nullpo_ret(packet); + nullpo_ret(out_buf); + + if (packet->packet_len < 4 + 1) { // 4-byte header and at least an empty string is expected - ShowWarning("clif_process_message: Received malformed packet from player '%s' (no message data)!\n", sd->status.name); - return false; + ShowWarning("clif_process_chat_message: Received malformed packet from player '%s' (no message data)!\n", sd->status.name); + return NULL; } - text = RFIFOP(fd,4); - textlen = packetlen - 4; +#if PACKETVER >= 20151001 + // Packet doesn't include a NUL terminator + textlen = packet->packet_len - 4; +#else // PACKETVER < 20151001 + // Packet includes a NUL terminator + textlen = packet->packet_len - 4 - 1; +#endif // PACKETVER > 20151001 - // process <name> part of the packet - if( format == 0 ) - {// name and message are separated by ' : ' - // validate name - name = text; - namelen = strnlen(sd->status.name, NAME_LENGTH-1); // name length (w/o zero byte) + // name and message are separated by ' : ' + srcname = packet->message; + namelen = (int)strnlen(sd->status.name, NAME_LENGTH-1); // name length (w/o zero byte) - if( strncmp(name, sd->status.name, namelen) || // the text must start with the speaker's name - name[namelen] != ' ' || name[namelen+1] != ':' || name[namelen+2] != ' ' ) // followed by ' : ' - { - //Hacked message, or infamous "client desynchronize" issue where they pick one char while loading another. - ShowWarning("clif_process_message: Player '%s' sent a message using an incorrect name! Forcing a relog...\n", sd->status.name); - sockt->eof(fd); // Just kick them out to correct it. - return false; - } + if (strncmp(srcname, sd->status.name, namelen) != 0 // the text must start with the speaker's name + || srcname[namelen] != ' ' || srcname[namelen+1] != ':' || srcname[namelen+2] != ' ' // followed by ' : ' + ) { + //Hacked message, or infamous "client desynchronize" issue where they pick one char while loading another. + ShowWarning("clif_process_chat_message: Player '%s' sent a message using an incorrect name! Forcing a relog...\n", sd->status.name); + sockt->eof(sd->fd); // Just kick them out to correct it. + return NULL; + } + + srcmessage = packet->message + namelen + 3; // <name> " : " <message> + messagelen = textlen - namelen - 3; - message = name + namelen + 3; - messagelen = textlen - namelen - 3; // this should be the message length (w/ zero byte included) + if (messagelen >= CHAT_SIZE_MAX || textlen >= out_buflen) { + // messages mustn't be too long + // Normally you can only enter CHATBOX_SIZE-1 letters into the chat box, but Frost Joke / Dazzler's text can be longer. + // Also, the physical size of strings that use multibyte encoding can go multiple times over the chatbox capacity. + // Neither the official client nor server place any restriction on the length of the data in the packet, + // but we'll only allow reasonably long strings here. This also makes sure that they fit into the `chatlog` table. + ShowWarning("clif_process_chat_message: Player '%s' sent a message too long ('%.*s')!\n", sd->status.name, CHATBOX_SIZE-1, srcmessage); + return NULL; } - else - {// name has fixed width - if( textlen < NAME_LENGTH + 1 ) - { - ShowWarning("clif_process_message: Received malformed packet from player '%s' (packet length is incorrect)!\n", sd->status.name); - return false; - } - // validate name - name = text; - namelen = strnlen(name, NAME_LENGTH-1); // name length (w/o zero byte) + safestrncpy(out_buf, packet->message, textlen+1); // [!] packet->message is not necessarily NUL terminated + message = out_buf + namelen + 3; - if (name[namelen] != '\0') { - // only restriction is that the name must be zero-terminated - ShowWarning("clif_process_message: Player '%s' sent an unterminated name!\n", sd->status.name); - return false; - } + if (!pc->process_chat_message(sd, message)) + return NULL; + return message; +} - message = name + NAME_LENGTH; - messagelen = textlen - NAME_LENGTH; // this should be the message length (w/ zero byte included) - } +/** + * Validates and processes a whisper message packet. + * + * @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). + * @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. + * @retval false if the validation failed, the messages was a command or the + * character can't send chat messages. out_name and out_message + * shan't be used. + */ +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; + + nullpo_retr(false, sd); + nullpo_retr(false, packet); + nullpo_retr(false, out_name); + nullpo_retr(false, out_message); - if (messagelen != strnlen(message, messagelen)+1) { - // the declared length must match real length - ShowWarning("clif_process_message: Received malformed packet from player '%s' (length is incorrect)!\n", sd->status.name); + if (packet->packet_len < NAME_LENGTH + 4 + 1) { + // 4-byte header and at least an empty string is expected + ShowWarning("clif_process_whisper_message: Received malformed packet from player '%s' (packet length is incorrect)!\n", sd->status.name); return false; } - // verify <message> part of the packet - if (message[messagelen-1] != '\0') { - // message must be zero-terminated - ShowWarning("clif_process_message: Player '%s' sent an unterminated message string!\n", sd->status.name); + + // 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 (messagelen > CHAT_SIZE_MAX-1) { + +#if PACKETVER >= 20151001 + // Packet doesn't include a NUL terminator + messagelen = packet->packet_len - NAME_LENGTH - 4; +#else // PACKETVER < 20151001 + // Packet includes a NUL terminator + messagelen = packet->packet_len - NAME_LENGTH - 4 - 1; +#endif // PACKETVER > 20151001 + + if (messagelen >= CHAT_SIZE_MAX || messagelen >= out_messagelen) { // messages mustn't be too long // Normally you can only enter CHATBOX_SIZE-1 letters into the chat box, but Frost Joke / Dazzler's text can be longer. // Also, the physical size of strings that use multibyte encoding can go multiple times over the chatbox capacity. // Neither the official client nor server place any restriction on the length of the data in the packet, // but we'll only allow reasonably long strings here. This also makes sure that they fit into the `chatlog` table. - ShowWarning("clif_process_message: Player '%s' sent a message too long ('%.*s')!\n", sd->status.name, CHAT_SIZE_MAX-1, message); + ShowWarning("clif_process_whisper_message: Player '%s' sent a message too long ('%.*s')!\n", sd->status.name, CHAT_SIZE_MAX-1, packet->message); return false; } - *name_ = name; - *namelen_ = namelen; - *message_ = message; - *messagelen_ = messagelen; + safestrncpy(out_name, packet->name, namelen+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)) + return false; + return true; } void clif_channel_msg(struct channel_data *chan, struct map_session_data *sd, char *msg) { - DBIterator *iter; + struct DBIterator *iter; struct map_session_data *user; - unsigned short msg_len; + int msg_len; uint32 color; nullpo_retv(chan); nullpo_retv(sd); nullpo_retv(msg); iter = db_iterator(chan->users); - msg_len = strlen(msg) + 1; + msg_len = (int)strlen(msg) + 1; + Assert_retv(msg_len <= INT16_MAX - 12); color = channel->config->colors[chan->color]; WFIFOHEAD(sd->fd,msg_len + 12); @@ -9002,16 +9057,17 @@ void clif_channel_msg(struct channel_data *chan, struct map_session_data *sd, ch void clif_channel_msg2(struct channel_data *chan, char *msg) { - DBIterator *iter; + struct DBIterator *iter; struct map_session_data *user; unsigned char buf[210]; - unsigned short msg_len; + int msg_len; uint32 color; nullpo_retv(chan); nullpo_retv(msg); iter = db_iterator(chan->users); - msg_len = strlen(msg) + 1; + msg_len = (int)strlen(msg) + 1; + Assert_retv(msg_len <= INT16_MAX - 12); color = channel->config->colors[chan->color]; WBUFW(buf,0) = 0x2C1; @@ -9377,7 +9433,7 @@ void clif_parse_LoadEndAck(int fd, struct map_session_data *sd) { if( map->list[sd->bl.m].flag.allowks && !map_flag_ks(sd->bl.m) ) { char output[128]; sprintf(output, "[ Kill Steal Protection Disabled. KS is allowed in this map ]"); - clif->broadcast(&sd->bl, output, strlen(output) + 1, BC_BLUE, SELF); + clif->broadcast(&sd->bl, output, (int)strlen(output) + 1, BC_BLUE, SELF); } map->iwall_get(sd); // Updates Walls Info on this Map to Client @@ -9709,144 +9765,108 @@ int clif_undisguise_timer(int tid, int64 tick, int id, intptr_t data) { return 0; } -void clif_parse_GlobalMessage(int fd, struct map_session_data* sd) __attribute__((nonnull (2))); -/// Validates and processes global messages -/// 008c <packet len>.W <text>.?B (<name> : <message>) 00 (CZ_REQUEST_CHAT) -/// There are various variants of this packet. -void clif_parse_GlobalMessage(int fd, struct map_session_data* sd) +/** + * Validates and processed global messages. + * + * There are various variants of this packet. + * + * @code + * 008c <packet len>.W <text>.?B (<name> : <message>) 00 (CZ_REQUEST_CHAT) + * @endcode + * + * @param fd The incoming file descriptor. + * @param sd The related character. + */ +void clif_parse_GlobalMessage(int fd, struct map_session_data *sd) __attribute__((nonnull (2))); +void clif_parse_GlobalMessage(int fd, struct map_session_data *sd) { - const char *text = RFIFOP(fd,4); - size_t textlen = RFIFOW(fd,2) - 4; - - const char *name = NULL, *message = NULL; - char *fakename = NULL; - size_t namelen, messagelen; + const struct packet_chat_message *packet = NULL; + char full_message[CHAT_SIZE_MAX + NAME_LENGTH + 3 + 1]; + const char *message = NULL; + bool is_fakename = false; + int outlen = 0; - bool is_fake; - - // validate packet and retrieve name and message - if( !clif->process_message(sd, 0, &name, &namelen, &message, &messagelen) ) + packet = RP2PTR(fd); + message = clif->process_chat_message(sd, packet, full_message, sizeof full_message); + if (message == NULL) return; - if( atcommand->exec(fd, sd, message, true) ) - return; + pc->check_supernovice_call(sd, message); - if( !pc->can_talk(sd) ) + if (sd->gcbind != NULL) { + channel->send(sd->gcbind, sd, message); return; - - if( battle_config.min_chat_delay ) { //[Skotlex] - if (DIFF_TICK(sd->cantalk_tick, timer->gettick()) > 0) - return; - sd->cantalk_tick = timer->gettick() + battle_config.min_chat_delay; } - if( (sd->class_&MAPID_UPPERMASK) == MAPID_SUPER_NOVICE ) { - unsigned int next = pc->nextbaseexp(sd); - if( next == 0 ) next = pc->thisbaseexp(sd); - if( next ) { // 0%, 10%, 20%, ... - int percent = (int)( ( (float)sd->status.base_exp/(float)next )*1000. ); - if( (battle_config.snovice_call_type || percent) && ( percent%100 ) == 0 ) {// 10.0%, 20.0%, ..., 90.0% - switch (sd->state.snovice_call_flag) { - case 0: - if( strstr(message, msg_txt(1479)) ) // "Dear angel, can you hear my voice?" - sd->state.snovice_call_flag = 1; - break; - case 1: { - char buf[256]; - snprintf(buf, 256, msg_txt(1480), sd->status.name); - if( strstr(message, buf) ) // "I am %s Super Novice~" - sd->state.snovice_call_flag = 2; - } - break; - case 2: - if( strstr(message, msg_txt(1481)) ) // "Help me out~ Please~ T_T" - sd->state.snovice_call_flag = 3; - break; - case 3: - sc_start(NULL,&sd->bl, status->skill2sc(MO_EXPLOSIONSPIRITS), 100, 17, skill->get_time(MO_EXPLOSIONSPIRITS, 5)); //Lv17-> +50 critical (noted by Poki) [Skotlex] - clif->skill_nodamage(&sd->bl, &sd->bl, MO_EXPLOSIONSPIRITS, 5, 1); // prayer always shows successful Lv5 cast and disregards noskill restrictions - sd->state.snovice_call_flag = 0; - break; - } - } - } + if (sd->fakename[0] != '\0') { + is_fakename = true; + outlen = (int)strlen(sd->fakename) + (int)strlen(message) + 3 + 1; + } else { + outlen = (int)strlen(full_message) + 1; } - pc->update_idle_time(sd, BCIDLE_CHAT); - - if( sd->gcbind ) { - channel->send(sd->gcbind,sd,message); - return; - } else if ( sd->fontcolor && !sd->chatID ) { - char mout[200]; - unsigned char mylen = 1; + if (sd->fontcolor != 0 && sd->chat_id == 0) { uint32 color = 0; - if( sd->disguise == -1 ) { + if (sd->disguise == -1) { sd->fontcolor_tid = timer->add(timer->gettick()+5000, clif->undisguise_timer, sd->bl.id, 0); pc->disguise(sd,sd->status.class_); - if( pc_isdead(sd) ) + if (pc_isdead(sd)) clif->clearunit_single(-sd->bl.id, CLR_DEAD, sd->fd); - if( unit->is_walking(&sd->bl) ) + if (unit->is_walking(&sd->bl)) clif->move(&sd->ud); - } else if ( sd->disguise == sd->status.class_ && sd->fontcolor_tid != INVALID_TIMER ) { + } else if (sd->disguise == sd->status.class_ && sd->fontcolor_tid != INVALID_TIMER) { const struct TimerData *td; - if( (td = timer->get(sd->fontcolor_tid)) ) { + if ((td = timer->get(sd->fontcolor_tid)) != NULL) timer->settick(sd->fontcolor_tid, td->tick+5000); - } } - mylen += snprintf(mout, 200, "%s : %s",sd->fakename[0]?sd->fakename:sd->status.name,message); - color = channel->config->colors[sd->fontcolor - 1]; - WFIFOHEAD(fd,mylen + 12); + WFIFOHEAD(fd, outlen + 12); WFIFOW(fd,0) = 0x2C1; - WFIFOW(fd,2) = mylen + 12; + WFIFOW(fd,2) = outlen + 12; WFIFOL(fd,4) = sd->bl.id; WFIFOL(fd,8) = RGB2BGR(color); - safestrncpy(WFIFOP(fd,12), mout, mylen); + if (is_fakename) + safesnprintf(WFIFOP(fd, 12), outlen, "%s : %s", sd->fakename, message); + else + safestrncpy(WFIFOP(fd, 12), full_message, outlen); clif->send(WFIFOP(fd,0), WFIFOW(fd,2), &sd->bl, AREA_WOS); WFIFOL(fd,4) = -sd->bl.id; - WFIFOSET(fd, mylen + 12); + WFIFOSET(fd, outlen + 12); return; } - /** - * Fake Name Design by FatalEror (bug report #9) - **/ - if( ( is_fake = ( sd->fakename[0] ) ) ) { - fakename = (char*) aMalloc(strlen(sd->fakename)+messagelen+3); - strcpy(fakename, sd->fakename); - strcat(fakename, " : "); - strcat(fakename, message); - textlen = strlen(fakename) + 1; + { + // send message to others + void *buf = aMalloc(8 + outlen); + WBUFW(buf, 0) = 0x8d; + WBUFW(buf, 2) = 8 + outlen; + WBUFL(buf, 4) = sd->bl.id; + if (is_fakename) + safesnprintf(WBUFP(buf, 8), outlen, "%s : %s", sd->fakename, message); + else + safestrncpy(WBUFP(buf, 8), full_message, outlen); + //FIXME: chat has range of 9 only + clif->send(buf, WBUFW(buf, 2), &sd->bl, sd->chat_id != 0 ? CHAT_WOS : AREA_CHAT_WOC); + aFree(buf); } - // send message to others (using the send buffer for temp. storage) - WFIFOHEAD(fd, 8 + textlen); - WFIFOW(fd,0) = 0x8d; - WFIFOW(fd,2) = 8 + textlen; - WFIFOL(fd,4) = sd->bl.id; - safestrncpy(WFIFOP(fd,8), is_fake ? fakename : text, textlen); - //FIXME: chat has range of 9 only - clif->send(WFIFOP(fd,0), WFIFOW(fd,2), &sd->bl, sd->chatID ? CHAT_WOS : AREA_CHAT_WOC); // send back message to the speaker - if( is_fake ) { - WFIFOW(fd,0) = 0x8e; - WFIFOW(fd,2) = textlen + 4; - safestrncpy(WFIFOP(fd,4), fakename, textlen); - aFree(fakename); - } else { - memcpy(WFIFOP(fd,0), RFIFOP(fd,0), RFIFOW(fd,2)); - WFIFOW(fd,0) = 0x8e; - } + WFIFOHEAD(fd, 4 + outlen); + WFIFOW(fd, 0) = 0x8e; + WFIFOW(fd, 2) = 4 + outlen; + if (is_fakename) + safesnprintf(WFIFOP(fd, 4), outlen, "%s : %s", sd->fakename, message); + else + safestrncpy(WFIFOP(fd, 4), full_message, outlen); WFIFOSET(fd, WFIFOW(fd,2)); // Chat logging type 'O' / Global Chat logs->chat(LOG_CHAT_GLOBAL, 0, sd->status.char_id, sd->status.account_id, mapindex_id2name(sd->mapindex), sd->bl.x, sd->bl.y, NULL, message); // trigger listening npcs - map->foreachinrange(npc_chat->sub, &sd->bl, AREA_SIZE, BL_NPC, text, textlen, &sd->bl); + map->foreachinrange(npc_chat->sub, &sd->bl, AREA_SIZE, BL_NPC, full_message, strlen(full_message), &sd->bl); } void clif_parse_MapMove(int fd, struct map_session_data *sd) __attribute__((nonnull (2))); @@ -10119,37 +10139,28 @@ void clif_parse_Restart(int fd, struct map_session_data *sd) { } } -void clif_parse_WisMessage(int fd, struct map_session_data* sd) __attribute__((nonnull (2))); -/// Validates and processes whispered messages (CZ_WHISPER). -/// 0096 <packet len>.W <nick>.24B <message>.?B +/** + * Validates and processes whispered messages (CZ_WHISPER). + * + * @code + * 0096 <packet len>.W <nick>.24B <message>.?B + * @endcode + * + * @param fd The incoming file descriptor. + * @param sd The related character. + */ +void clif_parse_WisMessage(int fd, struct map_session_data *sd) __attribute__((nonnull (2))); void clif_parse_WisMessage(int fd, struct map_session_data* sd) { struct map_session_data* dstsd; int i; - const char *target, *message; - size_t namelen, messagelen; - - // validate packet and retrieve name and message - if( !clif->process_message(sd, 1, &target, &namelen, &message, &messagelen) ) - return; - - if ( atcommand->exec(fd, sd, message, true) ) - return; + char target[NAME_LENGTH], message[CHAT_SIZE_MAX + 1]; + const struct packet_whisper_message *packet = RP2PTR(fd); - // Statuses that prevent the player from whispering - if( !pc->can_talk(sd) ) + if (!clif->process_whisper_message(sd, packet, target, message, sizeof message)) return; - if (battle_config.min_chat_delay) { //[Skotlex] - if (DIFF_TICK(sd->cantalk_tick, timer->gettick()) > 0) { - return; - } - sd->cantalk_tick = timer->gettick() + battle_config.min_chat_delay; - } - - pc->update_idle_time(sd, BCIDLE_CHAT); - // Chat logging type 'W' / Whisper logs->chat(LOG_CHAT_WHISPER, 0, sd->status.char_id, sd->status.account_id, mapindex_id2name(sd->mapindex), sd->bl.x, sd->bl.y, target, message); @@ -10219,7 +10230,7 @@ void clif_parse_WisMessage(int fd, struct map_session_data* sd) // if there are 'Test' player on an other map-server and 'test' player on this map-server, // and if we ask for 'Test', we must not contact 'test' player // so, we send information to inter-server, which is the only one which decide (and copy correct name). - intif->wis_message(sd, target, message, messagelen); + intif->wis_message(sd, target, message, (int)strlen(message)); return; } @@ -10233,10 +10244,10 @@ void clif_parse_WisMessage(int fd, struct map_session_data* sd) } // if player is autotrading - if( dstsd->state.autotrade ) { + if (dstsd->state.autotrade) { char output[256]; sprintf(output, "%s is in autotrade mode and cannot receive whispered messages.", dstsd->status.name); - clif->wis_message(fd, map->wisp_server_name, output, strlen(output) + 1); + clif->wis_message(fd, map->wisp_server_name, output, (int)strlen(output)); return; } @@ -10253,7 +10264,7 @@ void clif_parse_WisMessage(int fd, struct map_session_data* sd) clif->wis_end(fd, 0); // 0: success to send wisper // Normal message - clif->wis_message(dstsd->fd, sd->status.name, message, messagelen); + clif->wis_message(dstsd->fd, sd->status.name, message, (int)strlen(message)); } void clif_parse_Broadcast(int fd, struct map_session_data *sd) __attribute__((nonnull (2))); @@ -10370,7 +10381,7 @@ void clif_parse_UseItem(int fd, struct map_session_data *sd) return; } - if ( (!sd->npc_id && pc_istrading(sd)) || sd->chatID ) + if ((!sd->npc_id && pc_istrading(sd)) || sd->chat_id != 0) return; //Whether the item is used or not is irrelevant, the char ain't idle. [Skotlex] @@ -10730,10 +10741,10 @@ void clif_noask_sub(struct map_session_data *src, struct map_session_data *targe nullpo_retv(src); // Your request has been rejected by autoreject option. msg = msg_sd(src,392); - clif_disp_onlyself(src, msg, strlen(msg)); + clif_disp_onlyself(src, msg); //Notice that a request was rejected. snprintf(output, 256, msg_sd(target,393+type), src->status.name, 256); - clif_disp_onlyself(target, output, strlen(output)); + clif_disp_onlyself(target, output); } void clif_parse_TradeRequest(int fd,struct map_session_data *sd) __attribute__((nonnull (2))); @@ -10744,7 +10755,7 @@ void clif_parse_TradeRequest(int fd,struct map_session_data *sd) { t_sd = map->id2sd(RFIFOL(fd,2)); - if(!sd->chatID && pc_cant_act(sd)) + if (sd->chat_id == 0 && pc_cant_act(sd)) return; //You can trade while in a chatroom. // @noask [LuzZza] @@ -11521,7 +11532,7 @@ void clif_parse_OneClick_ItemIdentify(int fd, struct map_session_data *sd) return; if ((n = pc->have_magnifier(sd) ) != INDEX_NOT_FOUND && - pc->delitem(sd, n, 1, 0, DELITEM_NORMAL, LOG_TYPE_OTHER) == 0) + pc->delitem(sd, n, 1, 0, DELITEM_NORMAL, LOG_TYPE_CONSUME) == 0) skill->identify(sd, idx); } @@ -11949,36 +11960,26 @@ void clif_parse_PartyChangeOption(int fd, struct map_session_data *sd) #endif } -void clif_parse_PartyMessage(int fd, struct map_session_data* sd) __attribute__((nonnull (2))); -/// Validates and processes party messages (CZ_REQUEST_CHAT_PARTY). -/// 0108 <packet len>.W <text>.?B (<name> : <message>) 00 -void clif_parse_PartyMessage(int fd, struct map_session_data* sd) +/** + * Validates and processes party messages (CZ_REQUEST_CHAT_PARTY). + * + * @code + * 0108 <packet len>.W <text>.?B (<name> : <message>) 00 + * @endcode + * + * @param fd The incoming file descriptor. + * @param sd The related character. + */ +void clif_parse_PartyMessage(int fd, struct map_session_data *sd) __attribute__((nonnull (2))); +void clif_parse_PartyMessage(int fd, struct map_session_data *sd) { - const char *text = RFIFOP(fd,4); - int textlen = RFIFOW(fd,2) - 4; - - const char *name, *message; - size_t namelen, messagelen; + const struct packet_chat_message *packet = RP2PTR(fd); + char message[CHAT_SIZE_MAX + NAME_LENGTH + 3 + 1]; - // validate packet and retrieve name and message - if( !clif->process_message(sd, 0, &name, &namelen, &message, &messagelen) ) + if (clif->process_chat_message(sd, packet, message, sizeof message) == NULL) return; - if( atcommand->exec(fd, sd, message, true) ) - return; - - if( !pc->can_talk(sd) ) - return; - - if (battle_config.min_chat_delay) { - if (DIFF_TICK(sd->cantalk_tick, timer->gettick()) > 0) - return; - sd->cantalk_tick = timer->gettick() + battle_config.min_chat_delay; - } - - pc->update_idle_time(sd, BCIDLE_CHAT); - - party->send_message(sd, text, textlen); + party->send_message(sd, message); } void clif_parse_PartyChangeLeader(int fd, struct map_session_data* sd) __attribute__((nonnull (2))); @@ -12820,7 +12821,7 @@ bool clif_validate_emblem(const uint8 *emblem, unsigned long emblem_len) { //uint8 b; //uint8 g; //uint8 r; - unsigned int rgb:24; + uint32 rgb:24; } __attribute__((packed)); #if !defined(sun) && (!defined(__NETBSD__) || __NetBSD_Version__ >= 600000000) // NetBSD 5 and Solaris don't like pragma pack but accept the packed attribute #pragma pack(pop) @@ -13057,39 +13058,29 @@ void clif_parse_GuildExpulsion(int fd,struct map_session_data *sd) { guild->expulsion(sd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10), RFIFOP(fd,14)); } -void clif_parse_GuildMessage(int fd, struct map_session_data* sd) __attribute__((nonnull (2))); -/// Validates and processes guild messages (CZ_GUILD_CHAT). -/// 017e <packet len>.W <text>.?B (<name> : <message>) 00 -void clif_parse_GuildMessage(int fd, struct map_session_data* sd) +/** + * Validates and processes guild messages (CZ_GUILD_CHAT). + * + * @code + * 017e <packet len>.W <text>.?B (<name> : <message>) 00 + * @endcode + * + * @param fd The incoming file descriptor. + * @param sd The related character. + */ +void clif_parse_GuildMessage(int fd, struct map_session_data *sd) __attribute__((nonnull (2))); +void clif_parse_GuildMessage(int fd, struct map_session_data *sd) { - const char *text = RFIFOP(fd,4); - int textlen = RFIFOW(fd,2) - 4; + const struct packet_chat_message *packet = RP2PTR(fd); + char message[CHAT_SIZE_MAX + NAME_LENGTH + 3 + 1]; - const char *name, *message; - size_t namelen, messagelen; - - // validate packet and retrieve name and message - if( !clif->process_message(sd, 0, &name, &namelen, &message, &messagelen) ) - return; - - if( atcommand->exec(fd, sd, message, true) ) + if (clif->process_chat_message(sd, packet, message, sizeof message) == NULL) return; - if( !pc->can_talk(sd) ) - return; - - if (battle_config.min_chat_delay) { - if (DIFF_TICK(sd->cantalk_tick, timer->gettick()) > 0) - return; - sd->cantalk_tick = timer->gettick() + battle_config.min_chat_delay; - } - - pc->update_idle_time(sd, BCIDLE_CHAT); - - if( sd->bg_id ) - bg->send_message(sd, text, textlen); + if (sd->bg_id) + bg->send_message(sd, message); else - guild->send_message(sd, text, textlen); + guild->send_message(sd, message); } void clif_parse_GuildRequestAlliance(int fd, struct map_session_data *sd) __attribute__((nonnull (2))); @@ -13284,7 +13275,7 @@ void clif_parse_GMKick(int fd, struct map_session_data *sd) { case BL_PC: { char command[NAME_LENGTH+6]; - sprintf(command, "%ckick %s", atcommand->at_symbol, status->get_name(target)); + sprintf(command, "%ckick %s", atcommand->at_symbol, clif->get_bl_name(target)); atcommand->exec(fd, sd, command, true); } break; @@ -13299,7 +13290,7 @@ void clif_parse_GMKick(int fd, struct map_session_data *sd) { clif->GM_kickack(sd, 0); return; } - sprintf(command, "/kick %s (%d)", status->get_name(target), status->get_class(target)); + sprintf(command, "/kick %s (%d)", clif->get_bl_name(target), status->get_class(target)); logs->atcommand(sd, command); status_percent_damage(&sd->bl, target, 100, 0, true); // can invalidate 'target' } @@ -14671,7 +14662,7 @@ void clif_Mail_refreshinbox(struct map_session_data *sd) if( md->full ) {// TODO: is this official? char output[100]; sprintf(output, "Inbox is full (Max %d). Delete some mails.", MAIL_MAX_INBOX); - clif_disp_onlyself(sd, output, strlen(output)); + clif_disp_onlyself(sd, output); } } @@ -14709,11 +14700,16 @@ void clif_Mail_read(struct map_session_data *sd, int mail_id) struct mail_message *msg = &sd->mail.inbox.msg[i]; struct item *item = &msg->item; struct item_data *data; - size_t msg_len = strlen(msg->body), len; + int msg_len = (int)strlen(msg->body), len; - if( msg_len == 0 ) { + if (msg_len == 0) { strcpy(msg->body, "(no message)"); - msg_len = strlen(msg->body); + msg_len = (int)strlen(msg->body); + } + + if (msg_len > UINT8_MAX) { + Assert_report(msg_len > UINT8_MAX); + msg_len = UINT8_MAX; } len = 101 + msg_len; @@ -14741,7 +14737,7 @@ void clif_Mail_read(struct map_session_data *sd, int mail_id) } else // no item, set all to zero memset(WFIFOP(fd,80), 0x00, 19); - WFIFOB(fd,99) = (unsigned char)msg_len; + WFIFOB(fd,99) = (uint8)msg_len; safestrncpy(WFIFOP(fd,100), msg->body, msg_len + 1); WFIFOSET(fd,len); @@ -14775,7 +14771,6 @@ void clif_parse_Mail_getattach(int fd, struct map_session_data *sd) { int mail_id = RFIFOL(fd,2); int i; - bool fail = false; if( !chrif->isconnected() ) return; @@ -14799,6 +14794,7 @@ void clif_parse_Mail_getattach(int fd, struct map_session_data *sd) if( sd->mail.inbox.msg[i].item.nameid > 0 ) { struct item_data *data; unsigned int weight; + bool fail = false; if ((data = itemdb->exists(sd->mail.inbox.msg[i].item.nameid)) == NULL) return; @@ -16148,58 +16144,53 @@ void clif_bg_xy_remove(struct map_session_data *sd) /// Notifies clients of a battleground message (ZC_BATTLEFIELD_CHAT). /// 02dc <packet len>.W <account id>.L <name>.24B <message>.?B -void clif_bg_message(struct battleground_data *bgd, int src_id, const char *name, const char *mes, size_t len) +void clif_bg_message(struct battleground_data *bgd, int src_id, const char *name, const char *mes) { struct map_session_data *sd; unsigned char *buf; + int len; nullpo_retv(bgd); nullpo_retv(name); nullpo_retv(mes); - if( !bgd->count || (sd = bg->getavailablesd(bgd)) == NULL ) + + if (!bgd->count || (sd = bg->getavailablesd(bgd)) == NULL) return; + len = (int)strlen(mes); + Assert_retv(len <= INT16_MAX - NAME_LENGTH - 8); buf = (unsigned char*)aMalloc((len + NAME_LENGTH + 8)*sizeof(unsigned char)); WBUFW(buf,0) = 0x2dc; WBUFW(buf,2) = len + NAME_LENGTH + 8; WBUFL(buf,4) = src_id; memcpy(WBUFP(buf,8), name, NAME_LENGTH); - memcpy(WBUFP(buf,32), mes, len); + memcpy(WBUFP(buf,32), mes, len); // [!] no NUL terminator clif->send(buf,WBUFW(buf,2), &sd->bl, BG); aFree(buf); } -void clif_parse_BattleChat(int fd, struct map_session_data* sd) __attribute__((nonnull (2))); -/// Validates and processes battlechat messages [pakpil] (CZ_BATTLEFIELD_CHAT). -/// 0x2db <packet len>.W <text>.?B (<name> : <message>) 00 -void clif_parse_BattleChat(int fd, struct map_session_data* sd) +/** + * Validates and processes battlechat messages [pakpil] (CZ_BATTLEFIELD_CHAT). + * + * @code + * 0x2db <packet len>.W <text>.?B (<name> : <message>) 00 + * @endcode + * + * @param fd The incoming file descriptor. + * @param sd The related character. + */ +void clif_parse_BattleChat(int fd, struct map_session_data *sd) __attribute__((nonnull (2))); +void clif_parse_BattleChat(int fd, struct map_session_data *sd) { - const char *text = RFIFOP(fd,4); - int textlen = RFIFOW(fd,2) - 4; - - const char *name, *message; - size_t namelen, messagelen; - - if( !clif->process_message(sd, 0, &name, &namelen, &message, &messagelen) ) - return; - - if( atcommand->exec(fd, sd, message, true) ) - return; + const struct packet_chat_message *packet = RP2PTR(fd); + char message[CHAT_SIZE_MAX + NAME_LENGTH + 3 + 1]; - if( !pc->can_talk(sd) ) + if (clif->process_chat_message(sd, packet, message, sizeof message) == NULL) return; - if( battle_config.min_chat_delay ) { - if( DIFF_TICK(sd->cantalk_tick, timer->gettick()) > 0 ) - return; - sd->cantalk_tick = timer->gettick() + battle_config.min_chat_delay; - } - - pc->update_idle_time(sd, BCIDLE_CHAT); - - bg->send_message(sd, text, textlen); + bg->send_message(sd, message); } /// Notifies client of a battleground score change (ZC_BATTLEFIELD_NOTIFY_POINT). @@ -17694,26 +17685,27 @@ void clif_partytickack(struct map_session_data* sd, bool flag) { WFIFOSET(sd->fd, packet_len(0x2c9)); } -void clif_ShowScript(struct block_list* bl, const char* message) { +void clif_ShowScript(struct block_list *bl, const char *message) +{ char buf[256]; - size_t len; + int len; nullpo_retv(bl); - if(!message) + if (message == NULL) return; - len = strlen(message)+1; + len = (int)strlen(message)+1; - if (len > sizeof(buf)-8) { - ShowWarning("clif_ShowScript: Truncating too long message '%s' (len=%"PRIuS").\n", message, len); - len = sizeof(buf)-8; + if (len > (int)sizeof(buf)-8) { + ShowWarning("clif_ShowScript: Truncating too long message '%s' (len=%d).\n", message, len); + len = (int)sizeof(buf)-8; } - WBUFW(buf,0)=0x8b3; - WBUFW(buf,2)=len+8; - WBUFL(buf,4)=bl->id; + WBUFW(buf,0) = 0x8b3; + WBUFW(buf,2) = len+8; + WBUFL(buf,4) = bl->id; safestrncpy(WBUFP(buf,8),message,len); - clif->send((unsigned char *) buf,WBUFW(buf,2),bl,ALL_CLIENT); + clif->send(buf,WBUFW(buf,2),bl,ALL_CLIENT); } void clif_status_change_end(struct block_list *bl, int tid, enum send_target target, int type) { @@ -17808,7 +17800,6 @@ void clif_parse_bgqueue_checkstate(int fd, struct map_session_data *sd) { const struct packet_bgqueue_checkstate *p = RP2PTR(fd); - nullpo_retv(sd); if (sd->bg_queue.arena && sd->bg_queue.type) { clif->bgqueue_update_info(sd,sd->bg_queue.arena->id,bg->id2pos(sd->bg_queue.arena->queue_id,sd->status.account_id)); } else { @@ -18059,7 +18050,7 @@ void clif_show_modifiers (struct map_session_data *sd) { snprintf(output,128,"Base EXP : %d%% | Base Drop: %d%% | Base Death Penalty: %d%%", sd->status.mod_exp,sd->status.mod_drop,sd->status.mod_death); - clif->broadcast2(&sd->bl,output, strlen(output) + 1, 0xffbc90, 0x190, 12, 0, 0, SELF); + clif->broadcast2(&sd->bl, output, (int)strlen(output) + 1, 0xffbc90, 0x190, 12, 0, 0, SELF); } } @@ -18404,7 +18395,7 @@ void clif_parse_RouletteGenerate(int fd, struct map_session_data* sd) { it.nameid = clif->rd.nameid[stage][0]; it.identify = 1; - pc->additem(sd, &it, clif->rd.qty[stage][0], LOG_TYPE_OTHER);/** TODO maybe a new log type for roulette items? **/ + pc->additem(sd, &it, clif->rd.qty[stage][0], LOG_TYPE_ROULETTE);/** TODO maybe a new log type for roulette items? **/ sd->roulette.stage = 0; result = GENERATE_ROULETTE_LOSING; @@ -18439,7 +18430,7 @@ void clif_parse_RouletteRecvItem(int fd, struct map_session_data* sd) { it.nameid = clif->rd.nameid[sd->roulette.prizeStage][sd->roulette.prizeIdx]; it.identify = 1; - switch (pc->additem(sd, &it, clif->rd.qty[sd->roulette.prizeStage][sd->roulette.prizeIdx], LOG_TYPE_OTHER)) { + switch (pc->additem(sd, &it, clif->rd.qty[sd->roulette.prizeStage][sd->roulette.prizeIdx], LOG_TYPE_ROULETTE)) { case 0: p.Result = RECV_ITEM_SUCCESS; sd->roulette.claimPrize = false; @@ -18760,6 +18751,22 @@ void clif_selectcart(struct map_session_data *sd) #endif } +/** + * Returns the name of the given bl, in a client-friendly format. + * + * @param bl The requested bl. + * @return The bl's name (guaranteed to be non-NULL). + */ +const char *clif_get_bl_name(const struct block_list *bl) +{ + const char *name = status->get_name(bl); + + if (name == NULL) + return "Unknown"; + + return name; +} + /* */ unsigned short clif_decrypt_cmd( int cmd, struct map_session_data *sd ) { if( sd ) { @@ -19346,7 +19353,8 @@ void clif_defaults(void) { clif->message = clif_displaymessage; clif->messageln = clif_displaymessage2; clif->messages = clif_displaymessage_sprintf; - clif->process_message = clif_process_message; + clif->process_chat_message = clif_process_chat_message; + clif->process_whisper_message = clif_process_whisper_message; clif->wisexin = clif_wisexin; clif->wisall = clif_wisall; clif->PMIgnoreList = clif_PMIgnoreList; @@ -19829,4 +19837,5 @@ void clif_defaults(void) { clif->pHotkeyRowShift = clif_parse_HotkeyRowShift; clif->dressroom_open = clif_dressroom_open; clif->pOneClick_ItemIdentify = clif_parse_OneClick_ItemIdentify; + clif->get_bl_name = clif_get_bl_name; } diff --git a/src/map/clif.h b/src/map/clif.h index ac0191210..4d22fd4af 100644 --- a/src/map/clif.h +++ b/src/map/clif.h @@ -60,7 +60,7 @@ struct view_data; **/ #define packet_len(cmd) packet_db[cmd].len #define clif_menuskill_clear(sd) ((sd)->menuskill_id = (sd)->menuskill_val = (sd)->menuskill_val2 = 0) -#define clif_disp_onlyself(sd,mes,len) clif->disp_message( &(sd)->bl, (mes), (len), SELF ) +#define clif_disp_onlyself(sd, mes) clif->disp_message(&(sd)->bl, (mes), SELF) #define MAX_ROULETTE_LEVEL 7 /** client-defined value **/ #define MAX_ROULETTE_COLUMNS 9 /** client-defined value **/ #define RGB2BGR(c) (((c) & 0x0000FF) << 16 | ((c) & 0x00FF00) | ((c) & 0xFF0000) >> 16) @@ -841,11 +841,11 @@ struct clif_interface { void (*clearchat) (struct chat_data *cd,int fd); void (*leavechat) (struct chat_data* cd, struct map_session_data* sd, bool flag); void (*changechatstatus) (struct chat_data* cd); - void (*wis_message) (int fd, const char* nick, const char* mes, size_t mes_len); + void (*wis_message) (int fd, const char *nick, const char *mes, int mes_len); void (*wis_end) (int fd, int flag); - void (*disp_message) (struct block_list* src, const char* mes, size_t len, enum send_target target); - void (*broadcast) (struct block_list* bl, const char* mes, size_t len, int type, enum send_target target); - void (*broadcast2) (struct block_list* bl, const char* mes, size_t len, unsigned int fontColor, short fontType, short fontSize, short fontAlign, short fontY, enum send_target target); + void (*disp_message) (struct block_list *src, const char *mes, enum send_target target); + void (*broadcast) (struct block_list *bl, const char *mes, int len, int type, enum send_target target); + void (*broadcast2) (struct block_list *bl, const char *mes, int len, unsigned int fontColor, short fontType, short fontSize, short fontAlign, short fontY, enum send_target target); void (*messagecolor_self) (int fd, uint32 color, const char *msg); void (*messagecolor) (struct block_list* bl, uint32 color, const char* msg); void (*disp_overhead) (struct block_list *bl, const char* mes); @@ -856,7 +856,8 @@ struct clif_interface { void (*messageln) (const int fd, const char* mes); /* message+s(printf) */ void (*messages) (const int fd, const char *mes, ...) __attribute__((format(printf, 2, 3))); - bool (*process_message) (struct map_session_data *sd, int format, const char **name_, size_t *namelen_, const char **message_, size_t *messagelen_); + const char *(*process_chat_message) (struct map_session_data *sd, const struct packet_chat_message *packet, char *out_buf, int out_buflen); + bool (*process_whisper_message) (struct map_session_data *sd, const struct packet_whisper_message *packet, char *out_name, char *out_message, int out_messagelen); void (*wisexin) (struct map_session_data *sd,int type,int flag); void (*wisall) (struct map_session_data *sd,int type,int flag); void (*PMIgnoreList) (struct map_session_data* sd); @@ -942,7 +943,7 @@ struct clif_interface { void (*bg_hp) (struct map_session_data *sd); void (*bg_xy) (struct map_session_data *sd); void (*bg_xy_remove) (struct map_session_data *sd); - void (*bg_message) (struct battleground_data *bgd, int src_id, const char *name, const char *mes, size_t len); + void (*bg_message) (struct battleground_data *bgd, int src_id, const char *name, const char *mes); void (*bg_updatescore) (int16 m); void (*bg_updatescore_single) (struct map_session_data *sd); void (*sendbgemblem_area) (struct map_session_data *sd); @@ -1334,8 +1335,10 @@ struct clif_interface { void (*dressroom_open) (struct map_session_data *sd, int view); void (*pOneClick_ItemIdentify) (int fd,struct map_session_data *sd); /* Cart Deco */ - void(*selectcart) (struct map_session_data *sd); - void(*pSelectCart) (int fd, struct map_session_data *sd); + void (*selectcart) (struct map_session_data *sd); + void (*pSelectCart) (int fd, struct map_session_data *sd); + + const char *(*get_bl_name) (const struct block_list *bl); }; #ifdef HERCULES_CORE diff --git a/src/map/duel.c b/src/map/duel.c index c658ea3e3..64991d39c 100644 --- a/src/map/duel.c +++ b/src/map/duel.c @@ -73,7 +73,7 @@ static int duel_showinfo_sub(struct map_session_data* sd, va_list va) if (sd->duel_group != ssd->duel_group) return 0; sprintf(output, " %d. %s", ++(*p), sd->status.name); - clif_disp_onlyself(ssd, output, strlen(output)); + clif_disp_onlyself(ssd, output); return 1; } @@ -93,7 +93,7 @@ void duel_showinfo(const unsigned int did, struct map_session_data* sd) { duel->list[did].members_count, duel->list[did].members_count + duel->list[did].invites_count); - clif_disp_onlyself(sd, output, strlen(output)); + clif_disp_onlyself(sd, output); map->foreachpc(duel_showinfo_sub, sd, &p); } @@ -113,7 +113,7 @@ int duel_create(struct map_session_data* sd, const unsigned int maxpl) { duel->list[i].max_players_limit = maxpl; safestrncpy(output, msg_sd(sd,372), sizeof(output)); // " -- Duel has been created (@invite/@leave) --" - clif_disp_onlyself(sd, output, strlen(output)); + clif_disp_onlyself(sd, output); clif->map_property(sd, MAPPROPERTY_FREEPVPZONE); clif->maptypeproperty2(&sd->bl,SELF); @@ -127,14 +127,14 @@ void duel_invite(const unsigned int did, struct map_session_data* sd, struct map nullpo_retv(target_sd); // " -- Player %s invites %s to duel --" sprintf(output, msg_sd(sd,373), sd->status.name, target_sd->status.name); - clif->disp_message(&sd->bl, output, strlen(output), DUEL_WOS); + clif->disp_message(&sd->bl, output, DUEL_WOS); target_sd->duel_invite = did; duel->list[did].invites_count++; // "Blue -- Player %s invites you to PVP duel (@accept/@reject) --" sprintf(output, msg_sd(target_sd,374), sd->status.name); - clif->broadcast(&target_sd->bl, output, strlen(output)+1, BC_BLUE, SELF); + clif->broadcast(&target_sd->bl, output, (int)strlen(output)+1, BC_BLUE, SELF); } static int duel_leave_sub(struct map_session_data* sd, va_list va) @@ -152,7 +152,7 @@ void duel_leave(const unsigned int did, struct map_session_data* sd) { nullpo_retv(sd); // " <- Player %s has left duel --" sprintf(output, msg_sd(sd,375), sd->status.name); - clif->disp_message(&sd->bl, output, strlen(output), DUEL_WOS); + clif->disp_message(&sd->bl, output, DUEL_WOS); duel->list[did].members_count--; if(duel->list[did].members_count == 0) { @@ -177,7 +177,7 @@ void duel_accept(const unsigned int did, struct map_session_data* sd) { // " -> Player %s has accepted duel --" sprintf(output, msg_sd(sd,376), sd->status.name); - clif->disp_message(&sd->bl, output, strlen(output), DUEL_WOS); + clif->disp_message(&sd->bl, output, DUEL_WOS); clif->map_property(sd, MAPPROPERTY_FREEPVPZONE); clif->maptypeproperty2(&sd->bl,SELF); @@ -189,7 +189,7 @@ void duel_reject(const unsigned int did, struct map_session_data* sd) { nullpo_retv(sd); // " -- Player %s has rejected duel --" sprintf(output, msg_sd(sd,377), sd->status.name); - clif->disp_message(&sd->bl, output, strlen(output), DUEL_WOS); + clif->disp_message(&sd->bl, output, DUEL_WOS); duel->list[did].invites_count--; sd->duel_invite = 0; diff --git a/src/map/guild.c b/src/map/guild.c index 13acfc0db..1929808ca 100644 --- a/src/map/guild.c +++ b/src/map/guild.c @@ -178,7 +178,7 @@ struct guild* guild_search(int guild_id) struct guild* guild_searchname(char* str) { struct guild* g; - DBIterator *iter = db_iterator(guild->db); + struct DBIterator *iter = db_iterator(guild->db); nullpo_retr(NULL, str); for( g = dbi_first(iter); dbi_exists(iter); g = dbi_next(iter) ) @@ -201,7 +201,7 @@ struct guild_castle* guild_castle_search(int gcid) struct guild_castle* guild_mapindex2gc(short map_index) { struct guild_castle* gc; - DBIterator *iter = db_iterator(guild->castle_db); + struct DBIterator *iter = db_iterator(guild->castle_db); for( gc = dbi_first(iter); dbi_exists(iter); gc = dbi_next(iter) ) { @@ -282,7 +282,8 @@ void guild_makemember(struct guild_member *m,struct map_session_data *sd) * Server cache to be flushed to inter the Guild EXP * @see DBApply */ -int guild_payexp_timer_sub(DBKey key, DBData *data, va_list ap) { +int guild_payexp_timer_sub(union DBKey key, struct DBData *data, va_list ap) +{ int i; struct guild_expcache *c; struct guild *g; @@ -318,7 +319,7 @@ int guild_payexp_timer(int tid, int64 tick, int id, intptr_t data) { * Taken from party_send_xy_timer_sub. [Skotlex] * @see DBApply */ -int guild_send_xy_timer_sub(DBKey key, DBData *data, va_list ap) +int guild_send_xy_timer_sub(union DBKey key, struct DBData *data, va_list ap) { struct guild *g = DB->data2ptr(data); int i; @@ -423,7 +424,7 @@ int guild_npc_request_info(int guild_id,const char *event) if( event && *event ) { struct eventlist *ev; - DBData prev; + struct DBData prev; ev=(struct eventlist *)aCalloc(sizeof(struct eventlist),1); memcpy(ev->name,event,strlen(event)); //The one in the db (if present) becomes the next event from this. @@ -481,7 +482,7 @@ int guild_recv_info(const struct guild *sg) { struct guild *g,before; int i,bm,m; - DBData data; + struct DBData data; struct map_session_data *sd; bool guild_new = false; struct channel_data *aChSysSave = NULL; @@ -1059,14 +1060,15 @@ int guild_recv_memberinfoshort(int guild_id,int account_id,int char_id,int onlin /*==================================================== * Send a message to whole guild *---------------------------------------------------*/ -int guild_send_message(struct map_session_data *sd,const char *mes,int len) +int guild_send_message(struct map_session_data *sd, const char *mes) { + int len = (int)strlen(mes); nullpo_ret(sd); - if(sd->status.guild_id==0) + if (sd->status.guild_id == 0) return 0; - intif->guild_message(sd->status.guild_id,sd->status.account_id,mes,len); - guild->recv_message(sd->status.guild_id,sd->status.account_id,mes,len); + intif->guild_message(sd->status.guild_id, sd->status.account_id, mes, len); + guild->recv_message(sd->status.guild_id, sd->status.account_id, mes, len); // Chat logging type 'G' / Guild Chat logs->chat(LOG_CHAT_GUILD, sd->status.guild_id, sd->status.char_id, sd->status.account_id, mapindex_id2name(sd->mapindex), sd->bl.x, sd->bl.y, NULL, mes); @@ -1224,7 +1226,7 @@ int guild_emblem_changed(int len,int guild_id,int emblem_id,const char *data) } } {// update guardians (mobs) - DBIterator* iter = db_iterator(guild->castle_db); + struct DBIterator *iter = db_iterator(guild->castle_db); struct guild_castle* gc; for( gc = (struct guild_castle*)dbi_first(iter) ; dbi_exists(iter); gc = (struct guild_castle*)dbi_next(iter) ) { @@ -1262,7 +1264,7 @@ int guild_emblem_changed(int len,int guild_id,int emblem_id,const char *data) /** * @see DBCreateData */ -DBData create_expcache(DBKey key, va_list args) +struct DBData create_expcache(union DBKey key, va_list args) { struct guild_expcache *c; struct map_session_data *sd = va_arg(args, struct map_session_data*); @@ -1720,7 +1722,7 @@ int guild_allianceack(int guild_id1,int guild_id2,int account_id1,int account_id * Notification for the guild disbanded * @see DBApply */ -int guild_broken_sub(DBKey key, DBData *data, va_list ap) +int guild_broken_sub(union DBKey key, struct DBData *data, va_list ap) { struct guild *g = DB->data2ptr(data); int guild_id=va_arg(ap,int); @@ -1746,7 +1748,7 @@ int guild_broken_sub(DBKey key, DBData *data, va_list ap) * Invoked on Castles when a guild is broken. [Skotlex] * @see DBApply */ -int castle_guild_broken_sub(DBKey key, DBData *data, va_list ap) +int castle_guild_broken_sub(union DBKey key, struct DBData *data, va_list ap) { struct guild_castle *gc = DB->data2ptr(data); int guild_id = va_arg(ap, int); @@ -1827,7 +1829,7 @@ int guild_gm_change(int guild_id, struct map_session_data *sd) return 0; //Notify servers that master has changed. - intif->guild_change_gm(guild_id, sd->status.name, strlen(sd->status.name)+1); + intif->guild_change_gm(guild_id, sd->status.name, (int)strlen(sd->status.name)+1); return 1; } @@ -1955,7 +1957,7 @@ void guild_castle_map_init(void) if (num > 0) { struct guild_castle* gc = NULL; int *castle_ids, *cursor; - DBIterator* iter = NULL; + struct DBIterator *iter = NULL; CREATE(castle_ids, int, num); cursor = castle_ids; @@ -2153,7 +2155,7 @@ int guild_checkcastles(struct guild *g) { int nb_cas = 0; struct guild_castle* gc = NULL; - DBIterator *iter = db_iterator(guild->castle_db); + struct DBIterator *iter = db_iterator(guild->castle_db); for (gc = dbi_first(iter); dbi_exists(iter); gc = dbi_next(iter)) { if (gc->guild_id == g->guild_id) { @@ -2222,7 +2224,8 @@ void guild_flag_remove(struct npc_data *nd) { /** * @see DBApply */ -int eventlist_db_final(DBKey key, DBData *data, va_list ap) { +int eventlist_db_final(union DBKey key, struct DBData *data, va_list ap) +{ struct eventlist *next = NULL; struct eventlist *current = DB->data2ptr(data); while (current != NULL) { @@ -2236,7 +2239,8 @@ int eventlist_db_final(DBKey key, DBData *data, va_list ap) { /** * @see DBApply */ -int guild_expcache_db_final(DBKey key, DBData *data, va_list ap) { +int guild_expcache_db_final(union DBKey key, struct DBData *data, va_list ap) +{ ers_free(guild->expcache_ers, DB->data2ptr(data)); return 0; } @@ -2244,7 +2248,8 @@ int guild_expcache_db_final(DBKey key, DBData *data, va_list ap) { /** * @see DBApply */ -int guild_castle_db_final(DBKey key, DBData *data, va_list ap) { +int guild_castle_db_final(union DBKey key, struct DBData *data, va_list ap) +{ struct guild_castle* gc = DB->data2ptr(data); if( gc->temp_guardians ) aFree(gc->temp_guardians); @@ -2283,8 +2288,9 @@ void do_init_guild(bool minimal) { timer->add_interval(timer->gettick()+GUILD_SEND_XY_INVERVAL,guild->send_xy_timer,0,0,GUILD_SEND_XY_INVERVAL); } -void do_final_guild(void) { - DBIterator *iter = db_iterator(guild->db); +void do_final_guild(void) +{ + struct DBIterator *iter = db_iterator(guild->db); struct guild *g; for( g = dbi_first(iter); dbi_exists(iter); g = dbi_next(iter) ) { diff --git a/src/map/guild.h b/src/map/guild.h index cd796adb3..4fe7106d3 100644 --- a/src/map/guild.h +++ b/src/map/guild.h @@ -71,10 +71,10 @@ struct guild_interface { void (*init) (bool minimal); void (*final) (void); /* */ - DBMap* db; // int guild_id -> struct guild* - DBMap* castle_db; // int castle_id -> struct guild_castle* - DBMap* expcache_db; // int char_id -> struct guild_expcache* - DBMap* infoevent_db; // int guild_id -> struct eventlist* + struct DBMap *db; // int guild_id -> struct guild* + struct DBMap *castle_db; // int castle_id -> struct guild_castle* + struct DBMap *expcache_db; // int char_id -> struct guild_expcache* + struct DBMap *infoevent_db; // int guild_id -> struct eventlist* /* */ struct eri *expcache_ers; //For handling of guild exp payment. /* */ @@ -135,7 +135,7 @@ struct guild_interface { int (*notice_changed) (int guild_id,const char *mes1,const char *mes2); int (*change_emblem) (struct map_session_data *sd,int len,const char *data); int (*emblem_changed) (int len,int guild_id,int emblem_id,const char *data); - int (*send_message) (struct map_session_data *sd,const char *mes,int len); + int (*send_message) (struct map_session_data *sd, const char *mes); int (*recv_message) (int guild_id,int account_id,const char *mes,int len); int (*send_dot_remove) (struct map_session_data *sd); int (*skillupack) (int guild_id,uint16 skill_id,int account_id); @@ -166,15 +166,15 @@ struct guild_interface { struct map_session_data *(*sd_check) (int guild_id, int account_id, int char_id); bool (*read_guildskill_tree_db) (char* split[], int columns, int current); bool (*read_castledb) (char* str[], int columns, int current); - int (*payexp_timer_sub) (DBKey key, DBData *data, va_list ap); - int (*send_xy_timer_sub) (DBKey key, DBData *data, va_list ap); + int (*payexp_timer_sub) (union DBKey key, struct DBData *data, va_list ap); + int (*send_xy_timer_sub) (union DBKey key, struct DBData *data, va_list ap); int (*send_xy_timer) (int tid, int64 tick, int id, intptr_t data); - DBData (*create_expcache) (DBKey key, va_list args); - int (*eventlist_db_final) (DBKey key, DBData *data, va_list ap); - int (*expcache_db_final) (DBKey key, DBData *data, va_list ap); - int (*castle_db_final) (DBKey key, DBData *data, va_list ap); - int (*broken_sub) (DBKey key, DBData *data, va_list ap); - int (*castle_broken_sub) (DBKey key, DBData *data, va_list ap); + struct DBData (*create_expcache) (union DBKey key, va_list args); + int (*eventlist_db_final) (union DBKey key, struct DBData *data, va_list ap); + int (*expcache_db_final) (union DBKey key, struct DBData *data, va_list ap); + int (*castle_db_final) (union DBKey key, struct DBData *data, va_list ap); + int (*broken_sub) (union DBKey key, struct DBData *data, va_list ap); + int (*castle_broken_sub) (union DBKey key, struct DBData *data, va_list ap); void (*makemember) (struct guild_member *m,struct map_session_data *sd); int (*check_member) (const struct guild *g); int (*get_alliance_count) (struct guild *g,int flag); diff --git a/src/map/homunculus.c b/src/map/homunculus.c index bda8fd9e6..66cce23e6 100644 --- a/src/map/homunculus.c +++ b/src/map/homunculus.c @@ -391,7 +391,7 @@ bool homunculus_levelup(struct homun_data *hd) { growth_max_hp, growth_max_sp, growth_str/10.0, growth_agi/10.0, growth_vit/10.0, growth_int/10.0, growth_dex/10.0, growth_luk/10.0); - clif_disp_onlyself(hd->master,output,strlen(output)); + clif_disp_onlyself(hd->master, output); } return true; } diff --git a/src/map/instance.c b/src/map/instance.c index a6700d486..fa2cfec16 100644 --- a/src/map/instance.c +++ b/src/map/instance.c @@ -551,7 +551,7 @@ void instance_destroy(int instance_id) { struct party_data *p = NULL; struct guild *g = NULL; short *iptr = NULL; - int type, j; + int type; unsigned int now = (unsigned int)time(NULL); if( !instance->valid(instance_id) ) @@ -596,9 +596,10 @@ void instance_destroy(int instance_id) { } if( iptr != NULL ) { - ARR_FIND(0, *icptr, j, iptr[j] == instance_id); - if( j != *icptr ) - iptr[j] = -1; + int i; + ARR_FIND(0, *icptr, i, iptr[i] == instance_id); + if (i != *icptr) + iptr[i] = -1; } if (instance->list[instance_id].map) { diff --git a/src/map/intif.c b/src/map/intif.c index 7d2493d46..2d6d39406 100644 --- a/src/map/intif.c +++ b/src/map/intif.c @@ -150,7 +150,7 @@ int intif_rename(struct map_session_data *sd, int type, const char *name) } // GM Send a message -int intif_broadcast(const char* mes, size_t len, int type) +int intif_broadcast(const char *mes, int len, int type) { int lp = (type&BC_COLOR_MASK) ? 4 : 0; @@ -182,7 +182,7 @@ int intif_broadcast(const char* mes, size_t len, int type) return 0; } -int intif_broadcast2(const char* mes, size_t len, unsigned int fontColor, short fontType, short fontSize, short fontAlign, short fontY) +int intif_broadcast2(const char *mes, int len, unsigned int fontColor, short fontType, short fontSize, short fontAlign, short fontY) { nullpo_ret(mes); Assert_ret(len < 32000); @@ -222,7 +222,7 @@ int intif_main_message(struct map_session_data* sd, const char* message) snprintf( output, sizeof(output), msg_txt(386), sd->status.name, message ); // send the message using the inter-server broadcast service - intif->broadcast2( output, strlen(output) + 1, 0xFE000000, 0, 0, 0, 0 ); + intif->broadcast2(output, (int)strlen(output) + 1, 0xFE000000, 0, 0, 0, 0); // log the chat message logs->chat( LOG_CHAT_MAINCHAT, 0, sd->status.char_id, sd->status.account_id, mapindex_id2name(sd->mapindex), sd->bl.x, sd->bl.y, NULL, message ); @@ -231,7 +231,7 @@ int intif_main_message(struct map_session_data* sd, const char* message) } // The transmission of Wisp/Page to inter-server (player not found on this server) -int intif_wis_message(struct map_session_data *sd, const char *nick, const char *mes, size_t mes_len) +int intif_wis_message(struct map_session_data *sd, const char *nick, const char *mes, int mes_len) { if (intif->CheckForCharServer()) return 0; @@ -279,12 +279,14 @@ int intif_wis_replay(int id, int flag) // The transmission of GM only Wisp/Page from server to inter-server int intif_wis_message_to_gm(char *wisp_name, int permission, char *mes) { - size_t mes_len; + int mes_len; if (intif->CheckForCharServer()) return 0; nullpo_ret(wisp_name); nullpo_ret(mes); - mes_len = strlen(mes) + 1; // + null + mes_len = (int)strlen(mes) + 1; // + null + Assert_ret(mes_len > 0 && mes_len <= INT16_MAX - 32); + WFIFOHEAD(inter_fd, mes_len + 32); WFIFOW(inter_fd,0) = 0x3003; WFIFOW(inter_fd,2) = mes_len + 32; @@ -300,10 +302,11 @@ int intif_wis_message_to_gm(char *wisp_name, int permission, char *mes) } //Request for saving registry values. -int intif_saveregistry(struct map_session_data *sd) { - DBIterator *iter; - DBKey key; - DBData *data; +int intif_saveregistry(struct map_session_data *sd) +{ + struct DBIterator *iter; + union DBKey key; + struct DBData *data; int plen = 0; size_t len; @@ -657,7 +660,7 @@ int intif_guild_addmember(int guild_id,struct guild_member *m) } // Request a new leader for guild -int intif_guild_change_gm(int guild_id, const char* name, size_t len) +int intif_guild_change_gm(int guild_id, const char *name, int len) { if (intif->CheckForCharServer()) return 0; @@ -985,7 +988,7 @@ void intif_parse_WisMessage(int fd) { return; } //Success to send whisper. - clif->wis_message(sd->fd, wisp_source, RFIFOP(fd,56),RFIFOW(fd,2)-56); + clif->wis_message(sd->fd, wisp_source, RFIFOP(fd,56),RFIFOW(fd,2)-57); intif_wis_replay(id,0); // success } @@ -1004,7 +1007,8 @@ void intif_parse_WisEnd(int fd) return; } -int mapif_parse_WisToGM_sub(struct map_session_data* sd,va_list va) { +int intif_parse_WisToGM_sub(struct map_session_data *sd, va_list va) +{ int permission = va_arg(va, int); char *wisp_name; char *message; @@ -1022,22 +1026,22 @@ int mapif_parse_WisToGM_sub(struct map_session_data* sd,va_list va) { // Received wisp message from map-server via char-server for ALL gm // 0x3003/0x3803 <packet_len>.w <wispname>.24B <permission>.l <message>.?B -void mapif_parse_WisToGM(int fd) +void intif_parse_WisToGM(int fd) { int permission, mes_len; char Wisp_name[NAME_LENGTH]; char mbuf[255] = { 0 }; char *message; - mes_len = RFIFOW(fd,2) - 32; + mes_len = RFIFOW(fd,2) - 33; // Length not including the NUL terminator Assert_retv(mes_len > 0 && mes_len < 32000); - message = (char *) (mes_len >= 255 ? (char *) aMalloc(mes_len) : mbuf); + message = (mes_len >= 255 ? aMalloc(mes_len + 1) : mbuf); permission = RFIFOL(fd,28); safestrncpy(Wisp_name, RFIFOP(fd,4), NAME_LENGTH); - safestrncpy(message, RFIFOP(fd,32), mes_len); + safestrncpy(message, RFIFOP(fd,32), mes_len + 1); // information is sent to all online GM - map->foreachpc(mapif_parse_WisToGM_sub, permission, Wisp_name, message, mes_len); + map->foreachpc(intif->pWisToGM_sub, permission, Wisp_name, message, mes_len); if (message != mbuf) aFree(message); @@ -1110,7 +1114,7 @@ void intif_parse_Registers(int fd) safestrncpy(sval, RFIFOP(fd, cursor + 1), min((int)sizeof(sval), len)); cursor += len + 1; - script->set_reg(NULL,sd,reference_uid(script->add_str(key), index), key, (void*)sval, NULL); + script->set_reg(NULL,sd,reference_uid(script->add_str(key), index), key, sval, NULL); } /** * Vessel! @@ -1132,7 +1136,7 @@ void intif_parse_Registers(int fd) ival = RFIFOL(fd, cursor); cursor += 4; - script->set_reg(NULL,sd,reference_uid(script->add_str(key), index), key, (void*)h64BPTRSIZE(ival), NULL); + script->set_reg(NULL,sd,reference_uid(script->add_str(key), index), key, (const void *)h64BPTRSIZE(ival), NULL); } } script->parser_current_file = NULL;/* reset */ @@ -1653,7 +1657,7 @@ void intif_parse_MailInboxReceived(int fd) { else if( battle_config.mail_show_status && ( battle_config.mail_show_status == 1 || sd->mail.inbox.unread ) ) { char output[128]; sprintf(output, msg_sd(sd,510), sd->mail.inbox.unchecked, sd->mail.inbox.unread + sd->mail.inbox.unchecked); - clif_disp_onlyself(sd, output, strlen(output)); + clif_disp_onlyself(sd, output); } } /*------------------------------------------ @@ -2488,8 +2492,8 @@ void intif_defaults(void) { /* parse functions */ intif->pWisMessage = intif_parse_WisMessage; intif->pWisEnd = intif_parse_WisEnd; - intif->pWisToGM_sub = mapif_parse_WisToGM_sub; - intif->pWisToGM = mapif_parse_WisToGM; + intif->pWisToGM_sub = intif_parse_WisToGM_sub; + intif->pWisToGM = intif_parse_WisToGM; intif->pRegisters = intif_parse_Registers; intif->pChangeNameOk = intif_parse_ChangeNameOk; intif->pMessageToFD = intif_parse_MessageToFD; diff --git a/src/map/intif.h b/src/map/intif.h index dccd31d80..5e7f86fc2 100644 --- a/src/map/intif.h +++ b/src/map/intif.h @@ -59,10 +59,10 @@ struct intif_interface { int (*parse) (int fd); int (*create_pet)(int account_id, int char_id, short pet_type, short pet_lv, short pet_egg_id, short pet_equip, short intimate, short hungry, char rename_flag, char incubate, char *pet_name); - int (*broadcast) (const char* mes, size_t len, int type); - int (*broadcast2) (const char* mes, size_t len, unsigned int fontColor, short fontType, short fontSize, short fontAlign, short fontY); + int (*broadcast) (const char *mes, int len, int type); + int (*broadcast2) (const char *mes, int len, unsigned int fontColor, short fontType, short fontSize, short fontAlign, short fontY); int (*main_message) (struct map_session_data* sd, const char* message); - int (*wis_message) (struct map_session_data *sd, const char *nick, const char *mes, size_t mes_len); + int (*wis_message) (struct map_session_data *sd, const char *nick, const char *mes, int mes_len); int (*wis_message_to_gm) (char *Wisp_name, int permission, char *mes); int (*saveregistry) (struct map_session_data *sd); int (*request_registry) (struct map_session_data *sd, int flag); @@ -84,7 +84,7 @@ struct intif_interface { int (*guild_memberinfoshort) (int guild_id, int account_id, int char_id, int online, int lv, int class_); int (*guild_break) (int guild_id); int (*guild_message) (int guild_id, int account_id, const char *mes, int len); - int (*guild_change_gm) (int guild_id, const char* name, size_t len); + int (*guild_change_gm) (int guild_id, const char *name, int len); int (*guild_change_basicinfo) (int guild_id, int type, const void *data, int len); int (*guild_change_memberinfo) (int guild_id, int account_id, int char_id, int type, const void *data, int len); int (*guild_position) (int guild_id, int idx, struct guild_position *p); diff --git a/src/map/irc-bot.c b/src/map/irc-bot.c index b520e9e91..5820ad2cf 100644 --- a/src/map/irc-bot.c +++ b/src/map/irc-bot.c @@ -48,10 +48,7 @@ struct irc_bot_interface *ircbot; char send_string[IRC_MESSAGE_LENGTH]; -/** - * Timer callback to (re-)connect to an IRC server - * @see timer->do_timer - */ +/// @copydoc irc_bot_interface::connect_timer() int irc_connect_timer(int tid, int64 tick, int id, intptr_t data) { struct hSockOpt opt; if( ircbot->isOn || ++ircbot->fails >= 3 ) @@ -71,53 +68,43 @@ int irc_connect_timer(int tid, int64 tick, int id, intptr_t data) { return 0; } -/** - * Timer callback to send identification commands to an IRC server - * @see timer->do_timer - */ +/// @copydoc irc_bot_interface::identify_timer() int irc_identify_timer(int tid, int64 tick, int id, intptr_t data) { if( !ircbot->isOn ) return 0; sprintf(send_string, "USER HerculesWS%d 8 * : Hercules IRC Bridge",rnd()%777); - ircbot->send(send_string); + ircbot->send(send_string, true); sprintf(send_string, "NICK %s", channel->config->irc_nick); - ircbot->send(send_string); + ircbot->send(send_string, true); timer->add(timer->gettick() + 3000, ircbot->join_timer, 0, 0); return 0; } -/** - * Timer callback to join channels (and optionally send NickServ commands) - * @see timer->do_timer - */ +/// @copydoc irc_bot_interface::join_timer() int irc_join_timer(int tid, int64 tick, int id, intptr_t data) { if( !ircbot->isOn ) return 0; if (channel->config->irc_nick_pw[0] != '\0') { sprintf(send_string, "PRIVMSG NICKSERV : IDENTIFY %s", channel->config->irc_nick_pw); - ircbot->send(send_string); + ircbot->send(send_string, true); if (channel->config->irc_use_ghost) { sprintf(send_string, "PRIVMSG NICKSERV : GHOST %s %s", channel->config->irc_nick, channel->config->irc_nick_pw); + ircbot->send(send_string, true); } } sprintf(send_string, "JOIN %s", channel->config->irc_channel); - ircbot->send(send_string); + ircbot->send(send_string, true); ircbot->isIn = true; return 0; } -/** - * Search the handler for a given IRC received command - * @param function_name Name of the received IRC command - * @return Function pointer to the command handler, NULL in case - * of unhandled commands - */ +/// @copydoc irc_bot_interface::func_search() struct irc_func* irc_func_search(char* function_name) { int i; nullpo_retr(NULL, function_name); @@ -129,10 +116,7 @@ struct irc_func* irc_func_search(char* function_name) { return NULL; } -/** - * Parser for the IRC server connection - * @see do_sockets - */ +/// @copydoc irc_bot_interface::parse() int irc_parse(int fd) { char *parse_string = NULL, *p = NULL, *str_safe = NULL; @@ -166,16 +150,7 @@ int irc_parse(int fd) { return 0; } -/** - * Parse the source from a received irc message - * @param source Source string, as reported by the server - * @param nick Pointer to a string where to return the nick (may not be NULL, - * needs to be able to fit an IRC_NICK_LENGTH long string) - * @param ident Pointer to a string where to return the ident (may not be - * NULL, needs to be able to fit an IRC_IDENT_LENGTH long string) - * @param host Pointer to a string where to return the hostname (may not be - * NULL, needs to be able to fit an IRC_HOST_LENGTH long string) - */ +/// @copydoc irc_bot_interface::parse_source() void irc_parse_source(char *source, char *nick, char *ident, char *host) { int i, pos = 0; size_t len; @@ -199,12 +174,7 @@ void irc_parse_source(char *source, char *nick, char *ident, char *host) { } } -/** - * Parse a received message from the irc server, and do the appropriate action - * for the detected command - * @param fd IRC server connection file descriptor - * @param str Raw received message - */ +/// @copydoc irc_bot_interface::parse_sub() void irc_parse_sub(int fd, char *str) { char source[180], command[60], buf1[IRC_MESSAGE_LENGTH], buf2[IRC_MESSAGE_LENGTH]; char *target = buf1, *message = buf2; @@ -234,35 +204,92 @@ void irc_parse_sub(int fd, char *str) { func->func(fd,command,source,target,message); } -/** - * Send a raw command to the irc server - * @param str Command to send - */ -void irc_send(char *str) { +/// @copydoc irc_bot_interface::queue() +void irc_queue(char *str) +{ + struct message_flood *queue_entry = NULL; + + if (!ircbot->flood_protection_enabled) { + ircbot->send(str, true); + return; + } + + if (ircbot->message_current == NULL) { + // No queue yet + if (ircbot->messages_burst_count < ircbot->flood_protection_burst) { + ircbot->send(str, true); + if (DIFF_TICK(timer->gettick(), ircbot->last_message_tick) <= ircbot->flood_protection_rate) + ircbot->messages_burst_count++; + else + ircbot->messages_burst_count = 0; + ircbot->last_message_tick = timer->gettick(); + } else { //queue starts + CREATE(queue_entry, struct message_flood, 1); + safestrncpy(queue_entry->message, str, sizeof(queue_entry->message)); + queue_entry->next = NULL; + ircbot->message_current = queue_entry; + ircbot->message_last = queue_entry; + ircbot->queue_tid = timer->add(timer->gettick() + ircbot->flood_protection_rate, ircbot->queue_timer, 0, 0); //start queue timer + ircbot->messages_burst_count = 0; + } + } else { + CREATE(queue_entry, struct message_flood, 1); + safestrncpy(queue_entry->message, str, sizeof(queue_entry->message)); + queue_entry->next = NULL; + ircbot->message_last->next = queue_entry; + ircbot->message_last = queue_entry; + } +} + +/// @copydoc irc_bot_interface::queue_timer() +int irc_queue_timer(int tid, int64 tick, int id, intptr_t data) +{ + struct message_flood *queue_entry = ircbot->message_current; + nullpo_ret(queue_entry); + + ircbot->send(queue_entry->message, true); + if (queue_entry->next != NULL) { + ircbot->message_current = queue_entry->next; + ircbot->queue_tid = timer->add(timer->gettick() + ircbot->flood_protection_rate, ircbot->queue_timer, 0, 0); + } else { + ircbot->message_current = NULL; + ircbot->message_last = NULL; + ircbot->queue_tid = INVALID_TIMER; + } + + aFree(queue_entry); + + return 0; +} + +/// @copydoc irc_bot_interface::send() +void irc_send(char *str, bool force) +{ size_t len; nullpo_retv(str); len = strlen(str) + 2; if (len > IRC_MESSAGE_LENGTH-3) len = IRC_MESSAGE_LENGTH-3; + + if (!force && ircbot->flood_protection_enabled) { + // Add to queue + ircbot->queue(str); + return; + } + WFIFOHEAD(ircbot->fd, len); snprintf(WFIFOP(ircbot->fd,0),IRC_MESSAGE_LENGTH, "%s\r\n", str); WFIFOSET(ircbot->fd, len); } -/** - * Handler for the PING IRC command (send back a PONG) - * @see irc_parse_sub - */ +/// @copydoc irc_interface_bot::pong() void irc_pong(int fd, char *cmd, char *source, char *target, char *msg) { nullpo_retv(cmd); snprintf(send_string, IRC_MESSAGE_LENGTH, "PONG %s", cmd); - ircbot->send(send_string); + ircbot->send(send_string, false); } -/** - * Handler for CTCP commands received via PRIVMSG - * @see irc_privmsg - */ +/// @copydoc irc_interface_bot::privmsg_ctcp() void irc_privmsg_ctcp(int fd, char *cmd, char *source, char *target, char *msg) { char source_nick[IRC_NICK_LENGTH], source_ident[IRC_IDENT_LENGTH], source_host[IRC_HOST_LENGTH]; @@ -283,7 +310,7 @@ void irc_privmsg_ctcp(int fd, char *cmd, char *source, char *target, char *msg) // Ignore it } else if( strcmpi(cmd,"PING") == 0 ) { snprintf(send_string, IRC_MESSAGE_LENGTH, "NOTICE %s :\001PING %s\001",source_nick,msg); - ircbot->send(send_string); + ircbot->send(send_string, false); } else if( strcmpi(cmd,"TIME") == 0 ) { time_t time_server; // variable for number of seconds (used with time() function) struct tm *datetime; // variable for time in structure ->tm_mday, ->tm_sec, ... @@ -297,10 +324,10 @@ void irc_privmsg_ctcp(int fd, char *cmd, char *source, char *target, char *msg) strftime(temp, sizeof(temp)-1, msg_txt(230), datetime); // Server time (normal time): %A, %B %d %Y %X. snprintf(send_string, IRC_MESSAGE_LENGTH, "NOTICE %s :\001TIME %s\001",source_nick,temp); - ircbot->send(send_string); + ircbot->send(send_string, false); } else if( strcmpi(cmd,"VERSION") == 0 ) { snprintf(send_string, IRC_MESSAGE_LENGTH, "NOTICE %s :\001VERSION Hercules.ws IRC Bridge\001",source_nick); - ircbot->send(send_string); + ircbot->send(send_string, false); #ifdef IRCBOT_DEBUG } else { ShowWarning("Unknown CTCP command received %s (%s) from %s\n",cmd,msg,source); @@ -308,10 +335,7 @@ void irc_privmsg_ctcp(int fd, char *cmd, char *source, char *target, char *msg) } } -/** - * Handler for the PRIVMSG IRC command (action depends on the message contents) - * @see irc_parse_sub - */ +/// @copydoc irc_bot_interface::privmsg() void irc_privmsg(int fd, char *cmd, char *source, char *target, char *msg) { size_t len = msg ? strlen(msg) : 0; nullpo_retv(source); @@ -322,7 +346,7 @@ void irc_privmsg(int fd, char *cmd, char *source, char *target, char *msg) { command[0] = message[0] = '\0'; sscanf(msg, "\001%499[^\001\r\n ] %499[^\r\n\001]\001", command, message); - irc_privmsg_ctcp(fd, command, source, target, message); + ircbot->privmsg_ctcp(fd, command, source, target, message); #ifdef IRCBOT_DEBUG } else if (strcmpi(target, channel->config->irc_nick) == 0) { ShowDebug("irc_privmsg: Received message from %s: '%s'\n", source ? source : "(null)", msg); @@ -349,11 +373,7 @@ void irc_privmsg(int fd, char *cmd, char *source, char *target, char *msg) { } } -/** - * Handler for the JOIN IRC command (notify an in-game channel of users joining - * the IRC channel) - * @see irc_parse_sub - */ +/// @copydoc irc_bot_interface::userjoin() void irc_userjoin(int fd, char *cmd, char *source, char *target, char *msg) { char source_nick[IRC_NICK_LENGTH], source_ident[IRC_IDENT_LENGTH], source_host[IRC_HOST_LENGTH]; @@ -369,11 +389,7 @@ void irc_userjoin(int fd, char *cmd, char *source, char *target, char *msg) { } } -/** - * Handler for the PART and QUIT IRC commands (notify an in-game channel of - * users leaving the IRC channel) - * @see irc_parse_sub - */ +/// @copydoc irc_bot_interface::userleave() void irc_userleave(int fd, char *cmd, char *source, char *target, char *msg) { char source_nick[IRC_NICK_LENGTH], source_ident[IRC_IDENT_LENGTH], source_host[IRC_HOST_LENGTH]; @@ -392,11 +408,7 @@ void irc_userleave(int fd, char *cmd, char *source, char *target, char *msg) { } } -/** - * Handler for the NICK IRC commands (notify an in-game channel of users - * changing their name while in the IRC channel) - * @see irc_parse_sub - */ +/// @copydoc irc_bot_interface::usernick() void irc_usernick(int fd, char *cmd, char *source, char *target, char *msg) { char source_nick[IRC_NICK_LENGTH], source_ident[IRC_IDENT_LENGTH], source_host[IRC_HOST_LENGTH]; @@ -412,11 +424,7 @@ void irc_usernick(int fd, char *cmd, char *source, char *target, char *msg) { } } -/** - * Relay a chat message to the irc channel the bot is connected to - * @param name Sender's name - * @param msg Message text - */ +/// @copydoc irc_bot_interface::relay() void irc_relay(const char *name, const char *msg) { if (!ircbot->isIn) @@ -428,12 +436,10 @@ void irc_relay(const char *name, const char *msg) else sprintf(send_string,"PRIVMSG %s :%s", channel->config->irc_channel, msg); - ircbot->send(send_string); + ircbot->send(send_string, false); } -/** - * IRC bot initializer - */ +/// @copydoc irc_bot_interface::init() void irc_bot_init(bool minimal) { /// Command handlers const struct irc_func irc_func_base[] = { @@ -479,22 +485,31 @@ void irc_bot_init(bool minimal) { ircbot->isOn = false; timer->add_func_list(ircbot->connect_timer, "irc_connect_timer"); + timer->add_func_list(ircbot->queue_timer, "irc_queue_timer"); + timer->add(timer->gettick() + 7000, ircbot->connect_timer, 0, 0); } -/** - * IRC bot finalizer - */ +/// @copydoc irc_bot_interface::final() void irc_bot_final(void) { int i; if (!channel->config->irc) return; if( ircbot->isOn ) { - ircbot->send("QUIT :Hercules is shutting down"); + ircbot->send("QUIT :Hercules is shutting down", true); sockt->close(ircbot->fd); } + if (ircbot->queue_tid != INVALID_TIMER) + timer->delete(ircbot->queue_tid, ircbot->queue_timer); + + while (ircbot->message_current != NULL) { + struct message_flood *next = ircbot->message_current->next; + aFree(ircbot->message_current); + ircbot->message_current = next; + } + for( i = 0; i < ircbot->funcs.size; i++ ) { aFree(ircbot->funcs.list[i]); } @@ -509,6 +524,15 @@ void ircbot_defaults(void) { ircbot->channel = NULL; + ircbot->flood_protection_enabled = true; + ircbot->flood_protection_rate = 1000; + ircbot->flood_protection_burst = 3; + ircbot->last_message_tick = INVALID_TIMER; + ircbot->queue_tid = INVALID_TIMER; + ircbot->messages_burst_count = 0; + ircbot->message_current = NULL; + ircbot->message_last = NULL; + ircbot->init = irc_bot_init; ircbot->final = irc_bot_final; @@ -522,11 +546,14 @@ void ircbot_defaults(void) { ircbot->identify_timer = irc_identify_timer; ircbot->join_timer = irc_join_timer; + ircbot->queue_timer = irc_queue_timer; + ircbot->queue = irc_queue; ircbot->send = irc_send; ircbot->relay = irc_relay; ircbot->pong = irc_pong; ircbot->privmsg = irc_privmsg; + ircbot->privmsg_ctcp = irc_privmsg_ctcp; ircbot->userjoin = irc_userjoin; ircbot->userleave = irc_userleave; diff --git a/src/map/irc-bot.h b/src/map/irc-bot.h index dc67e2fe8..f73426693 100644 --- a/src/map/irc-bot.h +++ b/src/map/irc-bot.h @@ -39,6 +39,11 @@ struct irc_func { void (*func)(int, char*, char*, char*, char*); }; +struct message_flood { + char message[IRC_MESSAGE_LENGTH]; + struct message_flood *next; +}; + struct irc_bot_interface { int fd; bool isIn, isOn; @@ -46,6 +51,15 @@ struct irc_bot_interface { unsigned char fails; uint32 ip; unsigned short port; + /* messages flood protection */ + bool flood_protection_enabled; + int flood_protection_rate; + int flood_protection_burst; + int64 last_message_tick; + int messages_burst_count; + int queue_tid; + struct message_flood *message_current; + struct message_flood *message_last; /* */ struct channel_data *channel; /* */ @@ -53,27 +67,132 @@ struct irc_bot_interface { struct irc_func **list; unsigned int size; } funcs; - /* */ + + /** + * IRC bot initializer + */ void (*init) (bool minimal); + + /** + * IRC bot finalizer + */ void (*final) (void); - /* */ + + /** + * Parser for the IRC server connection + * @see do_sockets + */ int (*parse) (int fd); + + /** + * Parse a received message from the irc server, and do the appropriate action + * for the detected command + * @param fd IRC server connection file descriptor + * @param str Raw received message + */ void (*parse_sub) (int fd, char *str); + + /** + * Parse the source from a received irc message + * @param source Source string, as reported by the server + * @param nick Pointer to a string where to return the nick (may not be NULL, + * needs to be able to fit an IRC_NICK_LENGTH long string) + * @param ident Pointer to a string where to return the ident (may not be + * NULL, needs to be able to fit an IRC_IDENT_LENGTH long string) + * @param host Pointer to a string where to return the hostname (may not be + * NULL, needs to be able to fit an IRC_HOST_LENGTH long string) + */ void (*parse_source) (char *source, char *nick, char *ident, char *host); - /* */ + + /** + * Search the handler for a given IRC received command + * @param function_name Name of the received IRC command + * @return Function pointer to the command handler, NULL in case + * of unhandled commands + */ struct irc_func* (*func_search) (char* function_name); - /* */ + + /** + * Timer callback to (re-)connect to an IRC server + * @see timer_interface::do_timer + */ int (*connect_timer) (int tid, int64 tick, int id, intptr_t data); + + /** + * Timer callback to send identification commands to an IRC server + * @see timer_interface::do_timer + */ int (*identify_timer) (int tid, int64 tick, int id, intptr_t data); + + /** + * Timer callback to join channels (and optionally send NickServ commands) + * @see timer_interface::do_timer + */ int (*join_timer) (int tid, int64 tick, int id, intptr_t data); - /* */ - void (*send)(char *str); + + /** + * Timer callback to send queued IRC Commands + * @see timer_interface::do_timer + */ + int (*queue_timer) (int tid, int64 tick, int id, intptr_t data); + + /** + * Decides if an IRC Command should be queued or not, based on the flood protection settings. + * + * @param str Command to be checked + */ + void (*queue) (char *str); + + /** + * Send a raw command to the irc server + * @param str Command to send + */ + void (*send)(char *str, bool force); + + /** + * Relay a chat message to the irc channel the bot is connected to + * @param name Sender's name + * @param msg Message text + */ void (*relay) (const char *name, const char *msg); - /* */ + + /** + * Handler for the PING IRC command (send back a PONG) + * @see irc_bot_interface::parse_sub + */ void (*pong) (int fd, char *cmd, char *source, char *target, char *msg); + + /** + * Handler for the PRIVMSG IRC command (action depends on the message contents) + * @see irc_bot_interface::parse_sub + */ void (*privmsg) (int fd, char *cmd, char *source, char *target, char *msg); + + /** + * Handler for CTCP commands received via PRIVMSG + * @see irc_bot_interface::privmsg + */ + void (*privmsg_ctcp) (int fd, char *cmd, char *source, char *target, char *msg); + + /** + * Handler for the JOIN IRC command (notify an in-game channel of users joining + * the IRC channel) + * @see irc_bot_interface::parse_sub + */ void (*userjoin) (int fd, char *cmd, char *source, char *target, char *msg); + + /** + * Handler for the PART and QUIT IRC commands (notify an in-game channel of + * users leaving the IRC channel) + * @see irc_bot_interface::parse_sub + */ void (*userleave) (int fd, char *cmd, char *source, char *target, char *msg); + + /** + * Handler for the NICK IRC commands (notify an in-game channel of users + * changing their name while in the IRC channel) + * @see irc_bot_interface::parse_sub + */ void (*usernick) (int fd, char *cmd, char *source, char *target, char *msg); }; diff --git a/src/map/itemdb.c b/src/map/itemdb.c index 630bc4488..c59f627cc 100644 --- a/src/map/itemdb.c +++ b/src/map/itemdb.c @@ -49,7 +49,7 @@ struct itemdb_interface *itemdb; * name = item alias, so we should find items aliases first. if not found then look for "jname" (full name) * @see DBApply */ -int itemdb_searchname_sub(DBKey key, DBData *data, va_list ap) +int itemdb_searchname_sub(union DBKey key, struct DBData *data, va_list ap) { struct item_data *item = DB->data2ptr(data), **dst, **dst2; char *str; @@ -112,7 +112,7 @@ struct item_data* itemdb_name2id(const char *str) { /** * @see DBMatcher */ -int itemdb_searchname_array_sub(DBKey key, DBData data, va_list ap) +int itemdb_searchname_array_sub(union DBKey key, struct DBData data, va_list ap) { struct item_data *item = DB->data2ptr(&data); char *str; @@ -170,10 +170,10 @@ int itemdb_searchname_array(struct item_data** data, int size, const char *str, // search in the db if( count < size ) { - DBData *db_data[MAX_SEARCH]; + struct DBData *db_data[MAX_SEARCH]; int db_count = 0; size -= count; - db_count = itemdb->other->getall(itemdb->other, (DBData**)&db_data, size, itemdb->searchname_array_sub, str); + db_count = itemdb->other->getall(itemdb->other, (struct DBData**)&db_data, size, itemdb->searchname_array_sub, str); for (i = 0; i < db_count; i++) data[count++] = DB->data2ptr(db_data[i]); count += db_count; @@ -2094,7 +2094,7 @@ uint64 itemdb_unique_id(struct map_session_data *sd) { */ void itemdb_read(bool minimal) { int i; - DBData prev; + struct DBData prev; const char *filename[] = { DBPATH"item_db.conf", @@ -2171,7 +2171,7 @@ void destroy_item_data(struct item_data* self, int free_self) /** * @see DBApply */ -int itemdb_final_sub(DBKey key, DBData *data, va_list ap) +int itemdb_final_sub(union DBKey key, struct DBData *data, va_list ap) { struct item_data *id = DB->data2ptr(data); @@ -2307,8 +2307,9 @@ void itemdb_reload(void) { } mapit->free(iter); } -void itemdb_name_constants(void) { - DBIterator *iter = db_iterator(itemdb->names); +void itemdb_name_constants(void) +{ + struct DBIterator *iter = db_iterator(itemdb->names); struct item_data *data; #ifdef ENABLE_CASE_CHECK @@ -2343,7 +2344,7 @@ void do_init_itemdb(bool minimal) { clif->cashshop_load(); /** it failed? we disable it **/ - if( !clif->parse_roulette_db() ) + if (battle_config.feature_roulette == 1 && !clif->parse_roulette_db()) battle_config.feature_roulette = 0; } void itemdb_defaults(void) { diff --git a/src/map/itemdb.h b/src/map/itemdb.h index 47446d617..d33805174 100644 --- a/src/map/itemdb.h +++ b/src/map/itemdb.h @@ -589,10 +589,10 @@ struct itemdb_interface { struct item_combo **combos; unsigned short combo_count; /* */ - DBMap *names; + struct DBMap *names; /* */ struct item_data *array[MAX_ITEMDB]; - DBMap *other;// int nameid -> struct item_data* + struct DBMap *other;// int nameid -> struct item_data* struct item_data dummy; //This is the default dummy item used for non-existant items. [Skotlex] /* */ void (*read_groups) (void); @@ -612,8 +612,8 @@ struct itemdb_interface { int (*group_item) (struct item_group *group); int (*chain_item) (unsigned short chain_id, int *rate); void (*package_item) (struct map_session_data *sd, struct item_package *package); - int (*searchname_sub) (DBKey key, DBData *data, va_list ap); - int (*searchname_array_sub) (DBKey key, DBData data, va_list ap); + int (*searchname_sub) (union DBKey key, struct DBData *data, va_list ap); + int (*searchname_array_sub) (union DBKey key, struct DBData data, va_list ap); int (*searchrandomid) (struct item_group *group); const char* (*typename) (int type); void (*jobmask2mapid) (uint64 *bclass, uint64 jobmask); @@ -647,7 +647,7 @@ struct itemdb_interface { uint64 (*unique_id) (struct map_session_data *sd); void (*read) (bool minimal); void (*destroy_item_data) (struct item_data *self, int free_self); - int (*final_sub) (DBKey key, DBData *data, va_list ap); + int (*final_sub) (union DBKey key, struct DBData *data, va_list ap); void (*clear) (bool total); struct item_combo * (*id2combo) (unsigned short id); bool (*is_item_usable) (struct item_data *item); diff --git a/src/map/log.c b/src/map/log.c index f757faf43..c19190d90 100644 --- a/src/map/log.c +++ b/src/map/log.c @@ -62,6 +62,16 @@ char log_picktype2char(e_log_pick_type type) { case LOG_TYPE_BUYING_STORE: return 'B'; // (B)uying Store case LOG_TYPE_LOOT: return 'L'; // (L)oot (consumed monster pick/drop) case LOG_TYPE_BANK: return 'K'; // Ban(K) Transactions + case LOG_TYPE_DIVORCE: return 'Y'; // Divorce + case LOG_TYPE_ROULETTE: return 'Z'; // Roulette + case LOG_TYPE_RENTAL: return 'W'; // Rental + case LOG_TYPE_CARD: return 'Q'; // Card + case LOG_TYPE_INV_INVALID: return 'J'; // Invalid in inventory + case LOG_TYPE_CART_INVALID: return 'H'; // Invalid in cart + case LOG_TYPE_EGG: return '@'; // Egg + case LOG_TYPE_QUEST: return '0'; // Quest + case LOG_TYPE_SKILL: return '1'; // Skill + case LOG_TYPE_REFINE: return '2'; // Refine case LOG_TYPE_OTHER: return 'X'; // Other } @@ -109,8 +119,9 @@ bool should_log_item(int nameid, int amount, int refine, struct item_data *id) { return false; } -void log_branch_sub_sql(struct map_session_data* sd) { - SqlStmt* stmt; +void log_branch_sub_sql(struct map_session_data* sd) +{ + struct SqlStmt *stmt; nullpo_retv(sd); stmt = SQL->StmtMalloc(logs->mysql_handle); @@ -269,15 +280,16 @@ void log_mvpdrop(struct map_session_data* sd, int monster_id, int* log_mvp) logs->mvpdrop_sub(sd,monster_id,log_mvp); } -void log_atcommand_sub_sql(struct map_session_data* sd, const char* message) { - SqlStmt* stmt; +void log_atcommand_sub_sql(struct map_session_data* sd, const char* message) +{ + struct SqlStmt *stmt; nullpo_retv(sd); nullpo_retv(message); stmt = SQL->StmtMalloc(logs->mysql_handle); if( SQL_SUCCESS != SQL->StmtPrepare(stmt, LOG_QUERY " INTO `%s` (`atcommand_date`, `account_id`, `char_id`, `char_name`, `map`, `command`) VALUES (NOW(), '%d', '%d', ?, '%s', ?)", logs->config.log_gm, sd->status.account_id, sd->status.char_id, mapindex_id2name(sd->mapindex) ) || SQL_SUCCESS != SQL->StmtBindParam(stmt, 0, SQLDT_STRING, sd->status.name, strnlen(sd->status.name, NAME_LENGTH)) - || SQL_SUCCESS != SQL->StmtBindParam(stmt, 1, SQLDT_STRING, (char*)message, safestrnlen(message, 255)) + || SQL_SUCCESS != SQL->StmtBindParam(stmt, 1, SQLDT_STRING, message, safestrnlen(message, 255)) || SQL_SUCCESS != SQL->StmtExecute(stmt) ) { SqlStmt_ShowDebug(stmt); @@ -312,17 +324,18 @@ void log_atcommand(struct map_session_data* sd, const char* message) logs->atcommand_sub(sd,message); } -void log_npc_sub_sql(struct map_session_data *sd, const char *message) { - SqlStmt* stmt; +void log_npc_sub_sql(struct map_session_data *sd, const char *message) +{ + struct SqlStmt *stmt; nullpo_retv(sd); nullpo_retv(message); stmt = SQL->StmtMalloc(logs->mysql_handle); - if( SQL_SUCCESS != SQL->StmtPrepare(stmt, LOG_QUERY " INTO `%s` (`npc_date`, `account_id`, `char_id`, `char_name`, `map`, `mes`) VALUES (NOW(), '%d', '%d', ?, '%s', ?)", logs->config.log_npc, sd->status.account_id, sd->status.char_id, mapindex_id2name(sd->mapindex) ) - || SQL_SUCCESS != SQL->StmtBindParam(stmt, 0, SQLDT_STRING, sd->status.name, strnlen(sd->status.name, NAME_LENGTH)) - || SQL_SUCCESS != SQL->StmtBindParam(stmt, 1, SQLDT_STRING, (char*)message, safestrnlen(message, 255)) - || SQL_SUCCESS != SQL->StmtExecute(stmt) ) - { + if (SQL_SUCCESS != SQL->StmtPrepare(stmt, LOG_QUERY " INTO `%s` (`npc_date`, `account_id`, `char_id`, `char_name`, `map`, `mes`) VALUES (NOW(), '%d', '%d', ?, '%s', ?)", logs->config.log_npc, sd->status.account_id, sd->status.char_id, mapindex_id2name(sd->mapindex) ) + || SQL_SUCCESS != SQL->StmtBindParam(stmt, 0, SQLDT_STRING, sd->status.name, strnlen(sd->status.name, NAME_LENGTH)) + || SQL_SUCCESS != SQL->StmtBindParam(stmt, 1, SQLDT_STRING, message, safestrnlen(message, 255)) + || SQL_SUCCESS != SQL->StmtExecute(stmt) + ) { SqlStmt_ShowDebug(stmt); SQL->StmtFree(stmt); return; @@ -369,14 +382,14 @@ void log_npc(struct map_session_data* sd, const char* message) */ void log_chat_sub_sql(e_log_chat_type type, int type_id, int src_charid, int src_accid, const char *mapname, int x, int y, const char *dst_charname, const char *message) { - SqlStmt* stmt; + struct SqlStmt* stmt; nullpo_retv(dst_charname); nullpo_retv(message); stmt = SQL->StmtMalloc(logs->mysql_handle); if( SQL_SUCCESS != SQL->StmtPrepare(stmt, LOG_QUERY " INTO `%s` (`time`, `type`, `type_id`, `src_charid`, `src_accountid`, `src_map`, `src_map_x`, `src_map_y`, `dst_charname`, `message`) VALUES (NOW(), '%c', '%d', '%d', '%d', '%s', '%d', '%d', ?, ?)", logs->config.log_chat, logs->chattype2char(type), type_id, src_charid, src_accid, mapname, x, y) - || SQL_SUCCESS != SQL->StmtBindParam(stmt, 0, SQLDT_STRING, (char*)dst_charname, safestrnlen(dst_charname, NAME_LENGTH)) - || SQL_SUCCESS != SQL->StmtBindParam(stmt, 1, SQLDT_STRING, (char*)message, safestrnlen(message, CHAT_SIZE_MAX)) + || SQL_SUCCESS != SQL->StmtBindParam(stmt, 0, SQLDT_STRING, dst_charname, safestrnlen(dst_charname, NAME_LENGTH)) + || SQL_SUCCESS != SQL->StmtBindParam(stmt, 1, SQLDT_STRING, message, safestrnlen(message, CHAT_SIZE_MAX)) || SQL_SUCCESS != SQL->StmtExecute(stmt) ) { SqlStmt_ShowDebug(stmt); diff --git a/src/map/log.h b/src/map/log.h index fbd0acc0e..0a5e13208 100644 --- a/src/map/log.h +++ b/src/map/log.h @@ -22,11 +22,11 @@ #define MAP_LOG_H #include "common/hercules.h" -#include "common/sql.h" /** * Declarations **/ +struct Sql; // common/sql.h struct item; struct item_data; struct map_session_data; @@ -57,29 +57,40 @@ typedef enum e_log_chat_type { } e_log_chat_type; typedef enum e_log_pick_type { - LOG_TYPE_NONE = 0, - LOG_TYPE_TRADE = 0x00001, - LOG_TYPE_VENDING = 0x00002, - LOG_TYPE_PICKDROP_PLAYER = 0x00004, - LOG_TYPE_PICKDROP_MONSTER = 0x00008, - LOG_TYPE_NPC = 0x00010, - LOG_TYPE_SCRIPT = 0x00020, - LOG_TYPE_STEAL = 0x00040, - LOG_TYPE_CONSUME = 0x00080, - LOG_TYPE_PRODUCE = 0x00100, - LOG_TYPE_MVP = 0x00200, - LOG_TYPE_COMMAND = 0x00400, - LOG_TYPE_STORAGE = 0x00800, - LOG_TYPE_GSTORAGE = 0x01000, - LOG_TYPE_MAIL = 0x02000, - LOG_TYPE_AUCTION = 0x04000, - LOG_TYPE_BUYING_STORE = 0x08000, - LOG_TYPE_OTHER = 0x10000, - LOG_TYPE_BANK = 0x20000, + LOG_TYPE_NONE = 0x00000000, + LOG_TYPE_TRADE = 0x00000001, + LOG_TYPE_VENDING = 0x00000002, + LOG_TYPE_PICKDROP_PLAYER = 0x00000004, + LOG_TYPE_PICKDROP_MONSTER = 0x00000008, + LOG_TYPE_NPC = 0x00000010, + LOG_TYPE_SCRIPT = 0x00000020, + LOG_TYPE_STEAL = 0x00000040, + LOG_TYPE_CONSUME = 0x00000080, + LOG_TYPE_PRODUCE = 0x00000100, + LOG_TYPE_MVP = 0x00000200, + LOG_TYPE_COMMAND = 0x00000400, + LOG_TYPE_STORAGE = 0x00000800, + LOG_TYPE_GSTORAGE = 0x00001000, + LOG_TYPE_MAIL = 0x00002000, + LOG_TYPE_AUCTION = 0x00004000, + LOG_TYPE_BUYING_STORE = 0x00008000, + LOG_TYPE_OTHER = 0x00010000, + LOG_TYPE_BANK = 0x00020000, + LOG_TYPE_DIVORCE = 0x00040000, + LOG_TYPE_ROULETTE = 0x00080000, + LOG_TYPE_RENTAL = 0x00100000, + LOG_TYPE_CARD = 0x00200000, + LOG_TYPE_INV_INVALID = 0x00400000, + LOG_TYPE_CART_INVALID = 0x00800000, + LOG_TYPE_EGG = 0x01000000, + LOG_TYPE_QUEST = 0x02000000, + LOG_TYPE_SKILL = 0x04000000, + LOG_TYPE_REFINE = 0x08000000, + // combinations LOG_TYPE_LOOT = LOG_TYPE_PICKDROP_MONSTER|LOG_TYPE_CONSUME, // all - LOG_TYPE_ALL = 0xFFFFF, + LOG_TYPE_ALL = 0xFFFFFFFF, } e_log_pick_type; /// filters for item logging @@ -116,7 +127,7 @@ struct log_interface { char db_id[32]; char db_pw[100]; char db_name[32]; - Sql* mysql_handle; + struct Sql *mysql_handle; /* */ void (*pick_pc) (struct map_session_data* sd, e_log_pick_type type, int amount, struct item* itm, struct item_data *data); void (*pick_mob) (struct mob_data* md, e_log_pick_type type, int amount, struct item* itm, struct item_data *data); diff --git a/src/map/map.c b/src/map/map.c index f2e47be74..3a7d752c3 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -69,6 +69,7 @@ #include "common/random.h" #include "common/showmsg.h" #include "common/socket.h" // WFIFO*() +#include "common/sql.h" #include "common/strlib.h" #include "common/timer.h" #include "common/utils.h" @@ -192,6 +193,7 @@ void map_update_cell_bl( struct block_list *bl, bool increase ) { #ifdef CELL_NOSTACK int pos; + nullpo_retv(bl); if( bl->m < 0 || bl->x < 0 || bl->x >= map->list[bl->m].xs || bl->y < 0 || bl->y >= map->list[bl->m].ys || !(bl->type&BL_CHAR) ) @@ -308,9 +310,14 @@ int map_delblock(struct block_list* bl) * (which are executed by default on BL_CHAR types) *------------------------------------------*/ int map_moveblock(struct block_list *bl, int x1, int y1, int64 tick) { - int x0 = bl->x, y0 = bl->y; struct status_change *sc = NULL; - int moveblock = ( x0/BLOCK_SIZE != x1/BLOCK_SIZE || y0/BLOCK_SIZE != y1/BLOCK_SIZE); + int x0, y0; + int moveblock; + + nullpo_ret(bl); + x0 = bl->x; + y0 = bl->y; + moveblock = ( x0/BLOCK_SIZE != x1/BLOCK_SIZE || y0/BLOCK_SIZE != y1/BLOCK_SIZE); if (!bl->prev) { //Block not in map, just update coordinates, but do naught else. @@ -476,6 +483,8 @@ struct skill_unit* map_find_skill_unit_oncell(struct block_list* target,int16 x, int16 m,bx,by; struct block_list *bl; struct skill_unit *su; + + nullpo_retr(NULL, target); m = target->m; if (x < 0 || y < 0 || (x >= map->list[m].xs) || (y >= map->list[m].ys)) @@ -853,6 +862,9 @@ static int bl_vgetall_inshootrange(struct block_list *bl, va_list args) struct block_list *center = va_arg(args, struct block_list*); #ifdef CIRCULAR_AREA int range = va_arg(args, int); + nullpo_ret(center); + nullpo_ret(bl); + if (!check_distance_bl(center, bl, range)) return 0; #endif @@ -1040,6 +1052,9 @@ static int bl_vgetall_inmovearea(struct block_list *bl, va_list args) struct block_list *center = va_arg(args, struct block_list*); int range = va_arg(args, int); + nullpo_ret(bl); + nullpo_ret(center); + if ((dx > 0 && bl->x < center->x - range + dx) || (dx < 0 && bl->x > center->x + range + dx) || (dy > 0 && bl->y < center->y - range + dy) || @@ -1202,11 +1217,15 @@ static int bl_vgetall_inpath(struct block_list *bl, va_list args) int len_limit = va_arg(args, int); int magnitude2 = va_arg(args, int); - int xi = bl->x; - int yi = bl->y; + int xi; + int yi; int xu, yu; + int k; - int k = ( xi - x0 ) * ( x1 - x0 ) + ( yi - y0 ) * ( y1 - y0 ); + nullpo_ret(bl); + xi = bl->x; + yi = bl->y; + k = ( xi - x0 ) * ( x1 - x0 ) + ( yi - y0 ) * ( y1 - y0 ); if ( k < 0 || k > len_limit ) //Since more skills use this, check for ending point as well. return 0; @@ -1421,6 +1440,9 @@ int map_searchrandfreecell(int16 m, const struct block_list *bl, int16 *x, int16 int free_cell,i,j; int free_cells[9][2]; + nullpo_ret(x); + nullpo_ret(y); + for(free_cell=0,i=-1;i<=1;i++){ if(i+*y<0 || i+*y>=map->list[m].ys) continue; @@ -1467,6 +1489,9 @@ int map_search_freecell(struct block_list *src, int16 m, int16 *x,int16 *y, int1 int rx2 = 2*rx+1; int ry2 = 2*ry+1; + nullpo_ret(x); + nullpo_ret(y); + if( !src && (!(flag&1) || flag&2) ) { ShowDebug("map_search_freecell: Incorrect usage! When src is NULL, flag has to be &1 and can't have &2\n"); @@ -1477,6 +1502,7 @@ int map_search_freecell(struct block_list *src, int16 m, int16 *x,int16 *y, int1 bx = *x; by = *y; } else { + nullpo_ret(src); bx = src->x; by = src->y; m = src->m; @@ -1533,10 +1559,15 @@ int map_search_freecell(struct block_list *src, int16 m, int16 *x,int16 *y, int1 bool map_closest_freecell(int16 m, const struct block_list *bl, int16 *x, int16 *y, int type, int flag) { uint8 dir = 6; - int16 tx = *x; - int16 ty = *y; + int16 tx; + int16 ty; int costrange = 10; + nullpo_ret(x); + nullpo_ret(y); + tx = *x; + ty = *y; + if(!map->count_oncell(m, tx, ty, type, flag)) return true; //Current cell is free @@ -1657,7 +1688,7 @@ int map_addflooritem(const struct block_list *bl, struct item *item_data, int am /** * @see DBCreateData */ -DBData create_charid2nick(DBKey key, va_list args) +struct DBData create_charid2nick(union DBKey key, va_list args) { struct charid2nick *p; CREATE(p, struct charid2nick, 1); @@ -1694,7 +1725,7 @@ void map_delnickdb(int charid, const char* name) { struct charid2nick* p; struct charid_request* req; - DBData data; + struct DBData data; if (!map->nick_db->remove(map->nick_db, DB->i2key(charid), &data) || (p = DB->data2ptr(&data)) == NULL) return; @@ -1793,6 +1824,8 @@ void map_deliddb(struct block_list *bl) int map_quit(struct map_session_data *sd) { int i; + nullpo_ret(sd); + if(!sd->state.active) { //Removing a player that is not active. struct auth_node *node = chrif->search(sd->status.account_id); if (node && node->char_id == sd->status.char_id && @@ -2166,9 +2199,9 @@ struct map_session_data * map_nick2sd(const char *nick) /*========================================== * Convext Mirror *------------------------------------------*/ -struct mob_data * map_getmob_boss(int16 m) +struct mob_data *map_getmob_boss(int16 m) { - DBIterator* iter; + struct DBIterator *iter; struct mob_data *md = NULL; bool found = false; @@ -2230,11 +2263,11 @@ uint32 map_race_id2mask(int race) /// Applies func to all the players in the db. /// Stops iterating if func returns -1. -void map_vforeachpc(int (*func)(struct map_session_data* sd, va_list args), va_list args) { - DBIterator* iter; - struct map_session_data* sd; +void map_vforeachpc(int (*func)(struct map_session_data* sd, va_list args), va_list args) +{ + struct DBIterator *iter = db_iterator(map->pc_db); + struct map_session_data *sd = NULL; - iter = db_iterator(map->pc_db); for( sd = dbi_first(iter); dbi_exists(iter); sd = dbi_next(iter) ) { va_list argscopy; @@ -2262,11 +2295,11 @@ void map_foreachpc(int (*func)(struct map_session_data* sd, va_list args), ...) /// Applies func to all the mobs in the db. /// Stops iterating if func returns -1. -void map_vforeachmob(int (*func)(struct mob_data* md, va_list args), va_list args) { - DBIterator* iter; - struct mob_data* md; +void map_vforeachmob(int (*func)(struct mob_data* md, va_list args), va_list args) +{ + struct DBIterator *iter = db_iterator(map->mobid_db); + struct mob_data *md = NULL; - iter = db_iterator(map->mobid_db); for (md = dbi_first(iter); dbi_exists(iter); md = dbi_next(iter)) { va_list argscopy; int ret; @@ -2293,11 +2326,11 @@ void map_foreachmob(int (*func)(struct mob_data* md, va_list args), ...) { /// Applies func to all the npcs in the db. /// Stops iterating if func returns -1. -void map_vforeachnpc(int (*func)(struct npc_data* nd, va_list args), va_list args) { - DBIterator* iter; - struct block_list* bl; +void map_vforeachnpc(int (*func)(struct npc_data* nd, va_list args), va_list args) +{ + struct DBIterator *iter = db_iterator(map->id_db); + struct block_list *bl = NULL; - iter = db_iterator(map->id_db); for (bl = dbi_first(iter); dbi_exists(iter); bl = dbi_next(iter)) { if (bl->type == BL_NPC) { struct npc_data *nd = BL_UCAST(BL_NPC, bl); @@ -2327,11 +2360,11 @@ void map_foreachnpc(int (*func)(struct npc_data* nd, va_list args), ...) { /// Applies func to everything in the db. /// Stops iterating gif func returns -1. -void map_vforeachregen(int (*func)(struct block_list* bl, va_list args), va_list args) { - DBIterator* iter; - struct block_list* bl; +void map_vforeachregen(int (*func)(struct block_list* bl, va_list args), va_list args) +{ + struct DBIterator *iter = db_iterator(map->regen_db); + struct block_list *bl = NULL; - iter = db_iterator(map->regen_db); for (bl = dbi_first(iter); dbi_exists(iter); bl = dbi_next(iter)) { va_list argscopy; int ret; @@ -2358,11 +2391,11 @@ void map_foreachregen(int (*func)(struct block_list* bl, va_list args), ...) { /// Applies func to everything in the db. /// Stops iterating if func returns -1. -void map_vforeachiddb(int (*func)(struct block_list* bl, va_list args), va_list args) { - DBIterator* iter; - struct block_list* bl; +void map_vforeachiddb(int (*func)(struct block_list* bl, va_list args), va_list args) +{ + struct DBIterator *iter = db_iterator(map->id_db); + struct block_list *bl = NULL; - iter = db_iterator(map->id_db); for (bl = dbi_first(iter); dbi_exists(iter); bl = dbi_next(iter)) { va_list argscopy; int ret; @@ -2389,11 +2422,10 @@ void map_foreachiddb(int (*func)(struct block_list* bl, va_list args), ...) { /// Iterator. /// Can filter by bl type. -struct s_mapiterator -{ - enum e_mapitflags flags;// flags for special behaviour - enum bl_type types;// what bl types to return - DBIterator* dbi;// database iterator +struct s_mapiterator { + enum e_mapitflags flags; ///< flags for special behaviour + enum bl_type types; ///< what bl types to return + struct DBIterator *dbi; ///< database iterator }; /// Returns true if the block_list matches the description in the iterator. @@ -2547,6 +2579,7 @@ bool map_addnpc(int16 m,struct npc_data *nd) { // Returns the index of successful, or -1 if the list was full. int map_addmobtolist(unsigned short m, struct spawn_data *spawn) { int i; + nullpo_retr(-1, spawn); ARR_FIND( 0, MAX_MOB_LIST_PER_MAP, i, map->list[m].moblist[i] == NULL ); if( i < MAX_MOB_LIST_PER_MAP ) { map->list[m].moblist[i] = spawn; @@ -2628,6 +2661,7 @@ int map_removemobs_timer(int tid, int64 tick, int id, intptr_t data) { } void map_removemobs(int16 m) { + Assert_retv(m >= 0 && m < map->count); if (map->list[m].mob_delete_timer != INVALID_TIMER) // should never happen return; //Mobs are already scheduled for removal @@ -2662,6 +2696,8 @@ int16 map_mapindex2mapid(unsigned short map_index) { int map_mapname2ipport(unsigned short name, uint32* ip, uint16* port) { struct map_data_other_server *mdos; + nullpo_retr(-1, ip); + nullpo_retr(-1, port); mdos = (struct map_data_other_server*)uidb_get(map->map_db,(unsigned int)name); if(mdos==NULL || mdos->cell) //If gat isn't null, this is a local map. return -1; @@ -2737,11 +2773,19 @@ uint8 map_calc_dir(struct block_list* src, int16 x, int16 y) *------------------------------------------*/ int map_random_dir(struct block_list *bl, int16 *x, int16 *y) { - short xi = *x-bl->x; - short yi = *y-bl->y; + short xi; + short yi; short i=0; - int dist2 = xi*xi + yi*yi; - short dist = (short)sqrt((float)dist2); + int dist2; + short dist; + + nullpo_ret(bl); + nullpo_ret(x); + nullpo_ret(y); + xi = *x-bl->x; + yi = *y-bl->y; + dist2 = xi*xi + yi*yi; + dist = (short)sqrt((float)dist2); if (dist < 1) dist =1; @@ -2794,7 +2838,10 @@ int map_cell2gat(struct mapcell cell) { return 1; // default to 'wall' } void map_cellfromcache(struct map_data *m) { - struct map_cache_map_info *info = (struct map_cache_map_info *)m->cellPos; + struct map_cache_map_info *info; + + nullpo_retv(m); + info = (struct map_cache_map_info *)m->cellPos; if (info) { char decode_buffer[MAX_MAP_SIZE]; @@ -2897,6 +2944,7 @@ int map_getcellp(struct map_data* m, const struct block_list *bl, int16 x, int16 /* [Ind/Hercules] */ int map_sub_getcellp(struct map_data* m, const struct block_list *bl, int16 x, int16 y, cell_chk cellchk) { + nullpo_ret(m); map->cellfromcache(m); m->getcellp = map->getcellp; m->setcell = map->setcell; @@ -2963,6 +3011,9 @@ void map_setgatcell(int16 m, int16 x, int16 y, int gat) { *------------------------------------------*/ void map_iwall_nextxy(int16 x, int16 y, int8 dir, int pos, int16 *x1, int16 *y1) { + nullpo_retv(x1); + nullpo_retv(y1); + if( dir == 0 || dir == 4 ) *x1 = x; // Keep X else if( dir > 0 && dir < 4 ) @@ -3022,12 +3073,15 @@ bool map_iwall_set(int16 m, int16 x, int16 y, int size, int8 dir, bool shootable return true; } -void map_iwall_get(struct map_session_data *sd) { +void map_iwall_get(struct map_session_data *sd) +{ struct iwall_data *iwall; - DBIterator* iter; + struct DBIterator *iter; int16 x1, y1; int i; + nullpo_retv(sd); + if( map->list[sd->bl.m].iwall_num < 1 ) return; @@ -3068,7 +3122,7 @@ void map_iwall_remove(const char *wall_name) /** * @see DBCreateData */ -DBData create_map_data_other_server(DBKey key, va_list args) +struct DBData create_map_data_other_server(union DBKey key, va_list args) { struct map_data_other_server *mdos; unsigned short map_index = (unsigned short)key.ui; @@ -3103,9 +3157,10 @@ int map_setipport(unsigned short map_index, uint32 ip, uint16 port) * Delete all the other maps server management * @see DBApply */ -int map_eraseallipport_sub(DBKey key, DBData *data, va_list va) +int map_eraseallipport_sub(union DBKey key, struct DBData *data, va_list va) { struct map_data_other_server *mdos = DB->data2ptr(data); + nullpo_ret(mdos); if(mdos->cell == NULL) { db_remove(map->map_db,key); aFree(mdos); @@ -3192,6 +3247,9 @@ int map_readfromcache(struct map_data *m, char *buffer) { struct map_cache_map_info *info = NULL; char *p = buffer + sizeof(struct map_cache_main_header); + nullpo_ret(m); + nullpo_ret(buffer); + for(i = 0; i < header->map_count; i++) { info = (struct map_cache_map_info *)p; @@ -3233,6 +3291,7 @@ int map_addmap(const char* mapname) { } void map_delmapid(int id) { + Assert_retv(id >= 0 && id < map->count); ShowNotice("Removing map [ %s ] from maplist"CL_CLL"\n",map->list[id].name); memmove(map->list+id, map->list+id+1, sizeof(map->list[0])*(map->count-id-1)); map->count--; @@ -3242,6 +3301,7 @@ int map_delmap(char* mapname) { int i; char map_name[MAP_NAME_LENGTH]; + nullpo_ret(mapname); if (strcmpi(mapname, "all") == 0) { map->count = 0; return 0; @@ -3263,6 +3323,8 @@ int map_delmap(char* mapname) { void map_zone_clear_single(struct map_zone_data *zone) { int i; + nullpo_retv(zone); + for(i = 0; i < zone->disabled_skills_count; i++) { aFree(zone->disabled_skills[i]); } @@ -3300,9 +3362,10 @@ void map_zone_clear_single(struct map_zone_data *zone) { /** * **/ -void map_zone_db_clear(void) { - struct map_zone_data *zone; - DBIterator *iter = db_iterator(map->zone_db); +void map_zone_db_clear(void) +{ + struct DBIterator *iter = db_iterator(map->zone_db); + struct map_zone_data *zone = NULL; for(zone = dbi_first(iter); dbi_exists(iter); zone = dbi_next(iter)) { map->zone_clear_single(zone); @@ -3319,6 +3382,7 @@ void map_zone_db_clear(void) { } void map_clean(int i) { int v; + Assert_retv(i >= 0 && i < map->count); if(map->list[i].cell && map->list[i].cell != (struct mapcell *)0xdeadbeaf) aFree(map->list[i].cell); if(map->list[i].block) aFree(map->list[i].block); if(map->list[i].block_mob) aFree(map->list[i].block_mob); @@ -3517,6 +3581,7 @@ int map_waterheight(char* mapname) char fn[256]; char *rsw, *found; + nullpo_retr(NO_WATER, mapname); //Look up for the rsw snprintf(fn, sizeof(fn), "data\\%s.rsw", mapname); @@ -3545,6 +3610,7 @@ int map_readgat (struct map_data* m) int water_height; size_t xy, off, num_cells; + nullpo_ret(m); sprintf(filename, "data\\%s.gat", m->name); gat = (uint8 *) grfio_read(filename); @@ -3582,10 +3648,12 @@ int map_readgat (struct map_data* m) * Add/Remove map to the map_db *--------------------------------------*/ void map_addmap2db(struct map_data *m) { + nullpo_retv(m); map->index2mapid[m->index] = m->m; } void map_removemapdb(struct map_data *m) { + nullpo_retv(m); map->index2mapid[m->index] = -1; } @@ -3690,6 +3758,8 @@ int map_config_read(char *cfgName) { char line[1024], w1[1024], w2[1024]; FILE *fp; + nullpo_retr(1, cfgName); + fp = fopen(cfgName,"r"); if( fp == NULL ) { ShowError("Map configuration file not found at: %s\n", cfgName); @@ -3784,6 +3854,7 @@ int map_config_read_sub(char *cfgName) { char line[1024], w1[1024], w2[1024]; FILE *fp; + nullpo_retr(1, cfgName); fp = fopen(cfgName,"r"); if (fp == NULL) { ShowError("Map configuration file not found at: %s\n", cfgName); @@ -3821,6 +3892,7 @@ void map_reloadnpc_sub(char *cfgName) { char line[1024], w1[1024], w2[1024]; FILE *fp; + nullpo_retv(cfgName); fp = fopen(cfgName,"r"); if (fp == NULL) { ShowError("Map configuration file not found at: %s\n", cfgName); @@ -3882,6 +3954,7 @@ int inter_config_read(char *cfgName) { char line[1024],w1[1024],w2[1024]; FILE *fp; + nullpo_retr(1, cfgName); if (!(fp = fopen(cfgName,"r"))) { ShowError("File not found: %s\n",cfgName); return 1; @@ -3979,6 +4052,9 @@ struct map_zone_data *map_merge_zone(struct map_zone_data *main, struct map_zone struct map_zone_data *zone = NULL; int cursor, i, j; + nullpo_retr(NULL, main); + nullpo_retr(NULL, other); + sprintf(newzone, "%s+%s",main->name,other->name); if( (zone = strdb_get(map->zone_db, newzone)) ) @@ -4072,6 +4148,7 @@ void map_zone_change2(int m, struct map_zone_data *zone) { const char *empty = ""; + Assert_retv(m >= 0 && m < map->count); if( map->list[m].zone == zone ) return; @@ -4089,6 +4166,7 @@ void map_zone_change2(int m, struct map_zone_data *zone) } /* when changing from a mapflag to another during runtime */ void map_zone_change(int m, struct map_zone_data *zone, const char* start, const char* buffer, const char* filepath) { + Assert_retv(m >= 0 && m < map->count); map->list[m].prev_zone = map->list[m].zone; if( map->list[m].zone_mf_count ) @@ -4101,6 +4179,7 @@ void map_zone_remove(int m) char flag[MAP_ZONE_MAPFLAG_LENGTH], params[MAP_ZONE_MAPFLAG_LENGTH]; unsigned short k; const char *empty = ""; + Assert_retv(m >= 0 && m < map->count); for(k = 0; k < map->list[m].zone_mf_count; k++) { size_t len = strlen(map->list[m].zone_mf[k]),j; params[0] = '\0'; @@ -4123,6 +4202,7 @@ void map_zone_remove(int m) map->list[m].zone_mf_count = 0; } static inline void map_zone_mf_cache_add(int m, char *rflag) { + Assert_retv(m >= 0 && m < map->count); RECREATE(map->list[m].zone_mf, char *, ++map->list[m].zone_mf_count); CREATE(map->list[m].zone_mf[map->list[m].zone_mf_count - 1], char, MAP_ZONE_MAPFLAG_LENGTH); safestrncpy(map->list[m].zone_mf[map->list[m].zone_mf_count - 1], rflag, MAP_ZONE_MAPFLAG_LENGTH); @@ -4133,6 +4213,10 @@ bool map_zone_mf_cache(int m, char *flag, char *params) { char rflag[MAP_ZONE_MAPFLAG_LENGTH]; int state = 1; + nullpo_retr(false, flag); + nullpo_retr(false, params); + Assert_retr(false, m >= 0 && m < map->count); + if (params[0] != '\0' && !strcmpi(params, "off")) state = 0; @@ -4829,6 +4913,8 @@ void map_zone_apply(int m, struct map_zone_data *zone, const char* start, const int i; const char *empty = ""; char flag[MAP_ZONE_MAPFLAG_LENGTH], params[MAP_ZONE_MAPFLAG_LENGTH]; + Assert_retv(m >= 0 && m < map->count); + nullpo_retv(zone); map->list[m].zone = zone; for(i = 0; i < zone->mapflags_count; i++) { size_t len = strlen(zone->mapflags[i]); @@ -4939,8 +5025,9 @@ unsigned short map_zone_str2skillid(const char *name) { enum bl_type map_zone_bl_type(const char *entry, enum map_zone_skill_subtype *subtype) { char temp[200], *parse; enum bl_type bl = BL_NUL; - *subtype = MZS_NONE; + nullpo_retr(BL_NUL, subtype); + *subtype = MZS_NONE; if( !entry ) return BL_NUL; @@ -5414,6 +5501,8 @@ int map_get_new_bonus_id (void) { void map_add_questinfo(int m, struct questinfo *qi) { unsigned short i; + nullpo_retv(qi); + Assert_retv(m >= 0 && m < map->count); /* duplicate, override */ for(i = 0; i < map->list[m].qi_count; i++) { if( map->list[m].qi_data[i].nd == qi->nd ) @@ -5429,6 +5518,7 @@ void map_add_questinfo(int m, struct questinfo *qi) { bool map_remove_questinfo(int m, struct npc_data *nd) { unsigned short i; + Assert_retr(false, m >= 0 && m < map->count); for(i = 0; i < map->list[m].qi_count; i++) { struct questinfo *qi = &map->list[m].qi_data[i]; if( qi->nd == nd ) { @@ -5445,7 +5535,8 @@ bool map_remove_questinfo(int m, struct npc_data *nd) { /** * @see DBApply */ -int map_db_final(DBKey key, DBData *data, va_list ap) { +int map_db_final(union DBKey key, struct DBData *data, va_list ap) +{ struct map_data_other_server *mdos = DB->data2ptr(data); if(mdos && iMalloc->verify_ptr(mdos) && mdos->cell == NULL) @@ -5457,7 +5548,7 @@ int map_db_final(DBKey key, DBData *data, va_list ap) { /** * @see DBApply */ -int nick_db_final(DBKey key, DBData *data, va_list args) +int nick_db_final(union DBKey key, struct DBData *data, va_list args) { struct charid2nick* p = DB->data2ptr(data); struct charid_request* req; @@ -5504,7 +5595,8 @@ int cleanup_sub(struct block_list *bl, va_list ap) { /** * @see DBApply */ -int cleanup_db_sub(DBKey key, DBData *data, va_list va) { +int cleanup_db_sub(union DBKey key, struct DBData *data, va_list va) +{ return map->cleanup_sub(DB->data2ptr(data), va); } diff --git a/src/map/map.h b/src/map/map.h index ff7ca2d38..dbd30febf 100644 --- a/src/map/map.h +++ b/src/map/map.h @@ -27,11 +27,12 @@ #include "common/db.h" #include "common/mapindex.h" #include "common/mmo.h" -#include "common/sql.h" #include <stdio.h> #include <stdarg.h> +/* Forward Declarations */ +struct Sql; // common/sql.h struct mob_data; struct npc_data; struct channel_data; @@ -398,7 +399,7 @@ struct flooritem_data { struct item item_data; }; -enum status_point_types { +enum status_point_types { //we better clean up this enum and change it name [Hemagx] SP_SPEED,SP_BASEEXP,SP_JOBEXP,SP_KARMA,SP_MANNER,SP_HP,SP_MAXHP,SP_SP, // 0-7 SP_MAXSP,SP_STATUSPOINT,SP_0a,SP_BASELEVEL,SP_SKILLPOINT,SP_STR,SP_AGI,SP_VIT, // 8-15 SP_INT,SP_DEX,SP_LUK,SP_CLASS,SP_ZENY,SP_SEX,SP_NEXTBASEEXP,SP_NEXTJOBEXP, // 16-23 @@ -993,7 +994,7 @@ struct map_interface { char server_id[32]; char server_pw[100]; char server_db[32]; - Sql* mysql_handle; + struct Sql *mysql_handle; int port; int users; @@ -1003,16 +1004,16 @@ struct map_interface { int16 index2mapid[MAX_MAPINDEX]; /* */ - DBMap* id_db; // int id -> struct block_list* - DBMap* pc_db; // int id -> struct map_session_data* - DBMap* mobid_db; // int id -> struct mob_data* - DBMap* bossid_db; // int id -> struct mob_data* (MVP db) - DBMap* map_db; // unsigned int mapindex -> struct map_data_other_server* - DBMap* nick_db; // int char_id -> struct charid2nick* (requested names of offline characters) - DBMap* charid_db; // int char_id -> struct map_session_data* - DBMap* regen_db; // int id -> struct block_list* (status_natural_heal processing) - DBMap* zone_db; // string => struct map_zone_data - DBMap* iwall_db; + struct DBMap *id_db; // int id -> struct block_list* + struct DBMap *pc_db; // int id -> struct map_session_data* + struct DBMap *mobid_db; // int id -> struct mob_data* + struct DBMap *bossid_db; // int id -> struct mob_data* (MVP db) + struct DBMap *map_db; // unsigned int mapindex -> struct map_data_other_server* + struct DBMap *nick_db; // int char_id -> struct charid2nick* (requested names of offline characters) + struct DBMap *charid_db; // int char_id -> struct map_session_data* + struct DBMap *regen_db; // int id -> struct block_list* (status_natural_heal processing) + struct DBMap *zone_db; // string => struct map_zone_data + struct DBMap *iwall_db; struct block_list **block_free; int block_free_count, block_free_lock, block_free_list_size; struct block_list **bl_list; @@ -1166,7 +1167,7 @@ END_ZEROED_BLOCK; int (*freeblock_timer) (int tid, int64 tick, int id, intptr_t data); int (*searchrandfreecell) (int16 m, const struct block_list *bl, int16 *x, int16 *y, int stack); int (*count_sub) (struct block_list *bl, va_list ap); - DBData (*create_charid2nick) (DBKey key, va_list args); + struct DBData (*create_charid2nick) (union DBKey key, va_list args); int (*removemobs_sub) (struct block_list *bl, va_list ap); struct mapcell (*gat2cell) (int gat); int (*cell2gat) (struct mapcell cell); @@ -1175,8 +1176,8 @@ END_ZEROED_BLOCK; int (*sub_getcellp) (struct map_data *m, const struct block_list *bl, int16 x, int16 y, cell_chk cellchk); void (*sub_setcell) (int16 m, int16 x, int16 y, cell_t cell, bool flag); void (*iwall_nextxy) (int16 x, int16 y, int8 dir, int pos, int16 *x1, int16 *y1); - DBData (*create_map_data_other_server) (DBKey key, va_list args); - int (*eraseallipport_sub) (DBKey key, DBData *data, va_list va); + struct DBData (*create_map_data_other_server) (union DBKey key, va_list args); + int (*eraseallipport_sub) (union DBKey key, struct DBData *data, va_list va); char* (*init_mapcache) (FILE *fp); int (*readfromcache) (struct map_data *m, char *buffer); int (*addmap) (const char *mapname); @@ -1197,9 +1198,9 @@ END_ZEROED_BLOCK; unsigned short (*zone_str2skillid) (const char *name); enum bl_type (*zone_bl_type) (const char *entry, enum map_zone_skill_subtype *subtype); void (*read_zone_db) (void); - int (*db_final) (DBKey key, DBData *data, va_list ap); - int (*nick_db_final) (DBKey key, DBData *data, va_list args); - int (*cleanup_db_sub) (DBKey key, DBData *data, va_list va); + int (*db_final) (union DBKey key, struct DBData *data, va_list ap); + int (*nick_db_final) (union DBKey key, struct DBData *data, va_list args); + int (*cleanup_db_sub) (union DBKey key, struct DBData *data, va_list va); int (*abort_sub) (struct map_session_data *sd, va_list ap); void (*update_cell_bl) (struct block_list *bl, bool increase); int (*get_new_bonus_id) (void); diff --git a/src/map/mapreg.h b/src/map/mapreg.h index dfe1dfb2d..d19b2bb80 100644 --- a/src/map/mapreg.h +++ b/src/map/mapreg.h @@ -59,7 +59,7 @@ struct mapreg_interface { void (*load) (void); void (*save) (void); int (*save_timer) (int tid, int64 tick, int id, intptr_t data); - int (*destroyreg) (DBKey key, DBData *data, va_list ap); + int (*destroyreg) (union DBKey key, struct DBData *data, va_list ap); void (*reload) (void); bool (*config_read) (const char *w1, const char *w2); }; diff --git a/src/map/mapreg_sql.c b/src/map/mapreg_sql.c index 46962ac14..82ce39d64 100644 --- a/src/map/mapreg_sql.c +++ b/src/map/mapreg_sql.c @@ -28,6 +28,7 @@ #include "common/db.h" #include "common/ers.h" #include "common/memmgr.h" +#include "common/nullpo.h" #include "common/showmsg.h" #include "common/sql.h" #include "common/strlib.h" @@ -76,6 +77,7 @@ bool mapreg_setreg(int64 uid, int val) { unsigned int i = script_getvaridx(uid); const char* name = script->get_str(num); + nullpo_retr(true, name); if( val != 0 ) { if( (m = i64db_get(mapreg->regs.vars, uid)) ) { m->u.i = val; @@ -132,6 +134,8 @@ bool mapreg_setregstr(int64 uid, const char* str) { unsigned int i = script_getvaridx(uid); const char* name = script->get_str(num); + nullpo_retr(true, name); + if( str == NULL || *str == 0 ) { if( i ) script->array_update(&mapreg->regs, uid, true); @@ -190,7 +194,7 @@ void script_load_mapreg(void) { | varname | index | value | +-------------------------+ */ - SqlStmt* stmt = SQL->StmtMalloc(map->mysql_handle); + struct SqlStmt *stmt = SQL->StmtMalloc(map->mysql_handle); char varname[SCRIPT_VARNAME_LENGTH+1]; int index; char value[255+1]; @@ -236,15 +240,17 @@ void script_load_mapreg(void) { /** * Saves permanent variables to database. */ -void script_save_mapreg(void) { +void script_save_mapreg(void) +{ if (mapreg->dirty) { - DBIterator *iter = db_iterator(mapreg->regs.vars); - struct mapreg_save *m; + struct DBIterator *iter = db_iterator(mapreg->regs.vars); + struct mapreg_save *m = NULL; for (m = dbi_first(iter); dbi_exists(iter); m = dbi_next(iter)) { if (m->save) { int num = script_getvarid(m->uid); int i = script_getvaridx(m->uid); const char* name = script->get_str(num); + nullpo_retv(name); if (!m->is_string) { if( SQL_ERROR == SQL->Query(map->mysql_handle, "UPDATE `%s` SET `value`='%d' WHERE `varname`='%s' AND `index`='%d' LIMIT 1", mapreg->table, m->u.i, name, i) ) Sql_ShowDebug(map->mysql_handle); @@ -277,7 +283,8 @@ int script_autosave_mapreg(int tid, int64 tick, int id, intptr_t data) { * * @see DBApply */ -int mapreg_destroyreg(DBKey key, DBData *data, va_list ap) { +int mapreg_destroyreg(union DBKey key, struct DBData *data, va_list ap) +{ struct mapreg_save *m = NULL; if (data->type != DB_DATA_PTR) // Sanity check @@ -344,6 +351,8 @@ void mapreg_init(void) { * Loads the mapreg configuration file. */ bool mapreg_config_read(const char* w1, const char* w2) { + nullpo_retr(false, w1); + nullpo_retr(false, w2); if(!strcmpi(w1, "mapreg_db")) safestrncpy(mapreg->table, w2, sizeof(mapreg->table)); else diff --git a/src/map/mercenary.c b/src/map/mercenary.c index fa337e13b..0b055bedf 100644 --- a/src/map/mercenary.c +++ b/src/map/mercenary.c @@ -234,6 +234,7 @@ int mercenary_set_calls(struct mercenary_data *md, int value) int mercenary_save(struct mercenary_data *md) { + nullpo_retr(1, md); md->mercenary.hp = md->battle_status.hp; md->mercenary.sp = md->battle_status.sp; md->mercenary.life_time = mercenary->get_lifetime(md); @@ -265,7 +266,10 @@ int merc_contract_end_timer(int tid, int64 tick, int id, intptr_t data) { int merc_delete(struct mercenary_data *md, int reply) { - struct map_session_data *sd = md->master; + struct map_session_data *sd; + + nullpo_retr(0, md); + sd = md->master; md->mercenary.life_time = 0; mercenary->contract_stop(md); @@ -299,6 +303,7 @@ void merc_contract_stop(struct mercenary_data *md) void merc_contract_init(struct mercenary_data *md) { + nullpo_retv(md); if( md->contract_timer == INVALID_TIMER ) md->contract_timer = timer->add(timer->gettick() + md->mercenary.life_time, mercenary->contract_end_timer, md->master->bl.id, 0); @@ -310,8 +315,10 @@ int merc_data_received(const struct s_mercenary *merc, bool flag) struct map_session_data *sd; struct mercenary_data *md; struct s_mercenary_db *db; - int i = mercenary->search_index(merc->class_); + int i; + nullpo_ret(merc); + i = mercenary->search_index(merc->class_); if( (sd = map->charid2sd(merc->char_id)) == NULL ) return 0; if (!flag || i == INDEX_NOT_FOUND) { @@ -370,6 +377,7 @@ int merc_data_received(const struct s_mercenary *merc, bool flag) void mercenary_heal(struct mercenary_data *md, int hp, int sp) { + nullpo_retv(md); if( hp ) clif->mercenary_updatestatus(md->master, SP_HP); if( sp ) @@ -387,12 +395,14 @@ int mercenary_killbonus(struct mercenary_data *md) const enum sc_type scs[] = { SC_MER_FLEE, SC_MER_ATK, SC_MER_HP, SC_MER_SP, SC_MER_HIT }; int index = rnd() % ARRAYLENGTH(scs); + nullpo_ret(md); sc_start(NULL,&md->bl, scs[index], 100, rnd() % 5, 600000); return 0; } int mercenary_kills(struct mercenary_data *md) { + nullpo_ret(md); md->mercenary.kill_count++; md->mercenary.kill_count = cap_value(md->mercenary.kill_count, 0, INT_MAX); @@ -425,6 +435,8 @@ bool read_mercenarydb_sub(char* str[], int columns, int current) { struct s_mercenary_db *db; struct status_data *mstatus; + nullpo_retr(false, str); + Assert_retr(false, current >= 0 && current < MAX_MERCENARY_CLASS); db = &mercenary->db[current]; db->class_ = atoi(str[0]); safestrncpy(db->sprite, str[1], NAME_LENGTH); @@ -486,6 +498,7 @@ bool read_mercenary_skilldb_sub(char* str[], int columns, int current) int i, class_; uint16 skill_id, skill_lv; + nullpo_retr(false, str); class_ = atoi(str[0]); ARR_FIND(0, MAX_MERCENARY_CLASS, i, class_ == mercenary->db[i].class_); if( i == MAX_MERCENARY_CLASS ) diff --git a/src/map/mob.c b/src/map/mob.c index 8d38fead7..19fee52a5 100644 --- a/src/map/mob.c +++ b/src/map/mob.c @@ -114,6 +114,8 @@ struct mob_chat *mob_chat(short id) { int mobdb_searchname(const char *str) { int i; + + nullpo_ret(str); for(i=0;i<=MAX_MOB_DB;i++){ struct mob_db *monster = mob->db(i); if(monster == mob->dummy) //Skip dummy mobs. @@ -129,10 +131,13 @@ int mobdb_searchname(const char *str) return 0; } int mobdb_searchname_array_sub(struct mob_db* monster, const char *str, int flag) { + + nullpo_ret(monster); if (monster == mob->dummy) return 1; if(!monster->base_exp && !monster->job_exp && monster->spawn[0].qty < 1) return 1; // Monsters with no base/job exp and no spawn point are, by this criteria, considered "slave mobs" and excluded from search results + nullpo_ret(str); if( !flag ) { if(stristr(monster->jname,str)) return 0; @@ -156,6 +161,7 @@ void mvptomb_create(struct mob_data *md, char *killer, time_t time) { struct npc_data *nd; + nullpo_retv(md); if ( md->tomb_nid ) mob->mvptomb_destroy(md); @@ -181,6 +187,7 @@ void mvptomb_create(struct mob_data *md, char *killer, time_t time) void mvptomb_destroy(struct mob_data *md) { struct npc_data *nd; + nullpo_retv(md); if ( (nd = map->id2nd(md->tomb_nid)) ) { int16 m, i; @@ -212,6 +219,7 @@ int mobdb_searchname_array(struct mob_db** data, int size, const char *str, int { int count = 0, i; struct mob_db* monster; + nullpo_ret(data); for(i=0;i<=MAX_MOB_DB;i++){ monster = mob->db(i); if (monster == mob->dummy || mob->is_clone(i) ) //keep clones out (or you leak player stats) @@ -253,6 +261,7 @@ int mob_parse_dataset(struct spawn_data *data) { size_t len; + nullpo_ret(data); if ((!mob->db_checkid(data->class_) && !mob->is_clone(data->class_)) || !data->num) return 0; @@ -276,6 +285,7 @@ int mob_parse_dataset(struct spawn_data *data) *------------------------------------------*/ struct mob_data* mob_spawn_dataset(struct spawn_data *data) { struct mob_data *md = NULL; + nullpo_retr(NULL, data); CREATE(md, struct mob_data, 1); md->bl.id= npc->get_new_npc_id(); md->bl.type = BL_MOB; @@ -328,6 +338,7 @@ int mob_get_random_id(int type, int flag, int lv) ShowError("mob_get_random_id: Invalid type (%d) of random monster.\n", type); return 0; } + Assert_ret(type >= 0 && type < MAX_RANDOMMONSTER); do { if (type) class_ = summon[type].class_[rnd()%summon[type].qty]; @@ -410,7 +421,7 @@ bool mob_ksprotected(struct block_list *src, struct block_list *target) { if( DIFF_TICK(sd->ks_floodprotect_tick, tick) <= 0 ) { sprintf(output, "[KS Warning!! - Owner : %s]", pl_sd->status.name); - clif_disp_onlyself(sd, output, strlen(output)); + clif_disp_onlyself(sd, output); sd->ks_floodprotect_tick = tick + 2000; } @@ -419,7 +430,7 @@ bool mob_ksprotected(struct block_list *src, struct block_list *target) { if( DIFF_TICK(pl_sd->ks_floodprotect_tick, tick) <= 0 ) { sprintf(output, "[Watch out! %s is trying to KS you!]", sd->status.name); - clif_disp_onlyself(pl_sd, output, strlen(output)); + clif_disp_onlyself(pl_sd, output); pl_sd->ks_floodprotect_tick = tick + 2000; } @@ -634,6 +645,11 @@ int mob_spawn_guardian(const char* mapname, short x, short y, const char* mobnam struct guild *g=NULL; struct guild_castle *gc; int16 m; + + nullpo_ret(mapname); + nullpo_ret(mobname); + nullpo_ret(event); + memset(&data, 0, sizeof(struct spawn_data)); data.num = 1; @@ -728,6 +744,10 @@ int mob_spawn_bg(const char* mapname, short x, short y, const char* mobname, int struct spawn_data data; int16 m; + nullpo_ret(mapname); + nullpo_ret(mobname); + nullpo_ret(event); + if( (m = map->mapname2mapid(mapname)) < 0 ) { ShowWarning("mob_spawn_bg: Map [%s] not found.\n", mapname); return 0; @@ -846,6 +866,8 @@ int mob_setdelayspawn(struct mob_data *md) uint32 mode; struct mob_db *db; + nullpo_ret(md); + if (!md->spawn) //Doesn't has respawn data! return unit->free(&md->bl,CLR_DEAD); @@ -903,6 +925,7 @@ int mob_spawn (struct mob_data *md) int64 tick = timer->gettick(); int64 c = 0; + nullpo_retr(1, md); md->last_thinktime = tick; if (md->bl.prev != NULL) unit->remove_map(&md->bl,CLR_RESPAWN,ALC_MARK); @@ -992,6 +1015,8 @@ int mob_spawn (struct mob_data *md) *------------------------------------------*/ int mob_can_changetarget(const struct mob_data *md, const struct block_list *target, uint32 mode) { + nullpo_ret(md); + nullpo_ret(target); // if the monster was provoked ignore the above rule [celest] if(md->state.provoke_flag) { @@ -1057,6 +1082,8 @@ int mob_ai_sub_hard_activesearch(struct block_list *bl, va_list ap) md=va_arg(ap,struct mob_data *); target= va_arg(ap,struct block_list**); mode = va_arg(ap, uint32); + nullpo_ret(md); + nullpo_ret(target); //If can't seek yet, not an enemy, or you can't attack it, skip. if (md->bl.id == bl->id || (*target) == bl || !status->check_skilluse(&md->bl, bl, 0, 0)) @@ -1111,8 +1138,10 @@ int mob_ai_sub_hard_changechase(struct block_list *bl,va_list ap) { struct block_list **target; nullpo_ret(bl); - md=va_arg(ap,struct mob_data *); - target= va_arg(ap,struct block_list**); + md = va_arg(ap,struct mob_data *); + target = va_arg(ap,struct block_list**); + nullpo_ret(md); + nullpo_ret(target); //If can't seek yet, not an enemy, or you can't attack it, skip. if( md->bl.id == bl->id || *target == bl @@ -1139,6 +1168,8 @@ int mob_ai_sub_hard_bg_ally(struct block_list *bl,va_list ap) { nullpo_ret(bl); md=va_arg(ap,struct mob_data *); target= va_arg(ap,struct block_list**); + nullpo_retr(1, md); + nullpo_retr(1, target); if( status->check_skilluse(&md->bl, bl, 0, 0) && battle->check_target(&md->bl,bl,BCT_ENEMY)<=0 ) { (*target) = bl; @@ -1157,6 +1188,8 @@ int mob_ai_sub_hard_lootsearch(struct block_list *bl,va_list ap) md=va_arg(ap,struct mob_data *); target= va_arg(ap,struct block_list**); + nullpo_ret(md); + nullpo_ret(target); dist=distance_bl(&md->bl, bl); if(mob->can_reach(md,bl,dist+1, MSS_LOOT) && @@ -1177,6 +1210,9 @@ int mob_warpchase_sub(struct block_list *bl,va_list ap) { struct npc_data *nd = NULL; nullpo_ret(bl); + nullpo_ret(target); + nullpo_ret(target_nd); + nullpo_ret(min_distance); Assert_ret(bl->type == BL_NPC); nd = BL_UCAST(BL_NPC, bl); @@ -1201,6 +1237,7 @@ int mob_warpchase_sub(struct block_list *bl,va_list ap) { int mob_ai_sub_hard_slavemob(struct mob_data *md, int64 tick) { struct block_list *bl; + nullpo_ret(md); bl=map->id2bl(md->master_id); if (!bl || status->isdead(bl)) { @@ -1378,6 +1415,7 @@ int mob_warpchase(struct mob_data *md, struct block_list *target) { struct npc_data *warp = NULL; int distance = AREA_SIZE; + nullpo_ret(md); if (!(target && battle_config.mob_ai&0x40 && battle_config.mob_warp&1)) return 0; //Can't warp chase. @@ -1405,6 +1443,7 @@ bool mob_ai_sub_hard(struct mob_data *md, int64 tick) { uint32 mode; int view_range, can_move; + nullpo_retr(false, md); if(md->bl.prev == NULL || md->status.hp <= 0) return false; @@ -1702,6 +1741,7 @@ int mob_ai_sub_hard_timer(struct block_list *bl, va_list ap) *------------------------------------------*/ int mob_ai_sub_foreachclient(struct map_session_data *sd, va_list ap) { int64 tick; + nullpo_ret(sd); tick=va_arg(ap, int64); map->foreachinrange(mob->ai_sub_hard_timer,&sd->bl, AREA_SIZE+ACTIVE_AI_RANGE, BL_MOB,tick); @@ -1810,7 +1850,10 @@ struct item_drop* mob_setdropitem(int nameid, int qty, struct item_data *data) { *------------------------------------------*/ struct item_drop* mob_setlootitem(struct item* item) { - struct item_drop *drop = ers_alloc(item_drop_ers, struct item_drop); + struct item_drop *drop ; + + nullpo_retr(NULL, item); + drop = ers_alloc(item_drop_ers, struct item_drop); memcpy(&drop->item_data, item, sizeof(struct item)); drop->next = NULL; return drop; @@ -1847,6 +1890,9 @@ void mob_item_drop(struct mob_data *md, struct item_drop_list *dlist, struct ite { struct map_session_data *sd = NULL; + nullpo_retv(md); + nullpo_retv(dlist); + nullpo_retv(ditem); //Logs items, dropped by mobs [Lupus] logs->pick_mob(md, loot?LOG_TYPE_LOOT:LOG_TYPE_PICKDROP_MONSTER, -ditem->item_data.amount, &ditem->item_data, NULL); @@ -1932,6 +1978,9 @@ void mob_log_damage(struct mob_data *md, struct block_list *src, int damage) { int char_id = 0, flag = MDLF_NORMAL; + nullpo_retv(md); + nullpo_retv(src); + if( damage < 0 ) return; //Do nothing for absorbed damage. if( !damage && !(src->type&DEFAULT_ENEMY_TYPE(md)) ) @@ -2042,6 +2091,7 @@ void mob_log_damage(struct mob_data *md, struct block_list *src, int damage) } //Call when a mob has received damage. void mob_damage(struct mob_data *md, struct block_list *src, int damage) { + nullpo_retv(md); if (damage > 0) { //Store total damage... if (UINT_MAX - (unsigned int)damage > md->tdmg) md->tdmg+=damage; @@ -2105,12 +2155,14 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) { int id,zeny; unsigned int base_exp,job_exp; } pt[DAMAGELOG_SIZE] = { { 0 } }; - int i, temp, count, m = md->bl.m; + int i, temp, count, m; int dmgbltypes = 0; // bitfield of all bl types, that caused damage to the mob and are eligible for exp distribution unsigned int mvp_damage; int64 tick = timer->gettick(); bool rebirth, homkillonly; + nullpo_retr(3, md); + m = md->bl.m; mstatus = &md->status; if( md->guardian_data && md->guardian_data->number >= 0 && md->guardian_data->number < MAX_GUARDIANS ) @@ -2395,14 +2447,16 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) { char message[128]; sprintf (message, msg_txt(541), mvp_sd->status.name, md->name, it->jname, (float)drop_rate/100); //MSG: "'%s' won %s's %s (chance: %0.02f%%)" - intif->broadcast(message, strlen(message)+1, BC_DEFAULT); + intif->broadcast(message, (int)strlen(message)+1, BC_DEFAULT); } /* heres the thing we got the feature set up however we're still discussing how to best define the ids, * so while we discuss, for a small period of time, the list is hardcoded (yes officially only those 2 use it, * thus why we're unsure on how to best place the setting) */ /* temp, will not be hardcoded for long thudu. */ - if (it->nameid == ITEMID_GOLD_KEY77 || it->nameid == ITEMID_SILVER_KEY77) /* for when not hardcoded: add a check on mvp bonus drop as well */ + // TODO: This should be a field in the item db. + if (mvp_sd != NULL + && (it->nameid == ITEMID_GOLD_KEY77 || it->nameid == ITEMID_SILVER_KEY77)) /* for when not hardcoded: add a check on mvp bonus drop as well */ clif->item_drop_announce(mvp_sd, it->nameid, md->name); // Announce first, or else ditem will be freed. [Lance] @@ -2502,60 +2556,62 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) { pc->gainexp(mvp_sd, &md->bl, mexp,0, false); log_mvp[1] = mexp; - if( !(map->list[m].flag.nomvploot || type&1) ) { + if (!(map->list[m].flag.nomvploot || type&1)) { /* pose them randomly in the list -- so on 100% drop servers it wont always drop the same item */ - int mdrop_id[MAX_MVP_DROP]; - int mdrop_p[MAX_MVP_DROP]; - struct item item; - - memset(&mdrop_id,0,MAX_MVP_DROP*sizeof(int)); - - for(i = 0; i < MAX_MVP_DROP; i++) { - while( 1 ) { - int va = rnd()%MAX_MVP_DROP; - if( !mdrop_id[va] || !md->db->mvpitem[i].nameid ) { - mdrop_id[va] = md->db->mvpitem[i].nameid; - mdrop_p[va] = md->db->mvpitem[i].p; - break; - } - } + struct { + int nameid; + int p; + } mdrop[MAX_MVP_DROP] = { { 0 } }; + + for (i = 0; i < MAX_MVP_DROP; i++) { + int rpos; + if (md->db->mvpitem[i].nameid == 0) + continue; + do { + rpos = rnd()%MAX_MVP_DROP; + } while (mdrop[rpos].nameid != 0); + + mdrop[rpos].nameid = md->db->mvpitem[i].nameid; + mdrop[rpos].p = md->db->mvpitem[i].p; } - for(i = 0; i < MAX_MVP_DROP; i++) { - struct item_data *data; - if(mdrop_id[i] <= 0) + for (i = 0; i < MAX_MVP_DROP; i++) { + struct item_data *data = NULL; + int rate = 0; + + if (mdrop[i].nameid <= 0) continue; - if(! (data = itemdb->exists(mdrop_id[i])) ) + if ((data = itemdb->exists(mdrop[i].nameid)) == NULL) continue; - temp = mdrop_p[i]; - if(temp <= 0 && !battle_config.drop_rate0item) - temp = 1; - if(temp <= rnd()%10000+1) //if ==0, then it doesn't drop - continue; + rate = mdrop[i].p; + if (rate <= 0 && !battle_config.drop_rate0item) + rate = 1; + if (rate > rnd()%10000) { + struct item item = { 0 }; + + item.nameid = mdrop[i].nameid; + item.identify = itemdb->isidentified2(data); + clif->mvp_item(mvp_sd, item.nameid); + log_mvp[0] = item.nameid; + + //A Rare MVP Drop Global Announce by Lupus + if (rate <= battle_config.rare_drop_announce) { + char message[128]; + sprintf(message, msg_txt(541), mvp_sd->status.name, md->name, data->jname, rate/100.); + //MSG: "'%s' won %s's %s (chance: %0.02f%%)" + intif->broadcast(message, (int)strlen(message)+1, BC_DEFAULT); + } - memset(&item,0,sizeof(item)); - item.nameid=mdrop_id[i]; - item.identify= itemdb->isidentified2(data); - clif->mvp_item(mvp_sd,item.nameid); - log_mvp[0] = item.nameid; - - //A Rare MVP Drop Global Announce by Lupus - if(temp<=battle_config.rare_drop_announce) { - char message[128]; - sprintf (message, msg_txt(541), mvp_sd->status.name, md->name, data->jname, temp/100.); - //MSG: "'%s' won %s's %s (chance: %0.02f%%)" - intif->broadcast(message, strlen(message)+1, BC_DEFAULT); - } + if((temp = pc->additem(mvp_sd,&item,1,LOG_TYPE_PICKDROP_PLAYER)) != 0) { + clif->additem(mvp_sd,0,0,temp); + map->addflooritem(&md->bl, &item, 1, mvp_sd->bl.m, mvp_sd->bl.x, mvp_sd->bl.y, mvp_sd->status.char_id, (second_sd?second_sd->status.char_id : 0), (third_sd ? third_sd->status.char_id : 0), 1); + } - if((temp = pc->additem(mvp_sd,&item,1,LOG_TYPE_PICKDROP_PLAYER)) != 0) { - clif->additem(mvp_sd,0,0,temp); - map->addflooritem(&md->bl, &item, 1, mvp_sd->bl.m, mvp_sd->bl.x, mvp_sd->bl.y, mvp_sd->status.char_id, (second_sd?second_sd->status.char_id : 0), (third_sd ? third_sd->status.char_id : 0), 1); + //Logs items, MVP prizes [Lupus] + logs->pick_mob(md, LOG_TYPE_MVP, -1, &item, data); + break; } - - //Logs items, MVP prizes [Lupus] - logs->pick_mob(md, LOG_TYPE_MVP, -1, &item, data); - break; } } @@ -2661,6 +2717,8 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) { void mob_revive(struct mob_data *md, unsigned int hp) { int64 tick = timer->gettick(); + + nullpo_retv(md); md->state.skillstate = MSS_IDLE; md->last_thinktime = tick; md->next_walktime = tick+rnd()%1000+MIN_RANDOMWALKTIME; @@ -2808,6 +2866,7 @@ int mob_class_change (struct mob_data *md, int class_) { *------------------------------------------*/ void mob_heal(struct mob_data *md, unsigned int heal) { + nullpo_retv(md); if (battle_config.show_mob_info&3) clif->charnameack (0, &md->bl); #if PACKETVER >= 20131223 @@ -2842,6 +2901,7 @@ int mob_warpslave_sub(struct block_list *bl, va_list ap) range = va_arg(ap, int); nullpo_ret(bl); + nullpo_ret(master); Assert_ret(bl->type == BL_MOB); md = BL_UCAST(BL_MOB, bl); @@ -2859,6 +2919,7 @@ int mob_warpslave_sub(struct block_list *bl, va_list ap) * appear in randomly. *------------------------------------------*/ int mob_warpslave(struct block_list *bl, int range) { + nullpo_ret(bl); if (range < 1) range = 1; //Min range needed to avoid crashes and stuff. [Skotlex] @@ -2886,6 +2947,7 @@ int mob_countslave_sub(struct block_list *bl, va_list ap) * Counts the number of slaves a mob has on the map. *------------------------------------------*/ int mob_countslave(struct block_list *bl) { + nullpo_ret(bl); return map->foreachinmap(mob->countslave_sub, bl->m, BL_MOB,bl->id); } @@ -3014,6 +3076,8 @@ int mob_getfriendhprate_sub(struct block_list *bl,va_list ap) struct mob_data *md; md = va_arg(ap,struct mob_data *); + nullpo_ret(bl); + nullpo_ret(md); min_rate=va_arg(ap,int); max_rate=va_arg(ap,int); fr=va_arg(ap,struct block_list **); @@ -3324,6 +3388,8 @@ int mobskill_use(struct mob_data *md, int64 tick, int event) { int mobskill_event(struct mob_data *md, struct block_list *src, int64 tick, int flag) { int target_id, res = 0; + nullpo_ret(md); + nullpo_ret(src); if(md->bl.prev == NULL || md->status.hp <= 0) return 0; @@ -3385,7 +3451,7 @@ int mob_clone_spawn(struct map_session_data *sd, int16 m, int16 x, int16 y, cons return 0; ARR_FIND( MOB_CLONE_START, MOB_CLONE_END, class_, mob->db_data[class_] == NULL ); - if(class_ >= MOB_CLONE_END) + if(class_ < 0 || class_ >= MOB_CLONE_END) return 0; db = mob->db_data[class_]=(struct mob_db*)aCalloc(1, sizeof(struct mob_db)); @@ -3575,7 +3641,10 @@ int mob_clone_spawn(struct map_session_data *sd, int16 m, int16 x, int16 y, cons int mob_clone_delete(struct mob_data *md) { - const int class_ = md->class_; + int class_; + + nullpo_ret(md); + class_ = md->class_; if (class_ >= MOB_CLONE_START && class_ < MOB_CLONE_END && mob->db_data[class_]!=NULL) { mob->destroy_mob_db(class_); @@ -3665,6 +3734,7 @@ unsigned int mob_drop_adjust(int baserate, int rate_adjust, unsigned short rate_ */ void item_dropratio_adjust(int nameid, int mob_id, int *rate_adjust) { + nullpo_retv(rate_adjust); if( item_drop_ratio_db[nameid] ) { if( item_drop_ratio_db[nameid]->mob_id[0] ) { // only for listed mobs int i; @@ -3699,6 +3769,7 @@ static inline int mob_parse_dbrow_cap_value(int class_, int min, int max, int va void mob_read_db_stats_sub(struct mob_db *entry, struct config_setting_t *t) { int i32; + nullpo_retv(entry); if (mob->lookup_const(t, "Str", &i32) && i32 >= 0) { entry->status.str = mob_parse_dbrow_cap_value(entry->mob_id, UINT16_MIN, UINT16_MAX, i32); } @@ -3782,6 +3853,7 @@ void mob_read_db_mvpdrops_sub(struct mob_db *entry, struct config_setting_t *t) int idx = 0; int i32; + nullpo_retv(entry); while (idx < MAX_MVP_DROP && (drop = libconfig->setting_get_elem(t, i))) { const char *name = config_setting_name(drop); int rate_adjust = battle_config.item_rate_mvp; @@ -3839,6 +3911,7 @@ void mob_read_db_drops_sub(struct mob_db *entry, struct config_setting_t *t) int i32; int k; + nullpo_retv(entry); while (idx < MAX_MOB_DROP && (drop = libconfig->setting_get_elem(t, i))) { const char *name = config_setting_name(drop); int rate_adjust, type; @@ -3960,6 +4033,7 @@ int mob_db_validate_entry(struct mob_db *entry, int n, const char *source) { struct mob_data data; + nullpo_ret(entry); if (entry->mob_id <= 1000 || entry->mob_id > MAX_MOB_DB) { ShowError("mob_db_validate_entry: Invalid monster ID %d, must be in range %d-%d.\n", entry->mob_id, 1000, MAX_MOB_DB); return 0; @@ -4393,6 +4467,8 @@ bool mob_lookup_const(const struct config_setting_t *it, const char *name, int * bool mob_get_const(const struct config_setting_t *it, int *value) { const char *str = config_setting_get_string(it); + + nullpo_retr(false, value); if (str && *str && script->get_constant(str, value)) return true; @@ -4489,6 +4565,7 @@ bool mob_readdb_mobavail(char* str[], int columns, int current) { int class_, k; + nullpo_retr(false, str); class_=atoi(str[0]); if(mob->db(class_) == mob->dummy) { @@ -4600,6 +4677,8 @@ bool mob_parse_row_chatdb(char** str, const char* source, int line, int* last_ms int msg_id; size_t len; + nullpo_retr(false, str); + nullpo_retr(false, last_msg_id); msg_id = atoi(str[0]); if (msg_id <= 0 || msg_id > MAX_MOB_CHAT) @@ -4784,6 +4863,7 @@ bool mob_parse_row_mobskilldb(char** str, int columns, int current) int i =0, j, tmp; uint16 sidx = 0; + nullpo_retr(false, str); mob_id = atoi(str[0]); if (mob_id > 0 && mob->db(mob_id) == mob->dummy) @@ -4999,6 +5079,7 @@ bool mob_readdb_race2(char* fields[], int columns, int current) { int race, i; + nullpo_retr(false, fields); race = atoi(fields[0]); if (race < RC2_NONE || race >= RC2_MAX) { @@ -5023,6 +5104,8 @@ bool mob_readdb_race2(char* fields[], int columns, int current) bool mob_readdb_itemratio(char* str[], int columns, int current) { int nameid, ratio, i; + + nullpo_retr(false, str); nameid = atoi(str[0]); if( itemdb->exists(nameid) == NULL ) @@ -5124,7 +5207,9 @@ int do_init_mob(bool minimal) { void mob_destroy_mob_db(int index) { - struct mob_db *data = mob->db_data[index]; + struct mob_db *data; + Assert_retv(index >= 0 && index <= MAX_MOB_DB); + data = mob->db_data[index]; HPM->data_store_destroy(&data->hdata); aFree(data); mob->db_data[index] = NULL; diff --git a/src/map/npc.c b/src/map/npc.c index 2b1a541d8..6b55bf5ae 100644 --- a/src/map/npc.c +++ b/src/map/npc.c @@ -47,6 +47,7 @@ #include "common/nullpo.h" #include "common/showmsg.h" #include "common/socket.h" +#include "common/sql.h" #include "common/strlib.h" #include "common/timer.h" #include "common/utils.h" @@ -61,17 +62,6 @@ struct npc_interface npc_s; struct npc_interface *npc; -static int npc_id=START_NPC_NUM; -static int npc_warp=0; -static int npc_shop=0; -static int npc_script=0; -static int npc_mob=0; -static int npc_delay_mob=0; -static int npc_cache_mob=0; - -static const char *npc_last_path; -static const char *npc_last_ref; -struct npc_path_data *npc_last_npd; //For holding the view data of npc classes. [Skotlex] static struct view_data npc_viewdb[MAX_NPC_CLASS]; @@ -131,15 +121,15 @@ bool npc_db_checkid(int id) /// Returns a new npc id that isn't being used in id_db. /// Fatal error if nothing is available. int npc_get_new_npc_id(void) { - if( npc_id >= START_NPC_NUM && !map->blid_exists(npc_id) ) - return npc_id++;// available + if (npc->npc_id >= START_NPC_NUM && !map->blid_exists(npc->npc_id)) + return npc->npc_id++;// available else {// find next id - int base_id = npc_id; - while( base_id != ++npc_id ) { - if( npc_id < START_NPC_NUM ) - npc_id = START_NPC_NUM; - if( !map->blid_exists(npc_id) ) - return npc_id++;// available + int base_id = npc->npc_id; + while (base_id != ++npc->npc_id) { + if (npc->npc_id < START_NPC_NUM) + npc->npc_id = START_NPC_NUM; + if (!map->blid_exists(npc->npc_id)) + return npc->npc_id++;// available } // full loop, nothing available ShowFatalError("npc_get_new_npc_id: All ids are taken. Exiting..."); @@ -176,6 +166,7 @@ int npc_ontouch_event(struct map_session_data *sd, struct npc_data *nd) { char name[EVENT_NAME_LENGTH]; + nullpo_retr(1, nd); if( nd->touching_id ) return 0; // Attached a player already. Can't trigger on anyone else. @@ -190,6 +181,8 @@ int npc_ontouch2_event(struct map_session_data *sd, struct npc_data *nd) { char name[EVENT_NAME_LENGTH]; + nullpo_retr(1, sd); + nullpo_retr(1, nd); if (sd->areanpc_id == nd->bl.id) return 0; @@ -201,6 +194,8 @@ int npc_onuntouch_event(struct map_session_data *sd, struct npc_data *nd) { char name[EVENT_NAME_LENGTH]; + nullpo_ret(sd); + nullpo_ret(nd); if (sd->areanpc_id != nd->bl.id) return 0; @@ -366,7 +361,7 @@ int npc_event_dequeue(struct map_session_data* sd) /** * @see DBCreateData */ -DBData npc_event_export_create(DBKey key, va_list args) +struct DBData npc_event_export_create(union DBKey key, va_list args) { struct linkdb_node** head_ptr; CREATE(head_ptr, struct linkdb_node*, 1); @@ -380,8 +375,12 @@ DBData npc_event_export_create(DBKey key, va_list args) *------------------------------------------*/ int npc_event_export(struct npc_data *nd, int i) { - char* lname = nd->u.scr.label_list[i].name; - int pos = nd->u.scr.label_list[i].pos; + char* lname; + int pos; + nullpo_ret(nd); + Assert_ret(i >= 0 && i < nd->u.scr.label_list_num); + lname = nd->u.scr.label_list[i].name; + pos = nd->u.scr.label_list[i].pos; if ((lname[0] == 'O' || lname[0] == 'o') && (lname[1] == 'N' || lname[1] == 'n')) { struct event_data *ev; struct linkdb_node **label_linkdb = NULL; @@ -434,6 +433,7 @@ void npc_event_doall_sub(void *key, void *data, va_list ap) // runs the specified event (supports both single-npc and global events) int npc_event_do(const char* name) { + nullpo_ret(name); if( name[0] == ':' && name[1] == ':' ) { return npc->event_doall(name+2); // skip leading "::" } @@ -538,9 +538,12 @@ void npc_event_do_oninit( bool reload ) int npc_timerevent_export(struct npc_data *nd, int i) { int t = 0, len = 0; - char *lname = nd->u.scr.label_list[i].name; - int pos = nd->u.scr.label_list[i].pos; - if (sscanf(lname, "OnTimer%d%n", &t, &len) == 1 && lname[len] == '\0') { + char *lname; + int pos; + nullpo_ret(nd); + lname = nd->u.scr.label_list[i].name; + pos = nd->u.scr.label_list[i].pos; + if (sscanf(lname, "OnTimer%d%n", &t, &len) == 1 && len < NAME_LENGTH && lname[len] == '\0') { // Timer event struct npc_timerevent_list *te = nd->u.scr.timer_event; int j, k = nd->u.scr.timeramount; @@ -580,6 +583,8 @@ int npc_timerevent(int tid, int64 tick, int id, intptr_t data) struct timer_event_data *ted = (struct timer_event_data*)data; struct map_session_data *sd=NULL; + nullpo_ret(ted); + if( nd == NULL ) { ShowError("npc_timerevent: NPC not found??\n"); return 0; @@ -732,6 +737,7 @@ void npc_timerevent_quit(struct map_session_data* sd) struct npc_data* nd; struct timer_event_data *ted; + nullpo_retv(sd); // Check timer existence if( sd->npc_timer_id == INVALID_TIMER ) return; @@ -763,6 +769,7 @@ void npc_timerevent_quit(struct map_session_data* sd) { int old_rid,old_timer; int64 old_tick; + nullpo_retv(ted); //Set timer related info. old_rid = (nd->u.scr.rid == sd->bl.id ? 0 : nd->u.scr.rid); // Detach rid if the last attached player logged off. @@ -831,6 +838,8 @@ int npc_settimerevent_tick(struct npc_data* nd, int newtimer) int npc_event_sub(struct map_session_data* sd, struct event_data* ev, const char* eventname) { + nullpo_retr(2, sd); + nullpo_retr(2, eventname); if ( sd->npc_id != 0 ) { //Enqueue the event trigger. @@ -915,9 +924,11 @@ int npc_touch_areanpc_sub(struct block_list *bl, va_list ap) { * If not, it unsets it and searches for another player in range. *------------------------------------------*/ int npc_touchnext_areanpc(struct map_session_data* sd, bool leavemap) { - struct npc_data *nd = map->id2nd(sd->touching_id); + struct npc_data *nd; short xs, ys; + nullpo_retr(1, sd); + nd = map->id2nd(sd->touching_id); if( !nd || nd->touching_id != sd->bl.id ) return 1; @@ -949,7 +960,7 @@ int npc_touch_areanpc(struct map_session_data* sd, int16 m, int16 x, int16 y) int j, found_warp = 0; nullpo_retr(1, sd); - + Assert_retr(1, m >= 0 && m < map->count); #if 0 // Why not enqueue it? [Inkfish] if(sd->npc_id) return 1; @@ -1034,6 +1045,7 @@ int npc_untouch_areanpc(struct map_session_data* sd, int16 m, int16 x, int16 y) { struct npc_data *nd = NULL; nullpo_retr(1, sd); + Assert_retr(1, m >= 0 && m < map->count); if (!sd->areanpc_id) return 0; @@ -1053,11 +1065,16 @@ int npc_untouch_areanpc(struct map_session_data* sd, int16 m, int16 x, int16 y) // Return 1 if Warped int npc_touch_areanpc2(struct mob_data *md) { - int i, m = md->bl.m, x = md->bl.x, y = md->bl.y, id; + int i, m, x, y, id; char eventname[EVENT_NAME_LENGTH]; struct event_data* ev; int xs, ys; + nullpo_ret(md); + m = md->bl.m; + x = md->bl.x; + y = md->bl.y; + for( i = 0; i < map->list[m].npc_num; i++ ) { if( map->list[m].npc[i]->option&OPTION_INVISIBLE ) continue; @@ -1116,6 +1133,8 @@ int npc_check_areanpc(int flag, int16 m, int16 x, int16 y, int16 range) { int x0,y0,x1,y1; int xs,ys; + Assert_retr(1, m >= 0 && m < map->count); + if (range < 0) return 0; x0 = max(x-range, 0); y0 = max(y-range, 0); @@ -1187,6 +1206,7 @@ struct npc_data* npc_checknear(struct map_session_data* sd, struct block_list* b if (distance > nd->area_size) distance = nd->area_size; + nullpo_retr(NULL, bl); if (bl->m != sd->bl.m || bl->x < sd->bl.x - distance || bl->x > sd->bl.x + distance || bl->y < sd->bl.y - distance || bl->y > sd->bl.y + distance) @@ -1208,6 +1228,9 @@ int npc_globalmessage(const char* name, const char* mes) if (!nd) return 0; + nullpo_ret(name); + nullpo_ret(mes); + snprintf(temp, sizeof(temp), "%s : %s", name, mes); clif->GlobalMessage(&nd->bl,temp); @@ -1219,6 +1242,7 @@ void run_tomb(struct map_session_data* sd, struct npc_data* nd) { char buffer[200]; char time[10]; + nullpo_retv(nd); strftime(time, sizeof(time), "%H:%M", localtime(&nd->u.tomb.kill_time)); // TODO: Find exact color? @@ -1393,6 +1417,8 @@ int npc_cashshop_buylist(struct map_session_data *sd, int points, struct itemlis struct npc_item_list *shop = NULL; unsigned short shop_size = 0; + nullpo_retr(ERROR_TYPE_SYSTEM, sd); + nullpo_retr(ERROR_TYPE_SYSTEM, item_list); if( sd->state.trading ) return ERROR_TYPE_EXCHANGE; @@ -1492,6 +1518,9 @@ int npc_buylist_sub(struct map_session_data *sd, struct itemlist *item_list, str int key_nameid = 0; int key_amount = 0; + nullpo_ret(item_list); + nullpo_ret(nd); + // discard old contents script->cleararray_pc(sd, "@bought_nameid", (void*)0); script->cleararray_pc(sd, "@bought_quantity", (void*)0); @@ -1514,8 +1543,9 @@ int npc_buylist_sub(struct map_session_data *sd, struct itemlist *item_list, str /** * Loads persistent NPC Market Data from SQL **/ -void npc_market_fromsql(void) { - SqlStmt* stmt = SQL->StmtMalloc(map->mysql_handle); +void npc_market_fromsql(void) +{ + struct SqlStmt *stmt = SQL->StmtMalloc(map->mysql_handle); char name[NAME_LENGTH+1]; int itemid; int amount; @@ -1565,6 +1595,8 @@ void npc_market_fromsql(void) { * Saves persistent NPC Market Data into SQL **/ void npc_market_tosql(struct npc_data *nd, unsigned short index) { + nullpo_retv(nd); + Assert_retv(index < nd->u.scr.shop->items); if (SQL_ERROR == SQL->Query(map->mysql_handle, "REPLACE INTO `%s` VALUES ('%s','%d','%u')", map->npc_market_data_db, nd->exname, nd->u.scr.shop->item[index].nameid, nd->u.scr.shop->item[index].qty)) Sql_ShowDebug(map->mysql_handle); @@ -1586,12 +1618,16 @@ void npc_market_delfromsql_sub(const char *npcname, unsigned short index) { * Removes persistent NPC Market Data from SQL **/ void npc_market_delfromsql(struct npc_data *nd, unsigned short index) { + nullpo_retv(nd); + Assert_retv(index == USHRT_MAX || index < nd->u.scr.shop->items); npc->market_delfromsql_sub(nd->exname, index == USHRT_MAX ? index : nd->u.scr.shop->item[index].nameid); } /** * Judges whether to allow and spawn a trader's window. **/ bool npc_trader_open(struct map_session_data *sd, struct npc_data *nd) { + nullpo_retr(false, sd); + nullpo_retr(false, nd); if( !nd->u.scr.shop || !nd->u.scr.shop->items ) return false; @@ -1630,7 +1666,7 @@ bool npc_trader_open(struct map_session_data *sd, struct npc_data *nd) { * @param master id of the original npc **/ void npc_trader_update(int master) { - DBIterator* iter; + struct DBIterator *iter; struct block_list* bl; struct npc_data *master_nd = map->id2nd(master); @@ -1657,6 +1693,9 @@ void npc_trader_count_funds(struct npc_data *nd, struct map_session_data *sd) { char evname[EVENT_NAME_LENGTH]; struct event_data *ev = NULL; + nullpo_retv(nd); + nullpo_retv(sd); + npc->trader_funds[0] = npc->trader_funds[1] = 0;/* clear */ switch( nd->u.scr.shop->type ) { @@ -1694,6 +1733,8 @@ bool npc_trader_pay(struct npc_data *nd, struct map_session_data *sd, int price, char evname[EVENT_NAME_LENGTH]; struct event_data *ev = NULL; + nullpo_retr(false, nd); + nullpo_retr(false, sd); npc->trader_ok = false;/* clear */ snprintf(evname, EVENT_NAME_LENGTH, "%s::OnPayFunds",nd->exname); @@ -1716,6 +1757,7 @@ int npc_cashshop_buy(struct map_session_data *sd, int nameid, int amount, int po int i, price, w; unsigned short shop_size = 0; + nullpo_retr(ERROR_TYPE_SYSTEM, sd); if( amount <= 0 ) return ERROR_TYPE_ITEM_ID; @@ -2055,6 +2097,10 @@ int npc_selllist_sub(struct map_session_data *sd, struct itemlist *item_list, st int key_identify = 0; int key_card[MAX_SLOTS]; + nullpo_ret(sd); + nullpo_ret(item_list); + nullpo_ret(nd); + // discard old contents script->cleararray_pc(sd, "@sold_nameid", (void*)0); script->cleararray_pc(sd, "@sold_quantity", (void*)0); @@ -2222,7 +2268,7 @@ int npc_remove_map(struct npc_data* nd) { /** * @see DBApply */ -int npc_unload_ev(DBKey key, DBData *data, va_list ap) +int npc_unload_ev(union DBKey key, struct DBData *data, va_list ap) { struct event_data* ev = DB->data2ptr(data); char* npcname = va_arg(ap, char *); @@ -2237,7 +2283,7 @@ int npc_unload_ev(DBKey key, DBData *data, va_list ap) /** * @see DBApply */ -int npc_unload_ev_label(DBKey key, DBData *data, va_list ap) +int npc_unload_ev_label(union DBKey key, struct DBData *data, va_list ap) { struct linkdb_node **label_linkdb = DB->data2ptr(data); struct npc_data* nd = va_arg(ap, struct npc_data *); @@ -2253,6 +2299,7 @@ int npc_unload_dup_sub(struct npc_data* nd, va_list args) { int src_id; + nullpo_ret(nd); src_id = va_arg(args, int); if (nd->src_id == src_id) npc->unload(nd, true); @@ -2261,6 +2308,7 @@ int npc_unload_dup_sub(struct npc_data* nd, va_list args) //Removes all npcs that are duplicates of the passed one. [Skotlex] void npc_unload_duplicates(struct npc_data* nd) { + nullpo_retv(nd); map->foreachnpc(npc->unload_dup_sub,nd->bl.id); } @@ -2384,6 +2432,7 @@ void npc_addsrcfile(const char* name) struct npc_src_list* file; struct npc_src_list* file_prev = NULL; + nullpo_retv(name); if( strcmpi(name, "clear") == 0 ) { npc->clearsrcfile(); @@ -2415,6 +2464,7 @@ void npc_delsrcfile(const char* name) struct npc_src_list* file = npc->src_files; struct npc_src_list* file_prev = NULL; + nullpo_retv(name); if( strcmpi(name, "all") == 0 ) { npc->clearsrcfile(); @@ -2448,10 +2498,10 @@ const char *npc_retainpathreference(const char *filepath) struct npc_path_data * npd = NULL; nullpo_ret(filepath); - if (npc_last_path == filepath) { - if (npc_last_npd != NULL) - npc_last_npd->references++; - return npc_last_ref; + if (npc->npc_last_path == filepath) { + if (npc->npc_last_npd != NULL) + npc->npc_last_npd->references++; + return npc->npc_last_ref; } if ((npd = strdb_get(npc->path_db,filepath)) == NULL) { @@ -2466,9 +2516,9 @@ const char *npc_retainpathreference(const char *filepath) npd->references++; - npc_last_npd = npd; - npc_last_ref = npd->path; - npc_last_path = filepath; + npc->npc_last_npd = npd; + npc->npc_last_ref = npd->path; + npc->npc_last_path = filepath; return npd->path; } @@ -2484,7 +2534,7 @@ void npc_releasepathreference(const char *filepath) nullpo_retv(filepath); - if (filepath != npc_last_ref) { + if (filepath != npc->npc_last_ref) { npd = strdb_get(npc->path_db, filepath); } @@ -2502,6 +2552,8 @@ void npc_parsename(struct npc_data* nd, const char* name, const char* start, con struct npc_data* dnd;// duplicate npc char newname[NAME_LENGTH]; + nullpo_retv(nd); + nullpo_retv(name); // parse name p = strstr(name,"::"); if( p ) { // <Display name>::<Unique name> @@ -2557,6 +2609,7 @@ int npc_parseview(const char* w4, const char* start, const char* buffer, const c int val = FAKE_NPC, i = 0; char viewid[1024]; // Max size of name from constants.conf, see script->read_constdb. + nullpo_retr(FAKE_NPC, w4); // Extract view ID / constant while (w4[i] != '\0') { if (ISSPACE(w4[i]) || w4[i] == '/' || w4[i] == ',') @@ -2588,6 +2641,7 @@ int npc_parseview(const char* w4, const char* start, const char* buffer, const c // Checks if given view is an ID or constant. bool npc_viewisid(const char * viewid) { + nullpo_retr(false, viewid); if (atoi(viewid) != FAKE_NPC) { // Loop through view, looking for non-numeric character. while (*viewid) { @@ -2634,6 +2688,8 @@ struct npc_data* npc_add_warp(char* name, short from_mapid, short from_x, short int i, flag = 0; struct npc_data *nd; + nullpo_retr(NULL, name); + nd = npc->create_npc(WARP, from_mapid, from_x, from_y, 0, battle_config.warp_point_debug ? WARP_DEBUG_CLASS : WARP_CLASS); safestrncpy(nd->exname, name, ARRAYLENGTH(nd->exname)); @@ -2682,6 +2738,9 @@ const char *npc_parse_warp(const char *w1, const char *w2, const char *w3, const char mapname[32], to_mapname[32]; struct npc_data *nd; + nullpo_retr(strchr(start,'\n'), w1); + nullpo_retr(strchr(start,'\n'), w4); + // w1=<from map name>,<fromX>,<fromY>,<facing> // w4=<spanx>,<spany>,<to map name>,<toX>,<toY> if( sscanf(w1, "%31[^,],%d,%d", mapname, &x, &y) != 3 @@ -2715,7 +2774,7 @@ const char *npc_parse_warp(const char *w1, const char *w2, const char *w3, const nd->u.warp.y = to_y; nd->u.warp.xs = xs; nd->u.warp.ys = ys; - npc_warp++; + npc->npc_warp++; npc->add_to_location(nd); @@ -2753,6 +2812,8 @@ const char *npc_parse_shop(const char *w1, const char *w2, const char *w3, const struct npc_data *nd; enum npc_subtype type; + nullpo_retr(strchr(start,'\n'), w1); + nullpo_retr(strchr(start,'\n'), w4); if( strcmp(w1,"-") == 0 ) { // 'floating' shop x = y = dir = 0; @@ -2858,7 +2919,7 @@ const char *npc_parse_shop(const char *w1, const char *w2, const char *w3, const npc->parsename(nd, w3, start, buffer, filepath); nd->path = npc->retainpathreference(filepath); - ++npc_shop; + ++npc->npc_shop; npc->add_to_location(nd); return strchr(start,'\n');// continue @@ -2867,6 +2928,7 @@ const char *npc_parse_shop(const char *w1, const char *w2, const char *w3, const void npc_convertlabel_db(struct npc_label_list* label_list, const char *filepath) { int i; + nullpo_retv(label_list); for( i = 0; i < script->label_count; i++ ) { const char* lname = script->get_str(script->labels[i].key); int lpos = script->labels[i].pos; @@ -2993,6 +3055,7 @@ const char *npc_parse_script(const char *w1, const char *w2, const char *w3, con int label_list_num; struct npc_data* nd; + nullpo_retr(NULL, w1); if (strcmp(w1, "-") == 0) { // floating npc x = 0; @@ -3062,7 +3125,7 @@ const char *npc_parse_script(const char *w1, const char *w2, const char *w3, con if( options&NPO_TRADER ) nd->u.scr.trader = true; nd->u.scr.shop = NULL; - ++npc_script; + ++npc->npc_script; npc->add_to_location(nd); //----------------------------------------- @@ -3129,7 +3192,10 @@ bool npc_duplicate_script_sub(struct npc_data *nd, const struct npc_data *snd, i int i; bool retval = true; - ++npc_script; + nullpo_retr(false, nd); + nullpo_retr(false, snd); + + ++npc->npc_script; nd->u.scr.xs = xs; nd->u.scr.ys = ys; nd->u.scr.script = snd->u.scr.script; @@ -3173,7 +3239,10 @@ bool npc_duplicate_script_sub(struct npc_data *nd, const struct npc_data *snd, i */ bool npc_duplicate_shop_sub(struct npc_data *nd, const struct npc_data *snd, int xs, int ys, int options) { - ++npc_shop; + nullpo_retr(false, nd); + nullpo_retr(false, snd); + + ++npc->npc_shop; nd->u.shop.shop_item = snd->u.shop.shop_item; nd->u.shop.count = snd->u.shop.count; @@ -3188,7 +3257,10 @@ bool npc_duplicate_shop_sub(struct npc_data *nd, const struct npc_data *snd, int */ bool npc_duplicate_warp_sub(struct npc_data *nd, const struct npc_data *snd, int xs, int ys, int options) { - ++npc_warp; + nullpo_retr(false, nd); + nullpo_retr(false, snd); + + ++npc->npc_warp; nd->u.warp.xs = xs; nd->u.warp.ys = ys; nd->u.warp.mapindex = snd->u.warp.mapindex; @@ -3217,6 +3289,9 @@ bool npc_duplicate_warp_sub(struct npc_data *nd, const struct npc_data *snd, int */ bool npc_duplicate_sub(struct npc_data *nd, const struct npc_data *snd, int xs, int ys, int options) { + nullpo_retr(false, nd); + nullpo_retr(false, snd); + nd->src_id = snd->bl.id; switch (nd->subtype) { case SCRIPT: @@ -3282,6 +3357,8 @@ const char *npc_parse_duplicate(const char *w1, const char *w2, const char *w3, struct npc_data* dnd; end = strchr(start,'\n'); + nullpo_retr(end, w2); + nullpo_retr(end, w4); length = strlen(w2); // get the npc being duplicated @@ -3366,7 +3443,13 @@ int npc_duplicate4instance(struct npc_data *snd, int16 m) int dm = -1, im = -1, xs = -1, ys = -1; struct npc_data *nd = NULL; - if( m == -1 || map->list[m].instance_id == -1 ) + if (m == -1) + return 1; + + Assert_retr(1, m >= 0 && m < map->count); + nullpo_retr(1, snd); + + if (map->list[m].instance_id == -1) return 1; snprintf(newname, ARRAYLENGTH(newname), "dup_%d_%d", map->list[m].instance_id, snd->bl.id); @@ -3410,10 +3493,15 @@ int npc_duplicate4instance(struct npc_data *snd, int16 m) } //Set mapcell CELL_NPC to trigger event later -void npc_setcells(struct npc_data* nd) { - int16 m = nd->bl.m, x = nd->bl.x, y = nd->bl.y, xs, ys; +void npc_setcells(struct npc_data* nd) +{ + int16 m, x, y, xs, ys; int i,j; + nullpo_retv(nd); + m = nd->bl.m; + x = nd->bl.x; + y = nd->bl.y; switch(nd->subtype) { case WARP: xs = nd->u.warp.xs; @@ -3455,9 +3543,13 @@ int npc_unsetcells_sub(struct block_list *bl, va_list ap) } void npc_unsetcells(struct npc_data* nd) { - int16 m = nd->bl.m, x = nd->bl.x, y = nd->bl.y, xs, ys; + int16 m, x, y, xs, ys; int i,j, x0, x1, y0, y1; + nullpo_retv(nd); + m = nd->bl.m; + x = nd->bl.x; + y = nd->bl.y; switch(nd->subtype) { case WARP: xs = nd->u.warp.xs; @@ -3492,7 +3584,9 @@ void npc_unsetcells(struct npc_data* nd) { void npc_movenpc(struct npc_data* nd, int16 x, int16 y) { - const int16 m = nd->bl.m; + int16 m; + nullpo_retv(nd); + m = nd->bl.m; if (m < 0 || nd->bl.prev == NULL) return; //Not on a map. x = cap_value(x, 0, map->list[m].xs-1); @@ -3510,6 +3604,7 @@ void npc_movenpc(struct npc_data* nd, int16 x, int16 y) void npc_setdisplayname(struct npc_data* nd, const char* newname) { nullpo_retv(nd); + nullpo_retv(newname); safestrncpy(nd->name, newname, sizeof(nd->name)); if( map->list[nd->bl.m].users ) @@ -3544,6 +3639,7 @@ int npc_do_atcmd_event(struct map_session_data* sd, const char* command, const c size_t len; nullpo_ret(sd); + nullpo_ret(message); if( ev == NULL || (nd = ev->nd) == NULL ) { ShowError("npc_event: event not found [%s]\n", eventname); @@ -3567,7 +3663,7 @@ int npc_do_atcmd_event(struct map_session_data* sd, const char* command, const c } st = script->alloc_state(ev->nd->u.scr.script, ev->pos, sd->bl.id, ev->nd->bl.id); - script->setd_sub(st, NULL, ".@atcmd_command$", 0, (void *)command, NULL); + script->setd_sub(st, NULL, ".@atcmd_command$", 0, command, NULL); len = strlen(message); if (len) { @@ -3623,12 +3719,19 @@ int npc_do_atcmd_event(struct map_session_data* sd, const char* command, const c */ const char *npc_parse_function(const char *w1, const char *w2, const char *w3, const char *w4, const char *start, const char *buffer, const char *filepath, int *retval) { - DBMap* func_db; - DBData old_data; + struct DBMap *func_db; + struct DBData old_data; struct script_code *scriptroot; const char* end; const char* script_start; + nullpo_retr(NULL, w1); + nullpo_retr(NULL, w2); + nullpo_retr(NULL, w3); + nullpo_retr(NULL, w4); + nullpo_retr(NULL, start); + nullpo_retr(NULL, retval); + script_start = strstr(start,"\t{"); end = strchr(start,'\n'); if( *w4 != '{' || script_start == NULL || (end != NULL && script_start > end) ) { @@ -3672,6 +3775,7 @@ void npc_parse_mob2(struct spawn_data* mobspawn) { int i; + nullpo_retv(mobspawn); for( i = mobspawn->active; i < mobspawn->num; ++i ) { struct mob_data* md = mob->spawn_dataset(mobspawn); md->spawn = mobspawn; @@ -3705,6 +3809,11 @@ const char *npc_parse_mob(const char *w1, const char *w2, const char *w3, const struct spawn_data mobspawn, *data; struct mob_db* db; + nullpo_retr(strchr(start,'\n'), w1); + nullpo_retr(strchr(start,'\n'), w2); + nullpo_retr(strchr(start,'\n'), w3); + nullpo_retr(strchr(start,'\n'), w4); + memset(&mobspawn, 0, sizeof(struct spawn_data)); mobspawn.state.boss = (strcmp(w2,"boss_monster") == 0 ? 1 : 0); @@ -3847,7 +3956,7 @@ const char *npc_parse_mob(const char *w1, const char *w2, const char *w3, const // spawn / cache the new mobs if( battle_config.dynamic_mobs && map->addmobtolist(data->m, data) >= 0 ) { data->state.dynamic = true; - npc_cache_mob += data->num; + npc->npc_cache_mob += data->num; // check if target map has players // (usually shouldn't occur when map server is just starting, @@ -3858,10 +3967,10 @@ const char *npc_parse_mob(const char *w1, const char *w2, const char *w3, const } else { data->state.dynamic = false; npc->parse_mob2(data); - npc_delay_mob += data->num; + npc->npc_delay_mob += data->num; } - npc_mob++; + npc->npc_mob++; return strchr(start,'\n');// continue } @@ -3911,6 +4020,9 @@ const char *npc_parse_mapflag(const char *w1, const char *w2, const char *w3, co char mapname[32]; int state = 1; + nullpo_retr(strchr(start,'\n'), w1); + nullpo_retr(strchr(start,'\n'), w3); + // w1=<mapname> if( sscanf(w1, "%31[^,]", mapname) != 1 ) { @@ -4335,6 +4447,7 @@ const char *npc_parse_mapflag(const char *w1, const char *w2, const char *w3, co */ const char *npc_parse_unknown_object(const char *w1, const char *w2, const char *w3, const char *w4, const char *start, const char *buffer, const char *filepath, int *retval) { + nullpo_retr(start, retval); ShowError("npc_parsesrcfile: Unable to parse, probably a missing or extra TAB in file '%s', line '%d'. Skipping line...\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,start-buffer), w1, w2, w3, w4); start = strchr(start,'\n');// skip and continue *retval = EXIT_FAILURE; @@ -4359,6 +4472,8 @@ int npc_parsesrcfile(const char* filepath, bool runOnInit) { char* buffer; const char* p; + nullpo_retr(EXIT_FAILURE, filepath); + // read whole file to buffer fp = fopen(filepath, "rb"); if( fp == NULL ) { @@ -4567,11 +4682,10 @@ void npc_read_event_script(void) {"Kill NPC Event",script->config.kill_mob_event_name}, }; - for (i = 0; i < NPCE_MAX; i++) - { - DBIterator* iter; - DBKey key; - DBData *data; + for (i = 0; i < NPCE_MAX; i++) { + struct DBIterator *iter; + union DBKey key; + struct DBData *data; char name[64]="::"; safestrncpy(name+2,config[i].event_name,62); @@ -4614,9 +4728,10 @@ void npc_read_event_script(void) /** * @see DBApply */ -int npc_path_db_clear_sub(DBKey key, DBData *data, va_list args) +int npc_path_db_clear_sub(union DBKey key, struct DBData *data, va_list args) { struct npc_path_data *npd = DB->data2ptr(data); + nullpo_ret(npd); if (npd->path) aFree(npd->path); return 0; @@ -4625,7 +4740,7 @@ int npc_path_db_clear_sub(DBKey key, DBData *data, va_list args) /** * @see DBApply */ -int npc_ev_label_db_clear_sub(DBKey key, DBData *data, va_list args) +int npc_ev_label_db_clear_sub(union DBKey key, struct DBData *data, va_list args) { struct linkdb_node **label_linkdb = DB->data2ptr(data); linkdb_final(label_linkdb); // linked data (struct event_data*) is freed when clearing ev_db @@ -4652,12 +4767,12 @@ void npc_process_files( int npc_min ) { "\t-'"CL_WHITE"%d"CL_RESET"' Spawn sets\n" "\t-'"CL_WHITE"%d"CL_RESET"' Mobs Cached\n" "\t-'"CL_WHITE"%d"CL_RESET"' Mobs Not Cached\n", - npc_id - npc_min, npc_warp, npc_shop, npc_script, npc_mob, npc_cache_mob, npc_delay_mob); + npc->npc_id - npc_min, npc->npc_warp, npc->npc_shop, npc->npc_script, npc->npc_mob, npc->npc_cache_mob, npc->npc_delay_mob); } //Clear then reload npcs files int npc_reload(void) { - int npc_new_min = npc_id; + int npc_new_min = npc->npc_id; struct s_mapiterator* iter; struct block_list* bl; @@ -4673,9 +4788,9 @@ int npc_reload(void) { db_clear(npc->ev_db); npc->ev_label_db->clear(npc->ev_label_db, npc->ev_label_db_clear_sub); - npc_last_npd = NULL; - npc_last_path = NULL; - npc_last_ref = NULL; + npc->npc_last_npd = NULL; + npc->npc_last_path = NULL; + npc->npc_last_ref = NULL; //Remove all npcs/mobs. [Skotlex] iter = mapit_geteachiddb(); @@ -4715,8 +4830,8 @@ int npc_reload(void) { // clear mob spawn lookup index mob->clear_spawninfo(); - npc_warp = npc_shop = npc_script = 0; - npc_mob = npc_cache_mob = npc_delay_mob = 0; + npc->npc_warp = npc->npc_shop = npc->npc_script = 0; + npc->npc_mob = npc->npc_cache_mob = npc->npc_delay_mob = 0; // reset mapflags map->flags_init(); @@ -4754,11 +4869,14 @@ int npc_reload(void) { } //Unload all npc in the given file -bool npc_unloadfile( const char* filepath ) { - DBIterator * iter = db_iterator(npc->name_db); +bool npc_unloadfile(const char *filepath) +{ + struct DBIterator *iter = db_iterator(npc->name_db); struct npc_data* nd = NULL; bool found = false; + nullpo_retr(false, filepath); + for( nd = dbi_first(iter); dbi_exists(iter); nd = dbi_next(iter) ) { if( nd->path && strcasecmp(nd->path,filepath) == 0 ) { // FIXME: This can break in case-sensitive file systems found = true; @@ -4797,6 +4915,9 @@ int do_final_npc(void) { void npc_debug_warps_sub(struct npc_data* nd) { int16 m; + + nullpo_retv(nd); + if (nd->bl.type != BL_NPC || nd->subtype != WARP || nd->bl.m < 0) return; @@ -4833,14 +4954,8 @@ static void npc_debug_warps(void) { int do_init_npc(bool minimal) { int i; - memset(&npc->base_ud, 0, sizeof( struct unit_data) ); - npc->base_ud.bl = NULL; - npc->base_ud.walktimer = INVALID_TIMER; - npc->base_ud.skilltimer = INVALID_TIMER; - npc->base_ud.attacktimer = INVALID_TIMER; - npc->base_ud.attackabletime = - npc->base_ud.canact_tick = - npc->base_ud.canmove_tick = timer->gettick(); + unit->init_ud(&npc->base_ud); + npc->base_ud.bl = NULL; //Stock view data for normal npcs. memset(&npc_viewdb, 0, sizeof(npc_viewdb)); @@ -4856,9 +4971,9 @@ int do_init_npc(bool minimal) { npc->name_db = strdb_alloc(DB_OPT_BASE, NAME_LENGTH); npc->path_db = strdb_alloc(DB_OPT_DUP_KEY|DB_OPT_RELEASE_DATA, 0); - npc_last_npd = NULL; - npc_last_path = NULL; - npc_last_ref = NULL; + npc->npc_last_npd = NULL; + npc->npc_last_path = NULL; + npc->npc_last_ref = NULL; // Should be loaded before npc processing, otherwise labels could overwrite constant values // and lead to undefined behavior [Panikon] @@ -4902,7 +5017,7 @@ int do_init_npc(bool minimal) { strcpy(npc->fake_nd->name,"FAKE_NPC"); memcpy(npc->fake_nd->exname, npc->fake_nd->name, 9); - npc_script++; + npc->npc_script++; npc->fake_nd->bl.type = BL_NPC; npc->fake_nd->subtype = SCRIPT; @@ -4916,6 +5031,17 @@ int do_init_npc(bool minimal) { void npc_defaults(void) { npc = &npc_s; + npc->npc_id = START_NPC_NUM; + npc->npc_warp = 0; + npc->npc_shop = 0; + npc->npc_script = 0; + npc->npc_mob = 0; + npc->npc_delay_mob = 0; + npc->npc_cache_mob = 0; + npc->npc_last_path = NULL; + npc->npc_last_ref = NULL; + npc->npc_last_npd = NULL; + npc->motd = NULL; npc->ev_db = NULL; npc->ev_label_db = NULL; diff --git a/src/map/npc.h b/src/map/npc.h index 965a34f94..24ea9ea59 100644 --- a/src/map/npc.h +++ b/src/map/npc.h @@ -177,10 +177,10 @@ struct npc_path_data { struct npc_interface { /* */ struct npc_data *motd; - DBMap *ev_db; // const char* event_name -> struct event_data* - DBMap *ev_label_db; // const char* label_name (without leading "::") -> struct linkdb_node** (key: struct npc_data*; data: struct event_data*) - DBMap *name_db; // const char* npc_name -> struct npc_data* - DBMap *path_db; + struct DBMap *ev_db; // const char* event_name -> struct event_data* + struct DBMap *ev_label_db; // const char* label_name (without leading "::") -> struct linkdb_node** (key: struct npc_data*; data: struct event_data*) + struct DBMap *name_db; // const char* npc_name -> struct npc_data* + struct DBMap *path_db; struct eri *timer_event_ers; //For the npc timer data. [Skotlex] struct npc_data *fake_nd; struct npc_src_list *src_files; @@ -188,6 +188,16 @@ struct npc_interface { /* npc trader global data, for ease of transition between the script, cleared on every usage */ bool trader_ok; int trader_funds[2]; + int npc_id; + int npc_warp; + int npc_shop; + int npc_script; + int npc_mob; + int npc_delay_mob; + int npc_cache_mob; + const char *npc_last_path; + const char *npc_last_ref; + struct npc_path_data *npc_last_npd; /* */ int (*init) (bool minimal); int (*final) (void); @@ -203,7 +213,7 @@ struct npc_interface { int (*enable) (const char *name, int flag); struct npc_data* (*name2id) (const char *name); int (*event_dequeue) (struct map_session_data *sd); - DBData (*event_export_create) (DBKey key, va_list args); + struct DBData (*event_export_create) (union DBKey key, va_list args); int (*event_export) (struct npc_data *nd, int i); int (*event_sub) (struct map_session_data *sd, struct event_data *ev, const char *eventname); void (*event_doall_sub) (void *key, void *data, va_list ap); @@ -239,8 +249,8 @@ struct npc_interface { int (*selllist_sub) (struct map_session_data *sd, struct itemlist *item_list, struct npc_data *nd); int (*selllist) (struct map_session_data *sd, struct itemlist *item_list); int (*remove_map) (struct npc_data *nd); - int (*unload_ev) (DBKey key, DBData *data, va_list ap); - int (*unload_ev_label) (DBKey key, DBData *data, va_list ap); + int (*unload_ev) (union DBKey key, struct DBData *data, va_list ap); + int (*unload_ev_label) (union DBKey key, struct DBData *data, va_list ap); int (*unload_dup_sub) (struct npc_data *nd, va_list args); void (*unload_duplicates) (struct npc_data *nd); int (*unload) (struct npc_data *nd, bool single); @@ -282,8 +292,8 @@ struct npc_interface { int (*parsesrcfile) (const char *filepath, bool runOnInit); int (*script_event) (struct map_session_data *sd, enum npce_event type); void (*read_event_script) (void); - int (*path_db_clear_sub) (DBKey key, DBData *data, va_list args); - int (*ev_label_db_clear_sub) (DBKey key, DBData *data, va_list args); + int (*path_db_clear_sub) (union DBKey key, struct DBData *data, va_list args); + int (*ev_label_db_clear_sub) (union DBKey key, struct DBData *data, va_list args); int (*reload) (void); bool (*unloadfile) (const char *filepath); void (*do_clear_npc) (void); diff --git a/src/map/packets_struct.h b/src/map/packets_struct.h index f23cefb26..e461eebe9 100644 --- a/src/map/packets_struct.h +++ b/src/map/packets_struct.h @@ -2,7 +2,7 @@ * This file is part of Hercules. * http://herc.ws - http://github.com/HerculesWS/Hercules * - * Copyright (C) 2013-2015 Hercules Dev Team + * Copyright (C) 2013-2016 Hercules Dev Team * * Hercules is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,6 +26,11 @@ #include "common/cbasetypes.h" #include "common/mmo.h" +// Packet DB +#define MIN_PACKET_DB 0x0064 +#define MAX_PACKET_DB 0x0F00 +#define MAX_PACKET_POS 20 + /** * **/ @@ -307,134 +312,134 @@ enum packet_headers { * structs for data */ struct EQUIPSLOTINFO { - unsigned short card[4]; + uint16 card[4]; } __attribute__((packed)); struct NORMALITEM_INFO { - short index; - unsigned short ITID; - unsigned char type; + int16 index; + uint16 ITID; + uint8 type; #if PACKETVER < 20120925 uint8 IsIdentified; #endif - short count; + int16 count; #if PACKETVER >= 20120925 - unsigned int WearState; + uint32 WearState; #else - unsigned short WearState; + uint16 WearState; #endif #if PACKETVER >= 5 struct EQUIPSLOTINFO slot; #endif #if PACKETVER >= 20080102 - int HireExpireDate; + int32 HireExpireDate; #endif #if PACKETVER >= 20120925 struct { - unsigned char IsIdentified : 1; - unsigned char PlaceETCTab : 1; - unsigned char SpareBits : 6; + uint8 IsIdentified : 1; + uint8 PlaceETCTab : 1; + uint8 SpareBits : 6; } Flag; #endif } __attribute__((packed)); struct RndOptions { - short index; - short value; - unsigned char param; + int16 index; + int16 value; + uint8 param; } __attribute__((packed)); struct EQUIPITEM_INFO { - short index; - unsigned short ITID; - unsigned char type; + int16 index; + uint16 ITID; + uint8 type; #if PACKETVER < 20120925 uint8 IsIdentified; #endif #if PACKETVER >= 20120925 - unsigned int location; - unsigned int WearState; + uint32 location; + uint32 WearState; #else - unsigned short location; - unsigned short WearState; + uint16 location; + uint16 WearState; #endif #if PACKETVER < 20120925 uint8 IsDamaged; #endif - unsigned char RefiningLevel; + uint8 RefiningLevel; struct EQUIPSLOTINFO slot; #if PACKETVER >= 20071002 - int HireExpireDate; + int32 HireExpireDate; #endif #if PACKETVER >= 20080102 - unsigned short bindOnEquipType; + uint16 bindOnEquipType; #endif #if PACKETVER >= 20100629 - unsigned short wItemSpriteNumber; + uint16 wItemSpriteNumber; #endif #if PACKETVER >= 20150226 - unsigned char option_count; + uint8 option_count; struct RndOptions option_data[5]; #endif #if PACKETVER >= 20120925 struct { - unsigned char IsIdentified : 1; - unsigned char IsDamaged : 1; - unsigned char PlaceETCTab : 1; - unsigned char SpareBits : 5; + uint8 IsIdentified : 1; + uint8 IsDamaged : 1; + uint8 PlaceETCTab : 1; + uint8 SpareBits : 5; } Flag; #endif } __attribute__((packed)); struct packet_authok { - short PacketType; - unsigned int startTime; - unsigned char PosDir[3]; - unsigned char xSize; - unsigned char ySize; + int16 PacketType; + uint32 startTime; + uint8 PosDir[3]; + uint8 xSize; + uint8 ySize; #if PACKETVER >= 20080102 - short font; + int16 font; #endif #if PACKETVER >= 20141022 - unsigned char sex; + uint8 sex; #endif } __attribute__((packed)); struct packet_monster_hp { - short PacketType; - unsigned int GID; - int HP; - int MaxHP; + int16 PacketType; + uint32 GID; + int32 HP; + int32 MaxHP; } __attribute__((packed)); struct packet_sc_notick { - short PacketType; - short index; - unsigned int AID; - unsigned char state; + int16 PacketType; + int16 index; + uint32 AID; + uint8 state; } __attribute__((packed)); struct packet_additem { - short PacketType; - unsigned short Index; - unsigned short count; - unsigned short nameid; + int16 PacketType; + uint16 Index; + uint16 count; + uint16 nameid; uint8 IsIdentified; uint8 IsDamaged; - unsigned char refiningLevel; + uint8 refiningLevel; struct EQUIPSLOTINFO slot; #if PACKETVER >= 20120925 - unsigned int location; + uint32 location; #else - unsigned short location; + uint16 location; #endif - unsigned char type; - unsigned char result; + uint8 type; + uint8 result; #if PACKETVER >= 20061218 - int HireExpireDate; + int32 HireExpireDate; #endif #if PACKETVER >= 20071002 - unsigned short bindOnEquipType; + uint16 bindOnEquipType; #endif #if PACKETVER >= 20150226 struct RndOptions option_data[5]; @@ -442,51 +447,51 @@ struct packet_additem { } __attribute__((packed)); struct packet_dropflooritem { - short PacketType; - unsigned int ITAID; - unsigned short ITID; + int16 PacketType; + uint32 ITAID; + uint16 ITID; #if PACKETVER >= 20130000 /* not sure date */ - unsigned short type; + uint16 type; #endif uint8 IsIdentified; - short xPos; - short yPos; - unsigned char subX; - unsigned char subY; - short count; + int16 xPos; + int16 yPos; + uint8 subX; + uint8 subY; + int16 count; } __attribute__((packed)); struct packet_idle_unit2 { #if PACKETVER < 20091103 - short PacketType; + int16 PacketType; #if PACKETVER >= 20071106 - unsigned char objecttype; -#endif - unsigned int GID; - short speed; - short bodyState; - short healthState; - short effectState; - short job; - short head; - short weapon; - short accessory; - short shield; - short accessory2; - short accessory3; - short headpalette; - short bodypalette; - short headDir; - unsigned int GUID; - short GEmblemVer; - short honor; - short virtue; + uint8 objecttype; +#endif + uint32 GID; + int16 speed; + int16 bodyState; + int16 healthState; + int16 effectState; + int16 job; + int16 head; + int16 weapon; + int16 accessory; + int16 shield; + int16 accessory2; + int16 accessory3; + int16 headpalette; + int16 bodypalette; + int16 headDir; + uint32 GUID; + int16 GEmblemVer; + int16 honor; + int16 virtue; uint8 isPKModeON; - unsigned char sex; - unsigned char PosDir[3]; - unsigned char xSize; - unsigned char ySize; - unsigned char state; - short clevel; + uint8 sex; + uint8 PosDir[3]; + uint8 xSize; + uint8 ySize; + uint8 state; + int16 clevel; #else // ! PACKETVER < 20091103 UNAVAILABLE_STRUCT; #endif // PACKETVER < 20091103 @@ -494,470 +499,473 @@ struct packet_idle_unit2 { struct packet_spawn_unit2 { #if PACKETVER < 20091103 - short PacketType; + int16 PacketType; #if PACKETVER >= 20071106 - unsigned char objecttype; -#endif - unsigned int GID; - short speed; - short bodyState; - short healthState; - short effectState; - short head; - short weapon; - short accessory; - short job; - short shield; - short accessory2; - short accessory3; - short headpalette; - short bodypalette; - short headDir; + uint8 objecttype; +#endif + uint32 GID; + int16 speed; + int16 bodyState; + int16 healthState; + int16 effectState; + int16 head; + int16 weapon; + int16 accessory; + int16 job; + int16 shield; + int16 accessory2; + int16 accessory3; + int16 headpalette; + int16 bodypalette; + int16 headDir; uint8 isPKModeON; - unsigned char sex; - unsigned char PosDir[3]; - unsigned char xSize; - unsigned char ySize; + uint8 sex; + uint8 PosDir[3]; + uint8 xSize; + uint8 ySize; #else // ! PACKETVER < 20091103 UNAVAILABLE_STRUCT; #endif // PACKETVER < 20091103 } __attribute__((packed)); struct packet_spawn_unit { - short PacketType; + int16 PacketType; #if PACKETVER >= 20091103 - short PacketLength; - unsigned char objecttype; + int16 PacketLength; + uint8 objecttype; #endif #if PACKETVER >= 20131223 - unsigned int AID; + uint32 AID; #endif - unsigned int GID; - short speed; - short bodyState; - short healthState; + uint32 GID; + int16 speed; + int16 bodyState; + int16 healthState; #if PACKETVER < 20080102 - short effectState; + int16 effectState; #else - int effectState; + int32 effectState; #endif - short job; - short head; + int16 job; + int16 head; #if PACKETVER < 7 - short weapon; + int16 weapon; #else - int weapon; + int32 weapon; #endif - short accessory; + int16 accessory; #if PACKETVER < 7 - short shield; + int16 shield; #endif - short accessory2; - short accessory3; - short headpalette; - short bodypalette; - short headDir; + int16 accessory2; + int16 accessory3; + int16 headpalette; + int16 bodypalette; + int16 headDir; #if PACKETVER >= 20101124 - short robe; + int16 robe; #endif - unsigned int GUID; - short GEmblemVer; - short honor; + uint32 GUID; + int16 GEmblemVer; + int16 honor; #if PACKETVER > 7 - int virtue; + int32 virtue; #else - short virtue; + int16 virtue; #endif uint8 isPKModeON; - unsigned char sex; - unsigned char PosDir[3]; - unsigned char xSize; - unsigned char ySize; - short clevel; + uint8 sex; + uint8 PosDir[3]; + uint8 xSize; + uint8 ySize; + int16 clevel; #if PACKETVER >= 20080102 - short font; + int16 font; #endif #if PACKETVER >= 20120221 - int maxHP; - int HP; - unsigned char isBoss; + int32 maxHP; + int32 HP; + uint8 isBoss; #endif #if PACKETVER >= 20150513 - short body; + int16 body; + char name[NAME_LENGTH]; #endif } __attribute__((packed)); struct packet_unit_walking { - short PacketType; + int16 PacketType; #if PACKETVER >= 20091103 - short PacketLength; + int16 PacketLength; #endif #if PACKETVER > 20071106 - unsigned char objecttype; + uint8 objecttype; #endif #if PACKETVER >= 20131223 - unsigned int AID; + uint32 AID; #endif - unsigned int GID; - short speed; - short bodyState; - short healthState; + uint32 GID; + int16 speed; + int16 bodyState; + int16 healthState; #if PACKETVER < 7 - short effectState; + int16 effectState; #else - int effectState; + int32 effectState; #endif - short job; - short head; + int16 job; + int16 head; #if PACKETVER < 7 - short weapon; + int16 weapon; #else - int weapon; + int32 weapon; #endif - short accessory; - unsigned int moveStartTime; + int16 accessory; + uint32 moveStartTime; #if PACKETVER < 7 - short shield; + int16 shield; #endif - short accessory2; - short accessory3; - short headpalette; - short bodypalette; - short headDir; + int16 accessory2; + int16 accessory3; + int16 headpalette; + int16 bodypalette; + int16 headDir; #if PACKETVER >= 20101124 - short robe; + int16 robe; #endif - unsigned int GUID; - short GEmblemVer; - short honor; + uint32 GUID; + int16 GEmblemVer; + int16 honor; #if PACKETVER > 7 - int virtue; + int32 virtue; #else - short virtue; + int16 virtue; #endif uint8 isPKModeON; - unsigned char sex; - unsigned char MoveData[6]; - unsigned char xSize; - unsigned char ySize; - short clevel; + uint8 sex; + uint8 MoveData[6]; + uint8 xSize; + uint8 ySize; + int16 clevel; #if PACKETVER >= 20080102 - short font; + int16 font; #endif #if PACKETVER >= 20120221 - int maxHP; - int HP; - unsigned char isBoss; + int32 maxHP; + int32 HP; + uint8 isBoss; #endif #if PACKETVER >= 20150513 - short body; + int16 body; + char name[NAME_LENGTH]; #endif } __attribute__((packed)); struct packet_idle_unit { - short PacketType; + int16 PacketType; #if PACKETVER >= 20091103 - short PacketLength; - unsigned char objecttype; + int16 PacketLength; + uint8 objecttype; #endif #if PACKETVER >= 20131223 - unsigned int AID; + uint32 AID; #endif - unsigned int GID; - short speed; - short bodyState; - short healthState; + uint32 GID; + int16 speed; + int16 bodyState; + int16 healthState; #if PACKETVER < 20080102 - short effectState; + int16 effectState; #else - int effectState; + int32 effectState; #endif - short job; - short head; + int16 job; + int16 head; #if PACKETVER < 7 - short weapon; + int16 weapon; #else - int weapon; + int32 weapon; #endif - short accessory; + int16 accessory; #if PACKETVER < 7 - short shield; + int16 shield; #endif - short accessory2; - short accessory3; - short headpalette; - short bodypalette; - short headDir; + int16 accessory2; + int16 accessory3; + int16 headpalette; + int16 bodypalette; + int16 headDir; #if PACKETVER >= 20101124 - short robe; + int16 robe; #endif - unsigned int GUID; - short GEmblemVer; - short honor; + uint32 GUID; + int16 GEmblemVer; + int16 honor; #if PACKETVER > 7 - int virtue; + int32 virtue; #else - short virtue; + int16 virtue; #endif uint8 isPKModeON; - unsigned char sex; - unsigned char PosDir[3]; - unsigned char xSize; - unsigned char ySize; - unsigned char state; - short clevel; + uint8 sex; + uint8 PosDir[3]; + uint8 xSize; + uint8 ySize; + uint8 state; + int16 clevel; #if PACKETVER >= 20080102 - short font; + int16 font; #endif #if PACKETVER >= 20120221 - int maxHP; - int HP; - unsigned char isBoss; + int32 maxHP; + int32 HP; + uint8 isBoss; #endif #if PACKETVER >= 20150513 - short body; + int16 body; + char name[NAME_LENGTH]; #endif } __attribute__((packed)); struct packet_status_change { - short PacketType; - short index; - unsigned int AID; - unsigned char state; + int16 PacketType; + int16 index; + uint32 AID; + uint8 state; #if PACKETVER >= 20120618 - unsigned int Total; + uint32 Total; #endif #if PACKETVER >= 20090121 - unsigned int Left; - int val1; - int val2; - int val3; + uint32 Left; + int32 val1; + int32 val2; + int32 val3; #endif } __attribute__((packed)); struct packet_status_change_end { - short PacketType; - short index; - unsigned int AID; - unsigned char state; + int16 PacketType; + int16 index; + uint32 AID; + uint8 state; } __attribute__((packed)); struct packet_status_change2 { - short PacketType; - short index; - unsigned int AID; - unsigned char state; - unsigned int Left; - int val1; - int val2; - int val3; + int16 PacketType; + int16 index; + uint32 AID; + uint8 state; + uint32 Left; + int32 val1; + int32 val2; + int32 val3; } __attribute__((packed)); struct packet_maptypeproperty2 { - short PacketType; - short type; + int16 PacketType; + int16 type; struct { - unsigned int party : 1; // Show attack cursor on non-party members (PvP) - unsigned int guild : 1; // Show attack cursor on non-guild members (GvG) - unsigned int siege : 1; // Show emblem over characters' heads when in GvG (WoE castle) - unsigned int mineffect : 1; // Automatically enable /mineffect - unsigned int nolockon : 1; // TODO: What does this do? (shows attack cursor on non-party members) - unsigned int countpk : 1; /// Show the PvP counter - unsigned int nopartyformation : 1; /// Prevent party creation/modification - unsigned int bg : 1; // TODO: What does this do? Probably related to Battlegrounds, but I'm not sure on the effect - unsigned int nocostume : 1; /// Does not show costume sprite. - unsigned int usecart : 1; /// Allow opening cart inventory - unsigned int summonstarmiracle : 1; // TODO: What does this do? Related to Taekwon Masters, but I have no idea. - unsigned int SpareBits : 15; /// Currently ignored, reserved for future updates + uint32 party : 1; // Show attack cursor on non-party members (PvP) + uint32 guild : 1; // Show attack cursor on non-guild members (GvG) + uint32 siege : 1; // Show emblem over characters' heads when in GvG (WoE castle) + uint32 mineffect : 1; // Automatically enable /mineffect + uint32 nolockon : 1; // TODO: What does this do? (shows attack cursor on non-party members) + uint32 countpk : 1; /// Show the PvP counter + uint32 nopartyformation : 1; /// Prevent party creation/modification + uint32 bg : 1; // TODO: What does this do? Probably related to Battlegrounds, but I'm not sure on the effect + uint32 nocostume : 1; /// Does not show costume sprite. + uint32 usecart : 1; /// Allow opening cart inventory + uint32 summonstarmiracle : 1; // TODO: What does this do? Related to Taekwon Masters, but I have no idea. + uint32 SpareBits : 15; /// Currently ignored, reserved for future updates } flag; } __attribute__((packed)); struct packet_bgqueue_ack { - short PacketType; - unsigned char type; + int16 PacketType; + uint8 type; char bg_name[NAME_LENGTH]; } __attribute__((packed)); struct packet_bgqueue_notice_delete { - short PacketType; - unsigned char type; + int16 PacketType; + uint8 type; char bg_name[NAME_LENGTH]; } __attribute__((packed)); struct packet_bgqueue_register { - short PacketType; - short type; + int16 PacketType; + int16 type; char bg_name[NAME_LENGTH]; } __attribute__((packed)); struct packet_bgqueue_update_info { - short PacketType; + int16 PacketType; char bg_name[NAME_LENGTH]; - int position; + int32 position; } __attribute__((packed)); struct packet_bgqueue_checkstate { - short PacketType; + int16 PacketType; char bg_name[NAME_LENGTH]; } __attribute__((packed)); struct packet_bgqueue_revoke_req { - short PacketType; + int16 PacketType; char bg_name[NAME_LENGTH]; } __attribute__((packed)); struct packet_bgqueue_battlebegin_ack { - short PacketType; - unsigned char result; + int16 PacketType; + uint8 result; char bg_name[NAME_LENGTH]; char game_name[NAME_LENGTH]; } __attribute__((packed)); struct packet_bgqueue_notify_entry { - short PacketType; + int16 PacketType; char name[NAME_LENGTH]; - int position; + int32 position; } __attribute__((packed)); struct packet_bgqueue_battlebegins { - short PacketType; + int16 PacketType; char bg_name[NAME_LENGTH]; char game_name[NAME_LENGTH]; } __attribute__((packed)); struct packet_script_clear { - short PacketType; - unsigned int NpcID; + int16 PacketType; + uint32 NpcID; } __attribute__((packed)); /* made possible thanks to Yommy!! */ struct packet_package_item_announce { - short PacketType; - short PacketLength; - unsigned char type; - unsigned short ItemID; - char len; + int16 PacketType; + int16 PacketLength; + uint8 type; + uint16 ItemID; + int8 len; char Name[NAME_LENGTH]; - char unknown; - unsigned short BoxItemID; + int8 unknown; + uint16 BoxItemID; } __attribute__((packed)); /* made possible thanks to Yommy!! */ struct packet_item_drop_announce { - short PacketType; - short PacketLength; - unsigned char type; - unsigned short ItemID; - char len; + int16 PacketType; + int16 PacketLength; + uint8 type; + uint16 ItemID; + int8 len; char Name[NAME_LENGTH]; char monsterNameLen; char monsterName[NAME_LENGTH]; } __attribute__((packed)); struct packet_cart_additem_ack { - short PacketType; - char result; + int16 PacketType; + int8 result; } __attribute__((packed)); struct packet_banking_check { - short PacketType; + int16 PacketType; int64 Money; - short Reason; + int16 Reason; } __attribute__((packed)); struct packet_banking_deposit_req { - short PacketType; - unsigned int AID; - int Money; + int16 PacketType; + uint32 AID; + int32 Money; } __attribute__((packed)); struct packet_banking_withdraw_req { - short PacketType; - unsigned int AID; - int Money; + int16 PacketType; + uint32 AID; + int32 Money; } __attribute__((packed)); struct packet_banking_deposit_ack { - short PacketType; - short Reason; + int16 PacketType; + int16 Reason; int64 Money; - int Balance; + int32 Balance; } __attribute__((packed)); struct packet_banking_withdraw_ack { - short PacketType; - short Reason; + int16 PacketType; + int16 Reason; int64 Money; - int Balance; + int32 Balance; } __attribute__((packed)); /* Roulette System [Yommy/Hercules] */ struct packet_roulette_open_ack { - short PacketType; - char Result; - int Serial; - char Step; - char Idx; - short AdditionItemID; - int GoldPoint; - int SilverPoint; - int BronzePoint; + int16 PacketType; + int8 Result; + int32 Serial; + int8 Step; + int8 Idx; + int16 AdditionItemID; + int32 GoldPoint; + int32 SilverPoint; + int32 BronzePoint; } __attribute__((packed)); struct packet_roulette_info_ack { - short PacketType; - short PacketLength; - unsigned int RouletteSerial; + int16 PacketType; + int16 PacketLength; + uint32 RouletteSerial; struct { - unsigned short Row; - unsigned short Position; - unsigned short ItemId; - unsigned short Count; + uint16 Row; + uint16 Position; + uint16 ItemId; + uint16 Count; } ItemInfo[42]; } __attribute__((packed)); struct packet_roulette_close_ack { - short PacketType; - unsigned char Result; + int16 PacketType; + uint8 Result; } __attribute__((packed)); struct packet_roulette_generate_ack { - short PacketType; - unsigned char Result; - unsigned short Step; - unsigned short Idx; - unsigned short AdditionItemID; - int RemainGold; - int RemainSilver; - int RemainBronze; + int16 PacketType; + uint8 Result; + uint16 Step; + uint16 Idx; + uint16 AdditionItemID; + int32 RemainGold; + int32 RemainSilver; + int32 RemainBronze; } __attribute__((packed)); struct packet_roulette_itemrecv_req { - short PacketType; - unsigned char Condition; + int16 PacketType; + uint8 Condition; } __attribute__((packed)); struct packet_roulette_itemrecv_ack { - short PacketType; - unsigned char Result; - unsigned short AdditionItemID; + int16 PacketType; + uint8 Result; + uint16 AdditionItemID; } __attribute__((packed)); struct packet_itemlist_normal { - short PacketType; - short PacketLength; + int16 PacketType; + int16 PacketLength; struct NORMALITEM_INFO list[MAX_ITEMLIST]; } __attribute__((packed)); struct packet_itemlist_equip { - short PacketType; - short PacketLength; + int16 PacketType; + int16 PacketLength; struct EQUIPITEM_INFO list[MAX_ITEMLIST]; } __attribute__((packed)); struct packet_storelist_normal { - short PacketType; - short PacketLength; + int16 PacketType; + int16 PacketLength; #if PACKETVER >= 20120925 char name[NAME_LENGTH]; #endif @@ -965,8 +973,8 @@ struct packet_storelist_normal { } __attribute__((packed)); struct packet_storelist_equip { - short PacketType; - short PacketLength; + int16 PacketType; + int16 PacketLength; #if PACKETVER >= 20120925 char name[NAME_LENGTH]; #endif @@ -974,124 +982,124 @@ struct packet_storelist_equip { } __attribute__((packed)); struct packet_equip_item { - short PacketType; - unsigned short index; + int16 PacketType; + uint16 index; #if PACKETVER >= 20120925 - unsigned int wearLocation; + uint32 wearLocation; #else - unsigned short wearLocation; + uint16 wearLocation; #endif } __attribute__((packed)); struct packet_equipitem_ack { - short PacketType; - unsigned short index; + int16 PacketType; + uint16 index; #if PACKETVER >= 20120925 - unsigned int wearLocation; + uint32 wearLocation; #else - unsigned short wearLocation; + uint16 wearLocation; #endif #if PACKETVER >= 20100629 - unsigned short wItemSpriteNumber; + uint16 wItemSpriteNumber; #endif - unsigned char result; + uint8 result; } __attribute__((packed)); struct packet_unequipitem_ack { - short PacketType; - unsigned short index; + int16 PacketType; + uint16 index; #if PACKETVER >= 20120925 - unsigned int wearLocation; + uint32 wearLocation; #else - unsigned short wearLocation; + uint16 wearLocation; #endif - unsigned char result; + uint8 result; } __attribute__((packed)); struct packet_viewequip_ack { - short PacketType; - short PacketLength; + int16 PacketType; + int16 PacketLength; char characterName[NAME_LENGTH]; - short job; - short head; - short accessory; - short accessory2; - short accessory3; + int16 job; + int16 head; + int16 accessory; + int16 accessory2; + int16 accessory3; #if PACKETVER >= 20101124 - short robe; + int16 robe; #endif - short headpalette; - short bodypalette; - unsigned char sex; + int16 headpalette; + int16 bodypalette; + uint8 sex; struct EQUIPITEM_INFO list[MAX_INVENTORY]; } __attribute__((packed)); struct packet_notify_bounditem { - short PacketType; - unsigned short index; + int16 PacketType; + uint16 index; } __attribute__((packed)); struct packet_skill_entry { - short PacketType; + int16 PacketType; #if PACKETVER >= 20110718 - short PacketLength; + int16 PacketLength; #endif - unsigned int AID; - unsigned int creatorAID; - short xPos; - short yPos; + uint32 AID; + uint32 creatorAID; + int16 xPos; + int16 yPos; #if PACKETVER >= 20121212 - int job; + int32 job; #else - unsigned char job; + uint8 job; #endif #if PACKETVER >= 20110718 - char RadiusRange; + int8 RadiusRange; #endif - unsigned char isVisible; + uint8 isVisible; #if PACKETVER >= 20130731 - unsigned char level; + uint8 level; #endif } __attribute__((packed)); struct packet_graffiti_entry { - short PacketType; - unsigned int AID; - unsigned int creatorAID; - short xPos; - short yPos; - unsigned char job; - unsigned char isVisible; - unsigned char isContens; + int16 PacketType; + uint32 AID; + uint32 creatorAID; + int16 xPos; + int16 yPos; + uint8 job; + uint8 isVisible; + uint8 isContens; char msg[80]; } __attribute__((packed)); struct packet_damage { - short PacketType; - unsigned int GID; - unsigned int targetGID; - unsigned int startTime; - int attackMT; - int attackedMT; + int16 PacketType; + uint32 GID; + uint32 targetGID; + uint32 startTime; + int32 attackMT; + int32 attackedMT; #if PACKETVER < 20071113 - short damage; + int16 damage; #else - int damage; + int32 damage; #endif #if PACKETVER >= 20131223 - unsigned char is_sp_damaged; + uint8 is_sp_damaged; #endif - short count; - unsigned char action; + int16 count; + uint8 action; #if PACKETVER < 20071113 - short leftDamage; + int16 leftDamage; #else - int leftDamage; + int32 leftDamage; #endif } __attribute__((packed)); struct packet_gm_monster_item { - short PacketType; + int16 PacketType; #if PACKETVER >= 20131218 char str[100]; #else @@ -1100,35 +1108,35 @@ struct packet_gm_monster_item { } __attribute__((packed)); struct packet_npc_market_purchase { - short PacketType; - short PacketLength; + int16 PacketType; + int16 PacketLength; struct { - unsigned short ITID; - int qty; + uint16 ITID; + int32 qty; } list[]; // Note: We assume this should be <= MAX_INVENTORY (since you can't hold more than MAX_INVENTORY items thus cant buy that many at once). } __attribute__((packed)); struct packet_npc_market_result_ack { - short PacketType; - short PacketLength; - unsigned char result; + int16 PacketType; + int16 PacketLength; + uint8 result; struct { - unsigned short ITID; - unsigned short qty; - unsigned int price; + uint16 ITID; + uint16 qty; + uint32 price; } list[MAX_INVENTORY];/* assuming MAX_INVENTORY is max since you can't hold more than MAX_INVENTORY items thus cant buy that many at once. */ } __attribute__((packed)); struct packet_npc_market_open { - short PacketType; - short PacketLength; + int16 PacketType; + int16 PacketLength; /* inner struct figured by Ind after some annoying hour of debugging (data Thanks to Yommy) */ struct { - unsigned short nameid; - unsigned char type; - unsigned int price; - unsigned int qty; - unsigned short view; + uint16 nameid; + uint8 type; + uint32 price; + uint32 qty; + uint16 view; // It seems that the client doesn't have any hard-coded limit for this list // it's possible to send up to 1890 items without dropping a packet that's // too large [Panikon] @@ -1136,30 +1144,30 @@ struct packet_npc_market_open { } __attribute__((packed)); struct packet_wis_end { - short PacketType; - char result; + int16 PacketType; + int8 result; #if PACKETVER >= 20131223 - unsigned int unknown;/* maybe AID, not sure what for (works sending as 0) */ + uint32 unknown;/* maybe AID, not sure what for (works sending as 0) */ #endif } __attribute__((packed)); struct packet_party_leader_changed { - short PacketType; - unsigned int prev_leader_aid; - unsigned int new_leader_aid; + int16 PacketType; + uint32 prev_leader_aid; + uint32 new_leader_aid; } __attribute__((packed)); struct packet_hotkey { #ifdef HOTKEY_SAVING - short PacketType; + int16 PacketType; #if PACKETVER >= 20141022 - char Rotate; + int8 Rotate; #endif struct { - char isSkill; // 0: Item, 1:Skill - unsigned int ID; // Item/Skill ID - short count; // Item Quantity/Skill Level + int8 isSkill; // 0: Item, 1:Skill + uint32 ID; // Item/Skill ID + int16 count; // Item Quantity/Skill Level } hotkey[MAX_HOTKEYS]; #else // not HOTKEY_SAVING UNAVAILABLE_STRUCT; @@ -1207,6 +1215,19 @@ struct packet_quest_list_header { //struct packet_quest_list_info list[]; // Variable-length } __attribute__((packed)); +struct packet_chat_message { + uint16 packet_id; + int16 packet_len; + char message[]; +} __attribute__((packed)); + +struct packet_whisper_message { + uint16 packet_id; + int16 packet_len; + char name[NAME_LENGTH]; + char message[]; +} __attribute__((packed)); + #if !defined(sun) && (!defined(__NETBSD__) || __NetBSD_Version__ >= 600000000) // NetBSD 5 and Solaris don't like pragma pack but accept the packed attribute #pragma pack(pop) #endif // not NetBSD < 6 / Solaris diff --git a/src/map/party.c b/src/map/party.c index 77f3c2b0b..dbb7b6ae2 100644 --- a/src/map/party.c +++ b/src/map/party.c @@ -122,7 +122,8 @@ struct map_session_data *party_sd_check(int party_id, int account_id, int char_i return sd; } -int party_db_final(DBKey key, DBData *data, va_list ap) { +int party_db_final(union DBKey key, struct DBData *data, va_list ap) +{ struct party_data *p; if ((p = DB->data2ptr(data))) { @@ -146,9 +147,8 @@ struct party_data* party_searchname(const char* str) { struct party_data* p; - DBIterator *iter = db_iterator(party->db); - for( p = dbi_first(iter); dbi_exists(iter); p = dbi_next(iter) ) - { + struct DBIterator *iter = db_iterator(party->db); + for (p = dbi_first(iter); dbi_exists(iter); p = dbi_next(iter)) { if( strncmpi(p->party.name,str,NAME_LENGTH) == 0 ) break; } @@ -798,12 +798,16 @@ int party_send_logout(struct map_session_data *sd) return 1; } -int party_send_message(struct map_session_data *sd,const char *mes,int len) +int party_send_message(struct map_session_data *sd, const char *mes) { - if(sd->status.party_id==0) + int len = (int)strlen(mes); + + nullpo_ret(sd); + + if (sd->status.party_id == 0) return 0; - intif->party_message(sd->status.party_id,sd->status.account_id,mes,len); - party->recv_message(sd->status.party_id,sd->status.account_id,mes,len); + intif->party_message(sd->status.party_id, sd->status.account_id, mes, len); + party->recv_message(sd->status.party_id, sd->status.account_id, mes, len); // Chat logging type 'P' / Party Chat logs->chat(LOG_CHAT_PARTY, sd->status.party_id, sd->status.char_id, sd->status.account_id, mapindex_id2name(sd->mapindex), sd->bl.x, sd->bl.y, NULL, mes); @@ -871,10 +875,11 @@ int party_skill_check(struct map_session_data *sd, int party_id, uint16 skill_id return 0; } -int party_send_xy_timer(int tid, int64 tick, int id, intptr_t data) { +int party_send_xy_timer(int tid, int64 tick, int id, intptr_t data) +{ + struct DBIterator *iter = db_iterator(party->db); struct party_data* p; - DBIterator *iter = db_iterator(party->db); // for each existing party, for( p = dbi_first(iter); dbi_exists(iter); p = dbi_next(iter) ) { @@ -1284,7 +1289,7 @@ void party_recruit_search(struct map_session_data *sd, short level, short mapid, int count = 0; struct party_booking_ad_info* result_list[PARTY_BOOKING_RESULTS]; bool more_result = false; - DBIterator* iter = db_iterator(party->booking_db); + struct DBIterator *iter = db_iterator(party->booking_db); memset(result_list, 0, sizeof(result_list)); @@ -1315,7 +1320,7 @@ void party_booking_search(struct map_session_data *sd, short level, short mapid, int count = 0; struct party_booking_ad_info* result_list[PARTY_BOOKING_RESULTS]; bool more_result = false; - DBIterator* iter = db_iterator(party->booking_db); + struct DBIterator *iter = db_iterator(party->booking_db); memset(result_list, 0, sizeof(result_list)); diff --git a/src/map/party.h b/src/map/party.h index b66a9770c..05037eb04 100644 --- a/src/map/party.h +++ b/src/map/party.h @@ -85,8 +85,8 @@ struct party_booking_ad_info { * created by Susu *-------------------------------------*/ struct party_interface { - DBMap* db; // int party_id -> struct party_data* (releases data) - DBMap* booking_db; // int char_id -> struct party_booking_ad_info* (releases data) // Party Booking [Spiria] + struct DBMap *db; // int party_id -> struct party_data* (releases data) + struct DBMap *booking_db; // int char_id -> struct party_booking_ad_info* (releases data) // Party Booking [Spiria] unsigned int booking_nextid; /* funcs */ void (*init) (bool minimal); @@ -117,7 +117,7 @@ struct party_interface { void (*send_movemap) (struct map_session_data *sd); void (*send_levelup) (struct map_session_data *sd); int (*send_logout) (struct map_session_data *sd); - int (*send_message) (struct map_session_data *sd,const char *mes,int len); + int (*send_message) (struct map_session_data *sd, const char *mes); int (*recv_message) (int party_id,int account_id,const char *mes,int len); int (*skill_check) (struct map_session_data *sd, int party_id, uint16 skill_id, uint16 skill_lv); int (*send_xy_clear) (struct party_data *p); @@ -145,7 +145,7 @@ struct party_interface { struct map_session_data *(*sd_check) (int party_id, int account_id, int char_id); void (*check_state) (struct party_data *p); struct party_booking_ad_info* (*create_booking_data) (void); - int (*db_final) (DBKey key, DBData *data, va_list ap); + int (*db_final) (union DBKey key, struct DBData *data, va_list ap); }; #ifdef HERCULES_CORE diff --git a/src/map/path.c b/src/map/path.c index 543497c33..0df9708d8 100644 --- a/src/map/path.c +++ b/src/map/path.c @@ -254,7 +254,7 @@ static int add_path(struct node_heap *heap, struct path_node *tp, int16 x, int16 *------------------------------------------*/ bool path_search(struct walkpath_data *wpd, struct block_list *bl, int16 m, int16 x0, int16 y0, int16 x1, int16 y1, int flag, cell_chk cell) { - register int i, j, x, y, dx, dy; + register int i, x, y, dx, dy; struct map_data *md; struct walkpath_data s_wpd; @@ -315,8 +315,7 @@ bool path_search(struct walkpath_data *wpd, struct block_list *bl, int16 m, int1 } return false; // easy path unsuccessful - } - else { // !(flag&1) + } else { // !(flag&1) // A* (A-star) pathfinding // We always use A* for finding walkpaths because it is what game client uses. // Easy pathfinding cuts corners of non-walkable cells, but client always walks around it. @@ -331,6 +330,7 @@ bool path_search(struct walkpath_data *wpd, struct block_list *bl, int16 m, int1 int xs = md->xs - 1; int ys = md->ys - 1; int len = 0; + int j; memset(tp, 0, sizeof(tp)); // Start node @@ -407,7 +407,7 @@ bool path_search(struct walkpath_data *wpd, struct block_list *bl, int16 m, int1 } for (it = current; it->parent != NULL; it = it->parent, len++); - if (len > sizeof(wpd->path)) { + if (len > (int)sizeof(wpd->path)) { return false; } diff --git a/src/map/pc.c b/src/map/pc.c index 7b4d47db2..1c635e5cf 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -63,6 +63,7 @@ #include "common/random.h" #include "common/showmsg.h" #include "common/socket.h" +#include "common/sql.h" #include "common/strlib.h" // safestrncpy() #include "common/sysinfo.h" #include "common/timer.h" @@ -539,7 +540,7 @@ void pc_rental_expire(struct map_session_data *sd, int i) { } clif->rental_expired(sd->fd, i, sd->status.inventory[i].nameid); - pc->delitem(sd, i, sd->status.inventory[i].amount, 0, DELITEM_NORMAL, LOG_TYPE_OTHER); + pc->delitem(sd, i, sd->status.inventory[i].amount, 0, DELITEM_NORMAL, LOG_TYPE_RENTAL); } void pc_inventory_rentals(struct map_session_data *sd) { @@ -1863,8 +1864,8 @@ int pc_disguise(struct map_session_data *sd, int class_) { clif->cartlist(sd); clif->updatestatus(sd,SP_CARTINFO); } - if (sd->chatID) { - struct chat_data *cd = map->id2cd(sd->chatID); + if (sd->chat_id != 0) { + struct chat_data *cd = map->id2cd(sd->chat_id); if (cd != NULL) clif->dispchat(cd,0); @@ -4136,7 +4137,7 @@ int pc_insert_card(struct map_session_data* sd, int idx_card, int idx_equip) // remember the card id to insert nameid = sd->status.inventory[idx_card].nameid; - if( pc->delitem(sd, idx_card, 1, 1, DELITEM_NORMAL, LOG_TYPE_OTHER) == 1 ) + if( pc->delitem(sd, idx_card, 1, 1, DELITEM_NORMAL, LOG_TYPE_CARD) == 1 ) {// failed clif->insert_card(sd,idx_equip,idx_card,1); } @@ -4146,9 +4147,9 @@ int pc_insert_card(struct map_session_data* sd, int idx_card, int idx_equip) ARR_FIND( 0, sd->inventory_data[idx_equip]->slot, i, sd->status.inventory[idx_equip].card[i] == 0); if (i == sd->inventory_data[idx_equip]->slot) return 0; // no free slots - logs->pick_pc(sd, LOG_TYPE_OTHER, -1, &sd->status.inventory[idx_equip],sd->inventory_data[idx_equip]); + logs->pick_pc(sd, LOG_TYPE_CARD, -1, &sd->status.inventory[idx_equip],sd->inventory_data[idx_equip]); sd->status.inventory[idx_equip].card[i] = nameid; - logs->pick_pc(sd, LOG_TYPE_OTHER, 1, &sd->status.inventory[idx_equip],sd->inventory_data[idx_equip]); + logs->pick_pc(sd, LOG_TYPE_CARD, 1, &sd->status.inventory[idx_equip],sd->inventory_data[idx_equip]); clif->insert_card(sd,idx_equip,idx_card,0); return 1; } @@ -4275,7 +4276,7 @@ int pc_payzeny(struct map_session_data *sd,int zeny, enum e_log_pick_type type, if( zeny > 0 && sd->state.showzeny ) { char output[255]; sprintf(output, "Removed %dz.", zeny); - clif_disp_onlyself(sd,output,strlen(output)); + clif_disp_onlyself(sd, output); } return 0; @@ -4317,7 +4318,7 @@ int pc_paycash(struct map_session_data *sd, int price, int points) { char output[128]; sprintf(output, msg_sd(sd,504), points, cash, sd->kafraPoints, sd->cashPoints); - clif_disp_onlyself(sd, output, strlen(output)); + clif_disp_onlyself(sd, output); } return cash+points; } @@ -4342,7 +4343,7 @@ int pc_getcash(struct map_session_data *sd, int cash, int points) if( battle_config.cashshop_show_points ) { sprintf(output, msg_sd(sd,505), cash, sd->cashPoints); - clif_disp_onlyself(sd, output, strlen(output)); + clif_disp_onlyself(sd, output); } return cash; } @@ -4365,7 +4366,7 @@ int pc_getcash(struct map_session_data *sd, int cash, int points) if( battle_config.cashshop_show_points ) { sprintf(output, msg_sd(sd,506), points, sd->kafraPoints); - clif_disp_onlyself(sd, output, strlen(output)); + clif_disp_onlyself(sd, output); } return points; } @@ -4403,7 +4404,7 @@ int pc_getzeny(struct map_session_data *sd,int zeny, enum e_log_pick_type type, if( zeny > 0 && sd->state.showzeny ) { char output[255]; sprintf(output, "Gained %dz.", zeny); - clif_disp_onlyself(sd,output,strlen(output)); + clif_disp_onlyself(sd, output); } return 0; @@ -5340,7 +5341,7 @@ int pc_steal_item(struct map_session_data *sd,struct block_list *bl, uint16 skil char message[128]; sprintf (message, msg_txt(542), sd->status.name, md->db->jname, data->jname, (float)md->db->dropitem[i].p / 100); //MSG: "'%s' stole %s's %s (chance: %0.02f%%)" - intif->broadcast(message, strlen(message)+1, BC_DEFAULT); + intif->broadcast(message, (int)strlen(message)+1, BC_DEFAULT); } return 1; } @@ -6725,7 +6726,7 @@ bool pc_gainexp(struct map_session_data *sd, struct block_list *src, unsigned in char output[256]; sprintf(output, "Experience Gained Base:%u (%.2f%%) Job:%u (%.2f%%)",base_exp,nextbp*(float)100,job_exp,nextjp*(float)100); - clif_disp_onlyself(sd,output,strlen(output)); + clif_disp_onlyself(sd, output); } return true; @@ -8990,7 +8991,7 @@ char* pc_readregstr(struct map_session_data* sd, int64 reg) { void pc_setregstr(struct map_session_data* sd, int64 reg, const char* str) { struct script_reg_str *p = NULL; unsigned int index = script_getvaridx(reg); - DBData prev; + struct DBData prev; if( str[0] ) { p = ers_alloc(pc->str_reg_ers, struct script_reg_str); @@ -9113,7 +9114,7 @@ int pc_setregistry(struct map_session_data *sd, int64 reg, int val) { if( !pc->reg_load ) p->flag.update = 1;/* either way, it will require either delete or replace */ } else if( val ) { - DBData prev; + struct DBData prev; if( index ) script->array_update(&sd->regs, reg, false); @@ -9166,7 +9167,7 @@ int pc_setregistry_str(struct map_session_data *sd, int64 reg, const char *val) if( !pc->reg_load ) p->flag.update = 1;/* either way, it will require either delete or replace */ } else if( val[0] ) { - DBData prev; + struct DBData prev; if( index ) script->array_update(&sd->regs, reg, false); @@ -9905,7 +9906,7 @@ int pc_checkitem(struct map_session_data *sd) if (!itemdb_available(id)) { ShowWarning("Removed invalid/disabled item id %d from inventory (amount=%d, char_id=%d).\n", id, sd->status.inventory[i].amount, sd->status.char_id); - pc->delitem(sd, i, sd->status.inventory[i].amount, 0, DELITEM_NORMAL, LOG_TYPE_OTHER); + pc->delitem(sd, i, sd->status.inventory[i].amount, 0, DELITEM_NORMAL, LOG_TYPE_INV_INVALID); continue; } @@ -9921,7 +9922,7 @@ int pc_checkitem(struct map_session_data *sd) if( !itemdb_available(id) ) { ShowWarning("Removed invalid/disabled item id %d from cart (amount=%d, char_id=%d).\n", id, sd->status.cart[i].amount, sd->status.char_id); - pc->cart_delitem(sd, i, sd->status.cart[i].amount, 0, LOG_TYPE_OTHER); + pc->cart_delitem(sd, i, sd->status.cart[i].amount, 0, LOG_TYPE_CART_INVALID); continue; } @@ -10139,9 +10140,9 @@ int pc_divorce(struct map_session_data *sd) for( i = 0; i < MAX_INVENTORY; i++ ) { if( sd->status.inventory[i].nameid == WEDDING_RING_M || sd->status.inventory[i].nameid == WEDDING_RING_F ) - pc->delitem(sd, i, 1, 0, DELITEM_NORMAL, LOG_TYPE_OTHER); + pc->delitem(sd, i, 1, 0, DELITEM_NORMAL, LOG_TYPE_DIVORCE); if( p_sd->status.inventory[i].nameid == WEDDING_RING_M || p_sd->status.inventory[i].nameid == WEDDING_RING_F ) - pc->delitem(p_sd, i, 1, 0, DELITEM_NORMAL, LOG_TYPE_OTHER); + pc->delitem(p_sd, i, 1, 0, DELITEM_NORMAL, LOG_TYPE_DIVORCE); } clif->divorced(sd, p_sd->status.name); @@ -10334,7 +10335,7 @@ int map_day_timer(int tid, int64 tick, int id, intptr_t data) { map->night_flag = 0; // 0=day, 1=night [Yor] map->foreachpc(pc->daynight_timer_sub); safestrncpy(tmp_soutput, (data == 0) ? msg_txt(502) : msg_txt(60), sizeof(tmp_soutput)); // The day has arrived! - intif->broadcast(tmp_soutput, strlen(tmp_soutput) + 1, BC_DEFAULT); + intif->broadcast(tmp_soutput, (int)strlen(tmp_soutput) + 1, BC_DEFAULT); return 0; } @@ -10354,7 +10355,7 @@ int map_night_timer(int tid, int64 tick, int id, intptr_t data) { map->night_flag = 1; // 0=day, 1=night [Yor] map->foreachpc(pc->daynight_timer_sub); safestrncpy(tmp_soutput, (data == 0) ? msg_txt(503) : msg_txt(59), sizeof(tmp_soutput)); // The night has fallen... - intif->broadcast(tmp_soutput, strlen(tmp_soutput) + 1, BC_DEFAULT); + intif->broadcast(tmp_soutput, (int)strlen(tmp_soutput) + 1, BC_DEFAULT); return 0; } @@ -11013,18 +11014,18 @@ int pc_readdb(void) { ShowError("can't read %s\n", line); return 1; } - while(fgets(line, sizeof(line), fp)) - { + while (fgets(line, sizeof(line), fp)) { char *split[10]; int lv,n; - if(line[0]=='/' && line[1]=='/') + if (line[0]=='/' && line[1]=='/') continue; - for(j=0,p=line;j<3 && p;j++){ - split[j]=p; - p=strchr(p,','); - if(p) *p++=0; + for (j = 0, p = line; j < 3 && p != NULL; j++) { + split[j] = p; + p = strchr(p,','); + if (p != NULL) + *p++ = 0; } - if( j < 2 ) + if (j < 2) continue; lv=atoi(split[0]); @@ -11036,8 +11037,8 @@ int pc_readdb(void) { if(line[0]=='/' && line[1]=='/') continue; - for ( j = ELE_NEUTRAL, p = line; j<n && j<ELE_MAX && p; j++ ) { - while(*p==32 && *p>0) + for (j = ELE_NEUTRAL, p = line; j < n && j < ELE_MAX && p != NULL; j++) { + while (*p == ' ') p++; battle->attr_fix_table[lv-1][i][j]=atoi(p); #ifndef RENEWAL @@ -11045,7 +11046,8 @@ int pc_readdb(void) { battle->attr_fix_table[lv-1][i][j] = 0; #endif p=strchr(p,','); - if(p) *p++=0; + if (p != NULL) + *p++ = 0; } i++; @@ -11194,7 +11196,7 @@ void pc_scdata_received(struct map_session_data *sd) { time_t exp_time = sd->expiration_time; char tmpstr[1024]; strftime(tmpstr, sizeof(tmpstr) - 1, msg_sd(sd,501), localtime(&exp_time)); // "Your account time limit is: %d-%m-%Y %H:%M:%S." - clif->wis_message(sd->fd, map->wisp_server_name, tmpstr, strlen(tmpstr)+1); + clif->wis_message(sd->fd, map->wisp_server_name, tmpstr, (int)strlen(tmpstr)); pc->expire_check(sd); } @@ -11474,7 +11476,8 @@ void pc_autotrade_populate(struct map_session_data *sd) { /** * @see DBApply */ -int pc_autotrade_final(DBKey key, DBData *data, va_list ap) { +int pc_autotrade_final(union DBKey key, struct DBData *data, va_list ap) +{ struct autotrade_vending* at_v = DB->data2ptr(data); HPM->data_store_destroy(&at_v->hdata); return 0; @@ -11514,6 +11517,87 @@ int pc_have_magnifier(struct map_session_data *sd) return n; } +/** + * Verifies a chat message, searching for atcommands, checking if the sender + * character can chat, and updating the idle timer. + * + * @param sd The sender character. + * @param message The message text. + * @return Whether the message is a valid chat message. + */ +bool pc_process_chat_message(struct map_session_data *sd, const char *message) +{ + if (atcommand->exec(sd->fd, sd, message, true)) { + return false; + } + + if (!pc->can_talk(sd)) { + return false; + } + + if (battle_config.min_chat_delay != 0) { + if (DIFF_TICK(sd->cantalk_tick, timer->gettick()) > 0) { + return false; + } + sd->cantalk_tick = timer->gettick() + battle_config.min_chat_delay; + } + + pc->update_idle_time(sd, BCIDLE_CHAT); + + return true; +} + +/** + * Checks a chat message, scanning for the Super Novice prayer sequence. + * + * If a match is found, the angel is invoked or the counter is incremented as + * appropriate. + * + * @param sd The sender character. + * @param message The message text. + */ +void pc_check_supernovice_call(struct map_session_data *sd, const char *message) +{ + unsigned int next = pc->nextbaseexp(sd); + int percent = 0; + + if ((sd->class_&MAPID_UPPERMASK) != MAPID_SUPER_NOVICE) + return; + if (next == 0) + next = pc->thisbaseexp(sd); + if (next == 0) + return; + + // 0%, 10%, 20%, ... + percent = (int)( ( (float)sd->status.base_exp/(float)next )*1000. ); + if ((battle_config.snovice_call_type != 0 || percent != 0) && (percent%100) == 0) { + // 10.0%, 20.0%, ..., 90.0% + switch (sd->state.snovice_call_flag) { + case 0: + if (strstr(message, msg_txt(1479))) // "Dear angel, can you hear my voice?" + sd->state.snovice_call_flag = 1; + break; + case 1: + { + char buf[256]; + snprintf(buf, 256, msg_txt(1480), sd->status.name); + if (strstr(message, buf)) // "I am %s Super Novice~" + sd->state.snovice_call_flag = 2; + } + break; + case 2: + if (strstr(message, msg_txt(1481))) // "Help me out~ Please~ T_T" + sd->state.snovice_call_flag = 3; + break; + case 3: + sc_start(NULL, &sd->bl, status->skill2sc(MO_EXPLOSIONSPIRITS), 100, 17, skill->get_time(MO_EXPLOSIONSPIRITS, 5)); //Lv17-> +50 critical (noted by Poki) [Skotlex] + clif->skill_nodamage(&sd->bl, &sd->bl, MO_EXPLOSIONSPIRITS, 5, 1); // prayer always shows successful Lv5 cast and disregards noskill restrictions + sd->state.snovice_call_flag = 0; + break; + } + } +} + void do_final_pc(void) { db_destroy(pc->itemcd_db); pc->at_db->destroy(pc->at_db,pc->autotrade_final); @@ -11869,6 +11953,9 @@ void pc_defaults(void) { pc->db_checkid = pc_db_checkid; pc->validate_levels = pc_validate_levels; + pc->check_supernovice_call = pc_check_supernovice_call; + pc->process_chat_message = pc_process_chat_message; + /** * Autotrade persistency [Ind/Hercules <3] **/ diff --git a/src/map/pc.h b/src/map/pc.h index 0d2bca84d..58f7a2266 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -33,8 +33,9 @@ #include "map/status.h" // enum sc_type, OPTION_* #include "map/unit.h" // struct unit_data, struct view_data #include "map/vending.h" // struct s_vending -#include "common/hercules.h" +#include "common/db.h" #include "common/ers.h" // struct eri +#include "common/hercules.h" #include "common/mmo.h" // JOB_*, MAX_FAME_LIST, struct fame_list, struct mmo_charstatus, NEW_CARTS /** @@ -257,7 +258,7 @@ struct map_session_data { struct script_state *st; 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; + int chat_id; int64 idletime; struct { int npc_id; @@ -530,7 +531,7 @@ END_ZEROED_BLOCK; unsigned char channel_count; struct channel_data *gcbind; unsigned char fontcolor; - unsigned int fontcolor_tid; + int fontcolor_tid; int64 hchsysch_tick; /* [Ind/Hercules] */ @@ -609,15 +610,15 @@ END_ZEROED_BLOCK; #define pc_setsit(sd) ( (sd)->state.dead_sit = (sd)->vd.dead_sit = 2 ) #define pc_isdead(sd) ( (sd)->state.dead_sit == 1 ) #define pc_issit(sd) ( (sd)->vd.dead_sit == 2 ) -#define pc_isidle(sd) ( (sd)->chatID || (sd)->state.vending || (sd)->state.buyingstore || DIFF_TICK(sockt->last_tick, (sd)->idletime) >= battle->bc->idle_no_share ) +#define pc_isidle(sd) ( (sd)->chat_id != 0 || (sd)->state.vending || (sd)->state.buyingstore || DIFF_TICK(sockt->last_tick, (sd)->idletime) >= battle->bc->idle_no_share ) #define pc_istrading(sd) ( (sd)->npc_id || (sd)->state.vending || (sd)->state.buyingstore || (sd)->state.trading ) -#define pc_cant_act(sd) ( (sd)->npc_id || (sd)->state.vending || (sd)->state.buyingstore || (sd)->chatID || ((sd)->sc.opt1 && (sd)->sc.opt1 != OPT1_BURNING) || (sd)->state.trading || (sd)->state.storage_flag || (sd)->state.prevend ) +#define pc_cant_act(sd) ( (sd)->npc_id || (sd)->state.vending || (sd)->state.buyingstore || (sd)->chat_id != 0 || ((sd)->sc.opt1 && (sd)->sc.opt1 != OPT1_BURNING) || (sd)->state.trading || (sd)->state.storage_flag || (sd)->state.prevend ) /* equals pc_cant_act except it doesn't check for chat rooms */ #define pc_cant_act2(sd) ( (sd)->npc_id || (sd)->state.buyingstore || ((sd)->sc.opt1 && (sd)->sc.opt1 != OPT1_BURNING) || (sd)->state.trading || (sd)->state.storage_flag || (sd)->state.prevend ) #define pc_setdir(sd,b,h) ( (sd)->ud.dir = (b) ,(sd)->head_dir = (h) ) -#define pc_setchatid(sd,n) ( (sd)->chatID = n ) +#define pc_setchatid(sd,n) ( (sd)->chat_id = (n) ) #define pc_ishiding(sd) ( (sd)->sc.option&(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK) ) #define pc_iscloaking(sd) ( !((sd)->sc.option&OPTION_CHASEWALK) && ((sd)->sc.option&OPTION_CLOAK) ) #define pc_ischasewalk(sd) ( (sd)->sc.option&OPTION_CHASEWALK ) @@ -657,7 +658,7 @@ END_ZEROED_BLOCK; #define pc_stop_attack(sd) (unit->stop_attack(&(sd)->bl)) //Weapon check considering dual wielding. -#define pc_check_weapontype(sd, type) ((type)&((sd)->status.weapon < MAX_WEAPON_TYPE? \ +#define pc_check_weapontype(sd, type) ((type)&((sd)->status.weapon < MAX_SINGLE_WEAPON_TYPE? \ 1<<(sd)->status.weapon:(1<<(sd)->weapontype1)|(1<<(sd)->weapontype2)|(1<<(sd)->status.weapon))) // clientside display macros (values to the left/right of the "+") @@ -784,9 +785,9 @@ struct autotrade_vending { struct pc_interface { /* */ - DBMap *at_db;/* char id -> struct autotrade_vending */ + struct DBMap *at_db;/* char id -> struct autotrade_vending */ /* */ - DBMap* itemcd_db; + struct DBMap *itemcd_db; /* */ int day_timer_tid; int night_timer_tid; @@ -1084,12 +1085,15 @@ END_ZEROED_BLOCK; /* End */ void (*autotrade_start) (struct map_session_data *sd); void (*autotrade_prepare) (struct map_session_data *sd); void (*autotrade_populate) (struct map_session_data *sd); - int (*autotrade_final) (DBKey key, DBData *data, va_list ap); + int (*autotrade_final) (union DBKey key, struct DBData *data, va_list ap); int (*check_job_name) (const char *name); void (*update_idle_time) (struct map_session_data* sd, enum e_battle_config_idletime type); - + int (*have_magnifier) (struct map_session_data *sd); + + bool (*process_chat_message) (struct map_session_data *sd, const char *message); + void (*check_supernovice_call) (struct map_session_data *sd, const char *message); }; #ifdef HERCULES_CORE diff --git a/src/map/pc_groups.c b/src/map/pc_groups.c index b325a8ed7..ccda34b1c 100644 --- a/src/map/pc_groups.c +++ b/src/map/pc_groups.c @@ -75,7 +75,7 @@ static void read_config(void) { if (groups != NULL) { GroupSettings *group_settings = NULL; - DBIterator *iter = NULL; + struct DBIterator *iter = NULL; int i, loop = 0; group_count = libconfig->setting_length(groups); @@ -465,7 +465,7 @@ void do_init_pc_groups(void) { /** * @see DBApply */ -static int group_db_clear_sub(DBKey key, DBData *data, va_list args) +static int group_db_clear_sub(union DBKey key, struct DBData *data, va_list args) { GroupSettings *group = DB->data2ptr(data); if (group->name) diff --git a/src/map/pc_groups.h b/src/map/pc_groups.h index 3f95237b7..27eac7284 100644 --- a/src/map/pc_groups.h +++ b/src/map/pc_groups.h @@ -22,9 +22,9 @@ #define MAP_PC_GROUPS_H #include "common/hercules.h" -#include "common/db.h" /* Forward Declarations */ +struct DBMap; // common/db.h struct config_setting_t; /// PC permissions @@ -91,8 +91,8 @@ struct pc_groups_new_permission { struct pc_groups_interface { /* */ - DBMap* db; // id -> GroupSettings - DBMap* name_db; // name -> GroupSettings + struct DBMap *db; // id -> GroupSettings + struct DBMap *name_db; // name -> GroupSettings /* */ struct pc_groups_permission_table *permissions; unsigned char permission_count; diff --git a/src/map/pet.c b/src/map/pet.c index 256324d29..e2b257e10 100644 --- a/src/map/pet.c +++ b/src/map/pet.c @@ -317,7 +317,7 @@ int pet_return_egg(struct map_session_data *sd, struct pet_data *pd) tmp_item.card[1] = GetWord(pd->pet.pet_id,0); tmp_item.card[2] = GetWord(pd->pet.pet_id,1); tmp_item.card[3] = pd->pet.rename_flag; - if((flag = pc->additem(sd,&tmp_item,1,LOG_TYPE_OTHER))) { + if((flag = pc->additem(sd,&tmp_item,1,LOG_TYPE_EGG))) { clif->additem(sd,0,0,flag); map->addflooritem(&sd->bl, &tmp_item, 1, sd->bl.m, sd->bl.x, sd->bl.y, 0, 0, 0, 0); } @@ -464,7 +464,7 @@ int pet_recv_petdata(int account_id,struct s_pet *p,int flag) { return 1; } if (!pet->birth_process(sd,p)) //Pet hatched. Delete egg. - pc->delitem(sd, i, 1, 0, DELITEM_NORMAL, LOG_TYPE_OTHER); + pc->delitem(sd, i, 1, 0, DELITEM_NORMAL, LOG_TYPE_EGG); } else { pet->data_init(sd,p); if(sd->pd && sd->bl.prev != NULL) { @@ -703,7 +703,7 @@ int pet_equipitem(struct map_session_data *sd,int index) { return 1; } - pc->delitem(sd, index, 1, 0, DELITEM_NORMAL, LOG_TYPE_OTHER); + pc->delitem(sd, index, 1, 0, DELITEM_NORMAL, LOG_TYPE_CONSUME); pd->pet.equip = nameid; status->set_viewdata(&pd->bl, pd->pet.class_); //Updates view_data. clif->send_petdata(NULL, sd->pd, 3, sd->pd->vd.head_bottom); @@ -734,7 +734,7 @@ int pet_unequipitem(struct map_session_data *sd, struct pet_data *pd) { memset(&tmp_item,0,sizeof(tmp_item)); tmp_item.nameid = nameid; tmp_item.identify = 1; - if((flag = pc->additem(sd,&tmp_item,1,LOG_TYPE_OTHER))) { + if((flag = pc->additem(sd,&tmp_item,1,LOG_TYPE_CONSUME))) { clif->additem(sd,0,0,flag); map->addflooritem(&sd->bl, &tmp_item, 1, sd->bl.m, sd->bl.x, sd->bl.y, 0, 0, 0, 0); } diff --git a/src/map/quest.c b/src/map/quest.c index bf0a76b16..79328ae9d 100644 --- a/src/map/quest.c +++ b/src/map/quest.c @@ -316,7 +316,7 @@ void quest_update_objective(struct map_session_data *sd, int mob_id) item.nameid = dropitem->nameid; item.identify = itemdb->isidentified2(data); item.amount = 1; - if((temp = pc->additem(sd, &item, 1, LOG_TYPE_OTHER)) != 0) { // TODO: We might want a new log type here? + if((temp = pc->additem(sd, &item, 1, LOG_TYPE_QUEST)) != 0) { // TODO: We might want a new log type here? // Failed to obtain the item clif->additem(sd, 0, 0, temp); } diff --git a/src/map/script.c b/src/map/script.c index 7d5ce7d43..07b37571e 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -56,6 +56,7 @@ #include "map/unit.h" #include "common/cbasetypes.h" #include "common/conf.h" +#include "common/db.h" #include "common/memmgr.h" #include "common/md5calc.h" #include "common/mmo.h" // NEW_CARTS @@ -63,6 +64,7 @@ #include "common/random.h" #include "common/showmsg.h" #include "common/socket.h" // usage: getcharip +#include "common/sql.h" #include "common/strlib.h" #include "common/sysinfo.h" #include "common/timer.h" @@ -235,9 +237,9 @@ void script_reportsrc(struct script_state *st) { break; default: if( bl->m >= 0 ) - ShowDebug("Source (Non-NPC type %u): name %s at %s (%d,%d)\n", bl->type, status->get_name(bl), map->list[bl->m].name, bl->x, bl->y); + ShowDebug("Source (Non-NPC type %u): name %s at %s (%d,%d)\n", bl->type, clif->get_bl_name(bl), map->list[bl->m].name, bl->x, bl->y); else - ShowDebug("Source (Non-NPC type %u): name %s (invisible/not on a map)\n", bl->type, status->get_name(bl)); + ShowDebug("Source (Non-NPC type %u): name %s (invisible/not on a map)\n", bl->type, clif->get_bl_name(bl)); break; } } @@ -2349,6 +2351,8 @@ void read_constdb(void) } else { value = libconfig->setting_get_int(t); } + if (is_parameter) + ShowWarning("read_constdb: Defining parameters in the constants configuration is deprecated and will no longer be possible in a future version. Parameters should be defined in source. (parameter = '%s')\n", name); script->set_constant(name, value, is_parameter, is_deprecated); } script->constdb_comment(NULL); @@ -2367,6 +2371,49 @@ void script_constdb_comment(const char *comment) (void)comment; } +void script_load_parameters(void) +{ + int i = 0; + struct { + char *name; + enum status_point_types type; + } parameters[] = { + {"BaseExp", SP_BASEEXP}, + {"JobExp", SP_JOBEXP}, + {"Karma", SP_KARMA}, + {"Manner", SP_MANNER}, + {"Hp", SP_HP}, + {"MaxHp", SP_MAXHP}, + {"Sp", SP_SP}, + {"MaxSp", SP_MAXSP}, + {"StatusPoint", SP_STATUSPOINT}, + {"BaseLevel", SP_BASELEVEL}, + {"SkillPoint", SP_SKILLPOINT}, + {"Class", SP_CLASS}, + {"Zeny", SP_ZENY}, + {"Sex", SP_SEX}, + {"NextBaseExp", SP_NEXTBASEEXP}, + {"NextJobExp", SP_NEXTJOBEXP}, + {"Weight", SP_WEIGHT}, + {"MaxWeight", SP_MAXWEIGHT}, + {"JobLevel", SP_JOBLEVEL}, + {"Upper", SP_UPPER}, + {"BaseJob", SP_BASEJOB}, + {"BaseClass", SP_BASECLASS}, + {"killerrid", SP_KILLERRID}, + {"killedrid", SP_KILLEDRID}, + {"SlotChange", SP_SLOTCHANGE}, + {"CharRename", SP_CHARRENAME}, + {"ModExp", SP_MOD_EXP}, + {"ModDrop", SP_MOD_DROP}, + {"ModDeath", SP_MOD_DEATH}, + }; + + script->constdb_comment("Parameters"); + for (i=0; i < ARRAYLENGTH(parameters); ++i) + script->set_constant(parameters[i].name, parameters[i].type, true, false); + script->constdb_comment(NULL); +} // Standard UNIX tab size is 8 #define TAB_SIZE 8 #define update_tabstop(tabstop,chars) \ @@ -2652,13 +2699,13 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o #endif #ifdef SCRIPT_DEBUG_DISASM i = 0; - while(i < script->pos) { - int j = i; - c_op op = script->get_com(script->buf,&i); + while (i < script->pos) { + c_op op = script->get_com(script->buf, &i); + int j = i; // Note: i is modified in the line above. ShowMessage("%06x %s", i, script->op2name(op)); - j = i; - switch(op) { + + switch (op) { case C_INT: ShowMessage(" %d", script->get_num(script->buf,&i)); break; @@ -2819,43 +2866,46 @@ struct script_data *get_val(struct script_state* st, struct script_data* data) { } } - if( postfix == '$' ) {// string variable + if (postfix == '$') { + // string variable + const char *str = NULL; - switch( prefix ) { + switch (prefix) { case '@': - data->u.str = pc->readregstr(sd, data->u.num); + str = pc->readregstr(sd, data->u.num); break; case '$': - data->u.str = mapreg->readregstr(data->u.num); + str = mapreg->readregstr(data->u.num); break; case '#': - if( name[1] == '#' ) - data->u.str = pc_readaccountreg2str(sd, data->u.num);// global + if (name[1] == '#') + str = pc_readaccountreg2str(sd, data->u.num);// global else - data->u.str = pc_readaccountregstr(sd, data->u.num);// local + str = pc_readaccountregstr(sd, data->u.num);// local break; case '.': if (data->ref) - data->u.str = script->get_val_ref_str(st, data->ref, data); + str = script->get_val_ref_str(st, data->ref, data); else if (name[1] == '@') - data->u.str = script->get_val_scope_str(st, &st->stack->scope, data); + str = script->get_val_scope_str(st, &st->stack->scope, data); else - data->u.str = script->get_val_npc_str(st, &st->script->local, data); + str = script->get_val_npc_str(st, &st->script->local, data); break; case '\'': - data->u.str = script->get_val_instance_str(st, name, data); + str = script->get_val_instance_str(st, name, data); break; default: - data->u.str = pc_readglobalreg_str(sd, data->u.num); + str = pc_readglobalreg_str(sd, data->u.num); break; } - if( data->u.str == NULL || data->u.str[0] == '\0' ) {// empty string + if (str == NULL || str[0] == '\0') { + // empty string data->type = C_CONSTSTR; data->u.str = ""; } else {// duplicate string data->type = C_STR; - data->u.str = aStrdup(data->u.str); + data->u.mutstr = aStrdup(str); } } else {// integer variable @@ -2912,12 +2962,16 @@ struct script_data *get_val(struct script_state* st, struct script_data* data) { * @param ref[in] the container to look up the reference into. * @return the retrieved value of the reference. */ -void* get_val2(struct script_state* st, int64 uid, struct reg_db *ref) { +const void *get_val2(struct script_state *st, int64 uid, struct reg_db *ref) +{ struct script_data* data; script->push_val(st->stack, C_NAME, uid, ref); data = script_getdatatop(st, -1); script->get_val(st, data); - return (data->type == C_INT ? (void*)h64BPTRSIZE((int32)data->u.num) : (void*)h64BPTRSIZE(data->u.str)); // u.num is int32 because it comes from script->get_val + if (data->type == C_INT) // u.num is int32 because it comes from script->get_val + return (const void *)h64BPTRSIZE((int32)data->u.num); + else + return (const void *)h64BPTRSIZE(data->u.str); } /** * Because, currently, array members with key 0 are indifferenciable from normal variables, we should ensure its actually in @@ -2934,8 +2988,8 @@ void script_array_ensure_zero(struct script_state *st, struct map_session_data * insert = true; } else { if( is_string_variable(name) ) { - char* str = (char*)script->get_val2(st, uid, ref); - if( str && *str ) + const char *str = script->get_val2(st, uid, ref); + if (str != NULL && *str != '\0') insert = true; script_removetop(st, -1, 0); } else { @@ -2999,7 +3053,8 @@ unsigned int script_array_highest_key(struct script_state *st, struct map_sessio } return 0; } -int script_free_array_db(DBKey key, DBData *data, va_list ap) { +int script_free_array_db(union DBKey key, struct DBData *data, va_list ap) +{ struct script_array *sa = DB->data2ptr(data); aFree(sa->members); ers_free(script->array_ers, sa); @@ -3306,59 +3361,59 @@ int set_var(struct map_session_data *sd, char *name, void *val) return script->set_reg(NULL, sd, reference_uid(script->add_str(name),0), name, val, NULL); } -void setd_sub(struct script_state *st, struct map_session_data *sd, const char *varname, int elem, void *value, struct reg_db *ref) +void setd_sub(struct script_state *st, struct map_session_data *sd, const char *varname, int elem, const void *value, struct reg_db *ref) { script->set_reg(st, sd, reference_uid(script->add_str(varname),elem), varname, value, ref); } /// Converts the data to a string -const char* conv_str(struct script_state* st, struct script_data* data) +const char *conv_str(struct script_state *st, struct script_data* data) { - char* p; - script->get_val(st, data); - if( data_isstring(data) ) - {// nothing to convert + if (data_isstring(data)) { + // nothing to convert + return data->u.str; } - else if( data_isint(data) ) - {// int -> string + if (data_isint(data)) { + // int -> string + char *p; CREATE(p, char, ITEM_NAME_LENGTH); snprintf(p, ITEM_NAME_LENGTH, "%"PRId64"", data->u.num); p[ITEM_NAME_LENGTH-1] = '\0'; data->type = C_STR; - data->u.str = p; + data->u.mutstr = p; + return data->u.mutstr; } - else if( data_isreference(data) ) - {// reference -> string + if (data_isreference(data)) { + // reference -> string //##TODO when does this happen (check script->get_val) [FlavioJS] data->type = C_CONSTSTR; data->u.str = reference_getname(data); - } - else - {// unsupported data type - ShowError("script:conv_str: cannot convert to string, defaulting to \"\"\n"); - script->reportdata(data); - script->reportsrc(st); - data->type = C_CONSTSTR; - data->u.str = ""; - } + return data->u.str; + } + // unsupported data type + ShowError("script:conv_str: cannot convert to string, defaulting to \"\"\n"); + script->reportdata(data); + script->reportsrc(st); + data->type = C_CONSTSTR; + data->u.str = ""; return data->u.str; } /// Converts the data to an int -int conv_num(struct script_state* st, struct script_data* data) { - char* p; +int conv_num(struct script_state *st, struct script_data *data) +{ long num; script->get_val(st, data); - if( data_isint(data) ) - {// nothing to convert + if (data_isint(data)) { + // nothing to convert + return (int)data->u.num; } - else if( data_isstring(data) ) - {// string -> int + if (data_isstring(data)) { + // string -> int // the result does not overflow or underflow, it is capped instead // ex: 999999999999 is capped to INT_MAX (2147483647) - p = data->u.str; errno = 0; num = strtol(data->u.str, NULL, 10);// change radix to 0 to support octal numbers "o377" and hex numbers "0xFF" if( errno == ERANGE @@ -3380,22 +3435,21 @@ int conv_num(struct script_state* st, struct script_data* data) { script->reportdata(data); script->reportsrc(st); } - if( data->type == C_STR ) - aFree(p); + if (data->type == C_STR) + aFree(data->u.mutstr); data->type = C_INT; data->u.num = (int)num; + return (int)data->u.num; } #if 0 + // unsupported data type // FIXME this function is being used to retrieve the position of labels and // probably other stuff [FlavioJS] - else - {// unsupported data type - ShowError("script:conv_num: cannot convert to number, defaulting to 0\n"); - script->reportdata(data); - script->reportsrc(st); - data->type = C_INT; - data->u.num = 0; - } + ShowError("script:conv_num: cannot convert to number, defaulting to 0\n"); + script->reportdata(data); + script->reportsrc(st); + data->type = C_INT; + data->u.num = 0; #endif return (int)data->u.num; } @@ -3425,11 +3479,23 @@ struct script_data* push_val(struct script_stack* stack, enum c_op type, int64 v } /// Pushes a string into the stack -struct script_data* push_str(struct script_stack* stack, enum c_op type, char* str) +struct script_data *push_str(struct script_stack *stack, char *str) { if( stack->sp >= stack->sp_max ) script->stack_expand(stack); - stack->stack_data[stack->sp].type = type; + stack->stack_data[stack->sp].type = C_STR; + stack->stack_data[stack->sp].u.mutstr = str; + stack->stack_data[stack->sp].ref = NULL; + stack->sp++; + return &stack->stack_data[stack->sp-1]; +} + +/// Pushes a constant string into the stack +struct script_data *push_conststr(struct script_stack *stack, const char *str) +{ + if( stack->sp >= stack->sp_max ) + script->stack_expand(stack); + stack->stack_data[stack->sp].type = C_CONSTSTR; stack->stack_data[stack->sp].u.str = str; stack->stack_data[stack->sp].ref = NULL; stack->sp++; @@ -3451,10 +3517,10 @@ struct script_data* push_retinfo(struct script_stack* stack, struct script_retin struct script_data* push_copy(struct script_stack* stack, int pos) { switch( stack->stack_data[pos].type ) { case C_CONSTSTR: - return script->push_str(stack, C_CONSTSTR, stack->stack_data[pos].u.str); + return script->push_conststr(stack, stack->stack_data[pos].u.str); break; case C_STR: - return script->push_str(stack, C_STR, aStrdup(stack->stack_data[pos].u.str)); + return script->push_str(stack, aStrdup(stack->stack_data[pos].u.mutstr)); break; case C_RETINFO: ShowFatalError("script:push_copy: can't create copies of C_RETINFO. Exiting...\n"); @@ -3488,8 +3554,8 @@ void pop_stack(struct script_state* st, int start, int end) { for( i = start; i < end; i++ ) { data = &stack->stack_data[i]; - if( data->type == C_STR ) - aFree(data->u.str); + if (data->type == C_STR) + aFree(data->u.mutstr); if( data->type == C_RETINFO ) { struct script_retinfo* ri = data->u.ri; @@ -3541,7 +3607,8 @@ void pop_stack(struct script_state* st, int start, int end) { /*========================================== * Release script dependent variable, dependent variable of function *------------------------------------------*/ -void script_free_vars(struct DBMap* var_storage) { +void script_free_vars(struct DBMap *var_storage) +{ if( var_storage ) { // destroy the storage construct containing the variables db_destroy(var_storage); @@ -3720,12 +3787,11 @@ void op_3(struct script_state* st, int op) data = script_getdatatop(st, -3); script->get_val(st, data); - if( data_isstring(data) ) - flag = data->u.str[0];// "" -> false - else if( data_isint(data) ) + if (data_isstring(data)) { + flag = data->u.str[0]; // "" -> false + } else if (data_isint(data)) { flag = data->u.num == 0 ? 0 : 1;// 0 -> false - else - { + } else { ShowError("script:op_3: invalid data for the ternary operator test\n"); script->reportdata(data); script->reportsrc(st); @@ -3768,7 +3834,7 @@ void op_2str(struct script_state* st, int op, const char* s1, const char* s2) pcre *compiled_regex; pcre_extra *extra_regex; const char *pcre_error, *pcre_match; - int pcre_erroroffset, offsetcount, i; + int pcre_erroroffset, offsetcount; int offsets[256*3]; // (max_capturing_groups+1)*3 compiled_regex = libpcre->compile(s2, 0, &pcre_error, &pcre_erroroffset, NULL); @@ -3809,8 +3875,9 @@ void op_2str(struct script_state* st, int op, const char* s1, const char* s2) return; } - if( op == C_RE_EQ ) { - for( i = 0; i < offsetcount; i++ ) { + if (op == C_RE_EQ) { + int i; + for (i = 0; i < offsetcount; i++) { libpcre->get_substring(s1, offsets, offsetcount, i, &pcre_match); mapreg->setregstr(reference_uid(script->add_str("$@regexmatch$"), i), pcre_match); libpcre->free_substring(pcre_match); @@ -3946,10 +4013,9 @@ void op_2(struct script_state *st, int op) script->op_2str(st, op, left->u.str, right->u.str); script_removetop(st, leftref.type == C_NOP ? -3 : -2, -1);// pop the two values before the top one - if (leftref.type != C_NOP) - { + if (leftref.type != C_NOP) { if (left->type == C_STR) // don't free C_CONSTSTR - aFree(left->u.str); + aFree(left->u.mutstr); *left = leftref; } } @@ -4198,8 +4264,9 @@ void run_script(struct script_code *rootscript, int pos, int rid, int oid) { script->run_main(st); } -void script_stop_instances(struct script_code *code) { - DBIterator *iter; +void script_stop_instances(struct script_code *code) +{ + struct DBIterator *iter; struct script_state* st; if( !script->active_scripts ) @@ -4347,7 +4414,7 @@ void run_script_main(struct script_state *st) { script->push_val(stack,c,0,NULL); break; case C_STR: - script->push_str(stack,C_CONSTSTR,(char*)(st->script->script_buf+st->pos)); + script->push_conststr(stack, (const char *)(st->script->script_buf+st->pos)); while(st->script->script_buf[st->pos++]); break; case C_LSTR: @@ -4359,7 +4426,7 @@ void run_script_main(struct script_state *st) { st->pos += sizeof(int) + sizeof(uint8); if( (!st->rid || !(lsd = map->id2sd(st->rid)) || !lsd->lang_id) && !map->default_lang_id ) - script->push_str(stack,C_CONSTSTR,script->string_list+string_id); + script->push_conststr(stack, script->string_list+string_id); else { uint8 k, wlang_id = lsd ? lsd->lang_id : map->default_lang_id; int offset = st->pos; @@ -4371,8 +4438,10 @@ void run_script_main(struct script_state *st) { break; offset += sizeof(char*); } - script->push_str(stack,C_CONSTSTR, - ( k == translations ) ? script->string_list+string_id : *(char**)(&st->script->script_buf[offset]) ); + if (k == translations) + script->push_conststr(stack, script->string_list+string_id); + else + script->push_conststr(stack, *(const char**)(&st->script->script_buf[offset]) ); } st->pos += ( ( sizeof(char*) + sizeof(uint8) ) * translations ); } @@ -4531,7 +4600,7 @@ int script_config_read(char *cfgName) { /** * @see DBApply */ -int db_script_free_code_sub(DBKey key, DBData *data, va_list ap) +int db_script_free_code_sub(union DBKey key, struct DBData *data, va_list ap) { struct script_code *code = DB->data2ptr(data); if (code) @@ -4607,7 +4676,8 @@ void script_setarray_pc(struct map_session_data* sd, const char* varname, uint32 /** * Clears persistent variables from memory **/ -int script_reg_destroy(DBKey key, DBData *data, va_list ap) { +int script_reg_destroy(union DBKey key, struct DBData *data, va_list ap) +{ struct script_reg_state *src; if( data->type != DB_DATA_PTR )/* got no need for those! */ @@ -4657,9 +4727,10 @@ void script_generic_ui_array_expand (unsigned int plus) { /*========================================== * Destructor *------------------------------------------*/ -void do_final_script(void) { +void do_final_script(void) +{ int i; - DBIterator *iter; + struct DBIterator *iter; struct script_state *st; #ifdef SCRIPT_DEBUG_HASH @@ -4850,9 +4921,8 @@ void script_load_translations(void) { libconfig->destroy(&translations_conf); if( total ) { - DBIterator *main_iter; - DBIterator *sub_iter; - DBMap *string_db; + struct DBIterator *main_iter; + struct DBMap *string_db; struct string_translation *st = NULL; uint32 j = 0; @@ -4860,9 +4930,9 @@ void script_load_translations(void) { script->translation_buf_size = total; main_iter = db_iterator(script->translation_db); - for( string_db = dbi_first(main_iter); dbi_exists(main_iter); string_db = dbi_next(main_iter) ) { - sub_iter = db_iterator(string_db); - for( st = dbi_first(sub_iter); dbi_exists(sub_iter); st = dbi_next(sub_iter) ) { + for (string_db = dbi_first(main_iter); dbi_exists(main_iter); string_db = dbi_next(main_iter)) { + struct DBIterator *sub_iter = db_iterator(string_db); + for (st = dbi_first(sub_iter); dbi_exists(sub_iter); st = dbi_next(sub_iter)) { script->translation_buf[j++] = st->buf; } dbi_destroy(sub_iter); @@ -4887,8 +4957,8 @@ void script_load_translations(void) { /** * **/ -const char * script_get_translation_file_name(const char *file) { - static char file_name[200]; +const char *script_get_translation_file_name(const char *file) +{ int i, len = (int)strlen(file), last_bar = -1, last_dot = -1; for(i = 0; i < len; i++) { @@ -4899,6 +4969,7 @@ const char * script_get_translation_file_name(const char *file) { } if( last_bar != -1 || last_dot != -1 ) { + static char file_name[200]; if( last_bar != -1 && last_dot < last_bar ) last_dot = -1; safestrncpy(file_name, file+(last_bar >= 0 ? last_bar+1 : 0), ( last_dot >= 0 ? ( last_bar >= 0 ? last_dot - last_bar : last_dot ) : sizeof(file_name) )); @@ -4915,7 +4986,7 @@ void script_load_translation(const char *file, uint8 lang_id, uint32 *total) { uint32 translations = 0; char line[1024]; char msgctxt[NAME_LENGTH*2+1] = { 0 }; - DBMap *string_db; + struct DBMap *string_db; size_t i; FILE *fp; struct script_string_buf msgid = { 0 }, msgstr = { 0 }; @@ -4930,7 +5001,7 @@ void script_load_translation(const char *file, uint8 lang_id, uint32 *total) { atcommand->expand_message_table(); while(fgets(line, sizeof(line), fp)) { - size_t len = strlen(line), cursor = 0; + size_t len = strlen(line); if( len <= 1 ) continue; @@ -4939,6 +5010,7 @@ void script_load_translation(const char *file, uint8 lang_id, uint32 *total) { continue; if( strncasecmp(line,"msgctxt \"", 9) == 0 ) { + int cursor = 0; msgctxt[0] = '\0'; for(i = 9; i < len - 2; i++) { if( line[i] == '\\' && line[i+1] == '"' ) { @@ -4946,7 +5018,7 @@ void script_load_translation(const char *file, uint8 lang_id, uint32 *total) { i++; } else msgctxt[cursor] = line[i]; - if( ++cursor >= sizeof(msgctxt) - 1 ) + if (++cursor >= (int)sizeof(msgctxt) - 1) break; } msgctxt[cursor] = '\0'; @@ -5066,12 +5138,13 @@ void script_clear_translations(bool reload) { /** * **/ -int script_translation_db_destroyer(DBKey key, DBData *data, va_list ap) { - DBMap *string_db = DB->data2ptr(data); +int script_translation_db_destroyer(union DBKey key, struct DBData *data, va_list ap) +{ + struct DBMap *string_db = DB->data2ptr(data); if( db_size(string_db) ) { struct string_translation *st = NULL; - DBIterator *iter = db_iterator(string_db); + struct DBIterator *iter = db_iterator(string_db); for( st = dbi_first(iter); dbi_exists(iter); st = dbi_next(iter) ) { aFree(st); @@ -5141,6 +5214,7 @@ void do_init_script(bool minimal) { script->parse_builtin(); script->read_constdb(); + script->load_parameters(); script->hardcoded_constants(); if (minimal) @@ -5150,9 +5224,10 @@ void do_init_script(bool minimal) { script->load_translations(); } -int script_reload(void) { +int script_reload(void) +{ int i; - DBIterator *iter; + struct DBIterator *iter; struct script_state *st; #ifdef ENABLE_CASE_CHECK @@ -6291,7 +6366,7 @@ BUILDIN(jobchange) BUILDIN(jobname) { int class_=script_getnum(st,2); - script_pushconststr(st, (char*)pc->job_name(class_)); + script_pushconststr(st, pc->job_name(class_)); return true; } @@ -6340,16 +6415,13 @@ BUILDIN(input) } else { // take received text/value and store it in the designated variable sd->state.menu_or_input = 0; - if( is_string_variable(name) ) - { + if (is_string_variable(name)) { int len = (int)strlen(sd->npc_str); - script->set_reg(st, sd, uid, name, (void*)sd->npc_str, script_getref(st,2)); + script->set_reg(st, sd, uid, name, sd->npc_str, script_getref(st,2)); script_pushint(st, (len > max ? 1 : len < min ? -1 : 0)); - } - else - { + } else { int amount = sd->npc_amount; - script->set_reg(st, sd, uid, name, (void*)h64BPTRSIZE(cap_value(amount,min,max)), script_getref(st,2)); + script->set_reg(st, sd, uid, name, (const void *)h64BPTRSIZE(cap_value(amount,min,max)), script_getref(st,2)); script_pushint(st, (amount > max ? 1 : amount < min ? -1 : 0)); } st->state = RUN; @@ -6436,9 +6508,9 @@ BUILDIN(__setr) } if (is_string_variable(name)) - script->set_reg(st,sd,num,name,(void*)script_getstr(st,3),script_getref(st,2)); + script->set_reg(st, sd, num, name, script_getstr(st, 3), script_getref(st, 2)); else - script->set_reg(st,sd,num,name,(void*)h64BPTRSIZE(script_getnum(st,3)),script_getref(st,2)); + script->set_reg(st, sd, num, name, (const void *)h64BPTRSIZE(script_getnum(st, 3)), script_getref(st, 2)); return true; } @@ -6485,15 +6557,14 @@ BUILDIN(setarray) if( end > SCRIPT_MAX_ARRAYSIZE ) end = SCRIPT_MAX_ARRAYSIZE; - if( is_string_variable(name) ) - {// string array - for( i = 3; start < end; ++start, ++i ) - script->set_reg(st, sd, reference_uid(id, start), name, (void*)script_getstr(st,i), reference_getref(data)); - } - else - {// int array - for( i = 3; start < end; ++start, ++i ) - script->set_reg(st, sd, reference_uid(id, start), name, (void*)h64BPTRSIZE(script_getnum(st,i)), reference_getref(data)); + if (is_string_variable(name)) { + // string array + for (i = 3; start < end; ++start, ++i) + script->set_reg(st, sd, reference_uid(id, start), name, script_getstr(st, i), reference_getref(data)); + } else { + // int array + for (i = 3; start < end; ++start, ++i) + script->set_reg(st, sd, reference_uid(id, start), name, (const void *)h64BPTRSIZE(script_getnum(st, i)), reference_getref(data)); } return true; } @@ -6509,7 +6580,7 @@ BUILDIN(cleararray) uint32 start; uint32 end; int32 id; - void* v; + const void *v = NULL; struct map_session_data *sd = NULL; data = script_getdata(st, 2); @@ -6532,10 +6603,10 @@ BUILDIN(cleararray) return true;// no player attached } - if( is_string_variable(name) ) - v = (void*)script_getstr(st, 3); + if (is_string_variable(name)) + v = script_getstr(st, 3); else - v = (void*)h64BPTRSIZE(script_getnum(st, 3)); + v = (const void *)h64BPTRSIZE(script_getnum(st, 3)); end = start + script_getnum(st, 4); if( end > SCRIPT_MAX_ARRAYSIZE ) @@ -6560,7 +6631,6 @@ BUILDIN(copyarray) int32 idx2; int32 id1; int32 id2; - void* v; int32 i; uint32 count; struct map_session_data *sd = NULL; @@ -6608,20 +6678,25 @@ BUILDIN(copyarray) if( is_same_reference(data1, data2) && idx1 > idx2 ) { // destination might be overlapping the source - copy in reverse order for( i = count - 1; i >= 0; --i ) { - v = script->get_val2(st, reference_uid(id2, idx2 + i), reference_getref(data2)); - script->set_reg(st, sd, reference_uid(id1, idx1 + i), name1, v, reference_getref(data1)); + const void *value = script->get_val2(st, reference_uid(id2, idx2 + i), reference_getref(data2)); + script->set_reg(st, sd, reference_uid(id1, idx1 + i), name1, value, reference_getref(data1)); script_removetop(st, -1, 0); } } else { // normal copy for( i = 0; i < count; ++i ) { if( idx2 + i < SCRIPT_MAX_ARRAYSIZE ) { - v = script->get_val2(st, reference_uid(id2, idx2 + i), reference_getref(data2)); - script->set_reg(st, sd, reference_uid(id1, idx1 + i), name1, v, reference_getref(data1)); + const void *value = script->get_val2(st, reference_uid(id2, idx2 + i), reference_getref(data2)); + script->set_reg(st, sd, reference_uid(id1, idx1 + i), name1, value, reference_getref(data1)); script_removetop(st, -1, 0); } else { // out of range - assume ""/0 - script->set_reg(st, sd, reference_uid(id1, idx1 + i), name1, (is_string_variable(name1)?(void*)"":(void*)0), reference_getref(data1)); + const void *value; + if (is_string_variable(name1)) + value = ""; + else + value = (const void *)0; + script->set_reg(st, sd, reference_uid(id1, idx1 + i), name1, value, reference_getref(data1)); } } } @@ -6650,8 +6725,9 @@ BUILDIN(getarraysize) script_pushint(st, script->array_highest_key(st,st->rid ? script->rid2sd(st) : NULL,reference_getname(data),reference_getref(data))); return true; } -int script_array_index_cmp(const void *a, const void *b) { - return ( *(const unsigned int*)a - *(const unsigned int*)b ); +int script_array_index_cmp(const void *a, const void *b) +{ + return (*(const unsigned int *)a - *(const unsigned int *)b); // FIXME: Is the unsigned difference really intended here? } /// Deletes count or all the elements in an array, from the starting index. @@ -6724,7 +6800,7 @@ BUILDIN(deletearray) // Better to iterate directly on the array, no speed-up from using sa for( ; start + count < end; ++start ) { // Compact and overwrite - void* v = script->get_val2(st, reference_uid(id, start + count), reference_getref(data)); + const void *v = script->get_val2(st, reference_uid(id, start + count), reference_getref(data)); script->set_reg(st, sd, reference_uid(id, start), name, v, reference_getref(data)); script_removetop(st, -1, 0); } @@ -6748,7 +6824,7 @@ BUILDIN(deletearray) for( ; i < size && list[i] < end; i++ ) { // Move back count positions any entries between start+count to fill the gaps - void* v = script->get_val2(st, reference_uid(id, list[i]), reference_getref(data)); + const void *v = script->get_val2(st, reference_uid(id, list[i]), reference_getref(data)); script->set_reg(st, sd, reference_uid(id, list[i]-count), name, v, reference_getref(data)); script_removetop(st, -1, 0); // Clear their originals @@ -10012,6 +10088,7 @@ int buildin_killmonsterall_sub_strip(struct block_list *bl,va_list ap) struct mob_data *md; md = BL_CAST(BL_MOB, bl); + nullpo_ret(md); if (md->npc_event[0]) md->npc_event[0] = 0; @@ -10434,7 +10511,8 @@ BUILDIN(playerattached) { /*========================================== *------------------------------------------*/ -BUILDIN(announce) { +BUILDIN(announce) +{ const char *mes = script_getstr(st,2); int flag = script_getnum(st,3); const char *fontColor = script_hasdata(st,4) ? script_getstr(st,4) : NULL; @@ -10442,6 +10520,8 @@ BUILDIN(announce) { int fontSize = script_hasdata(st,6) ? script_getnum(st,6) : 12; // default fontSize int fontAlign = script_hasdata(st,7) ? script_getnum(st,7) : 0; // default fontAlign int fontY = script_hasdata(st,8) ? script_getnum(st,8) : 0; // default fontY + size_t len = strlen(mes); + Assert_retr(false, len < INT_MAX); if( flag&(BC_TARGET_MASK|BC_SOURCE_MASK) ) { // Broadcast source or broadcast region defined @@ -10466,14 +10546,14 @@ BUILDIN(announce) { } if (fontColor) - clif->broadcast2(bl, mes, (int)strlen(mes)+1, (unsigned int)strtoul(fontColor, (char **)NULL, 0), fontType, fontSize, fontAlign, fontY, target); + clif->broadcast2(bl, mes, (int)len+1, (unsigned int)strtoul(fontColor, (char **)NULL, 0), fontType, fontSize, fontAlign, fontY, target); else - clif->broadcast(bl, mes, (int)strlen(mes)+1, flag&BC_COLOR_MASK, target); + clif->broadcast(bl, mes, (int)len+1, flag&BC_COLOR_MASK, target); } else { if (fontColor) - intif->broadcast2(mes, (int)strlen(mes)+1, (unsigned int)strtoul(fontColor, (char **)NULL, 0), fontType, fontSize, fontAlign, fontY); + intif->broadcast2(mes, (int)len+1, (unsigned int)strtoul(fontColor, (char **)NULL, 0), fontType, fontSize, fontAlign, fontY); else - intif->broadcast(mes, (int)strlen(mes)+1, flag&BC_COLOR_MASK); + intif->broadcast(mes, (int)len+1, flag&BC_COLOR_MASK); } return true; } @@ -10481,10 +10561,10 @@ BUILDIN(announce) { *------------------------------------------*/ int buildin_announce_sub(struct block_list *bl, va_list ap) { - char *mes = va_arg(ap, char *); + const char *mes = va_arg(ap, const char *); int len = va_arg(ap, int); int type = va_arg(ap, int); - char *fontColor = va_arg(ap, char *); + const char *fontColor = va_arg(ap, const char *); short fontType = (short)va_arg(ap, int); short fontSize = (short)va_arg(ap, int); short fontAlign = (short)va_arg(ap, int); @@ -10531,7 +10611,8 @@ BUILDIN(itemeffect) return true; } -BUILDIN(mapannounce) { +BUILDIN(mapannounce) +{ const char *mapname = script_getstr(st,2); const char *mes = script_getstr(st,3); int flag = script_getnum(st,4); @@ -10541,17 +10622,20 @@ BUILDIN(mapannounce) { int fontAlign = script_hasdata(st,8) ? script_getnum(st,8) : 0; // default fontAlign int fontY = script_hasdata(st,9) ? script_getnum(st,9) : 0; // default fontY int16 m; + size_t len = strlen(mes); + Assert_retr(false, len < INT_MAX); if ((m = map->mapname2mapid(mapname)) < 0) return true; map->foreachinmap(script->buildin_announce_sub, m, BL_PC, - mes, strlen(mes)+1, flag&BC_COLOR_MASK, fontColor, fontType, fontSize, fontAlign, fontY); + mes, (int)len+1, flag&BC_COLOR_MASK, fontColor, fontType, fontSize, fontAlign, fontY); return true; } /*========================================== *------------------------------------------*/ -BUILDIN(areaannounce) { +BUILDIN(areaannounce) +{ const char *mapname = script_getstr(st,2); int x0 = script_getnum(st,3); int y0 = script_getnum(st,4); @@ -10565,12 +10649,14 @@ BUILDIN(areaannounce) { int fontAlign = script_hasdata(st,12) ? script_getnum(st,12) : 0; // default fontAlign int fontY = script_hasdata(st,13) ? script_getnum(st,13) : 0; // default fontY int16 m; + size_t len = strlen(mes); + Assert_retr(false, len < INT_MAX); if ((m = map->mapname2mapid(mapname)) < 0) return true; map->foreachinarea(script->buildin_announce_sub, m, x0, y0, x1, y1, BL_PC, - mes, strlen(mes)+1, flag&BC_COLOR_MASK, fontColor, fontType, fontSize, fontAlign, fontY); + mes, (int)len+1, flag&BC_COLOR_MASK, fontColor, fontType, fontSize, fontAlign, fontY); return true; } @@ -11008,9 +11094,9 @@ BUILDIN(getstatus) case 4: script_pushint(st, sd->sc.data[id]->val4); break; case 5: { - const struct TimerData* td = (const struct TimerData*)timer->get(sd->sc.data[id]->timer); + const struct TimerData *td = timer->get(sd->sc.data[id]->timer); - if( td ) { + if (td != NULL) { // return the amount of time remaining script_pushint(st, (int)(td->tick - timer->gettick())); // TODO: change this to int64 when we'll support 64 bit script values } @@ -13585,25 +13671,27 @@ BUILDIN(npcskilleffect) { * Special effects [Valaris] *------------------------------------------*/ BUILDIN(specialeffect) { - struct block_list *bl=map->id2bl(st->oid); + struct block_list *bl = NULL; int type = script_getnum(st,2); enum send_target target = script_hasdata(st,3) ? (send_target)script_getnum(st,3) : AREA; - if(bl==NULL) - return true; - if (script_hasdata(st,4)) { struct npc_data *nd = npc->name2id(script_getstr(st,4)); if (nd != NULL) - clif->specialeffect(&nd->bl, type, target); + bl = &nd->bl; } else { - if (target == SELF) { - struct map_session_data *sd = script->rid2sd(st); - if (sd != NULL) - clif->specialeffect_single(bl,type,sd->fd); - } else { - clif->specialeffect(bl, type, target); - } + bl = map->id2bl(st->oid); + } + + if (bl == NULL) + return true; + + if (target == SELF) { + struct map_session_data *sd = script->rid2sd(st); + if (sd != NULL) + clif->specialeffect_single(bl, type, sd->fd); + } else { + clif->specialeffect(bl, type, target); } return true; @@ -13707,7 +13795,7 @@ BUILDIN(dispbottom) int color = script_getnum(st,3); clif->messagecolor_self(sd->fd, color, message); } else { - clif_disp_onlyself(sd, message, (int)strlen(message)); + clif_disp_onlyself(sd, message); } return true; @@ -14359,7 +14447,7 @@ BUILDIN(getmapxy) sd=script->rid2sd(st); else sd=NULL; - script->set_reg(st,sd,num,name,(void*)mapname,script_getref(st,2)); + script->set_reg(st, sd, num, name, mapname, script_getref(st, 2)); //Set MapX num=st->stack->stack_data[st->start+3].u.num; @@ -14370,7 +14458,7 @@ BUILDIN(getmapxy) sd=script->rid2sd(st); else sd=NULL; - script->set_reg(st,sd,num,name,(void*)h64BPTRSIZE(x),script_getref(st,3)); + script->set_reg(st, sd, num, name, (const void *)h64BPTRSIZE(x), script_getref(st, 3)); //Set MapY num=st->stack->stack_data[st->start+4].u.num; @@ -14381,7 +14469,7 @@ BUILDIN(getmapxy) sd=script->rid2sd(st); else sd=NULL; - script->set_reg(st,sd,num,name,(void*)h64BPTRSIZE(y),script_getref(st,4)); + script->set_reg(st, sd, num, name, (const void *)h64BPTRSIZE(y), script_getref(st, 4)); //Return Success value script_pushint(st,0); @@ -15041,7 +15129,7 @@ BUILDIN(explode) if (str[i] == delimiter && (int64)start + k < (int64)(SCRIPT_MAX_ARRAYSIZE-1)) { // FIXME[Haru]: SCRIPT_MAX_ARRAYSIZE should really be unsigned (and INT32_MAX) //break at delimiter but ignore after reaching last array index temp[j] = '\0'; - script->set_reg(st, sd, reference_uid(id, start + k), name, (void*)temp, reference_getref(data)); + script->set_reg(st, sd, reference_uid(id, start + k), name, temp, reference_getref(data)); k++; j = 0; } else { @@ -15050,7 +15138,7 @@ BUILDIN(explode) } //set last string temp[j] = '\0'; - script->set_reg(st, sd, reference_uid(id, start + k), name, (void*)temp, reference_getref(data)); + script->set_reg(st, sd, reference_uid(id, start + k), name, temp, reference_getref(data)); aFree(temp); @@ -15111,7 +15199,7 @@ BUILDIN(implode) size_t len = 0, glue_len = 0, k = 0; const char *glue = NULL, *temp; for(i = 0; i <= array_size; ++i) { - temp = (char*) script->get_val2(st, reference_uid(id, i), reference_getref(data)); + temp = script->get_val2(st, reference_uid(id, i), reference_getref(data)); len += strlen(temp); script_removetop(st, -1, 0); } @@ -15126,7 +15214,7 @@ BUILDIN(implode) //build output for(i = 0; i < array_size; ++i) { - temp = (char*) script->get_val2(st, reference_uid(id, i), reference_getref(data)); + temp = script->get_val2(st, reference_uid(id, i), reference_getref(data)); len = strlen(temp); memcpy(&output[k], temp, len); k += len; @@ -15136,7 +15224,7 @@ BUILDIN(implode) } script_removetop(st, -1, 0); } - temp = (char*) script->get_val2(st, reference_uid(id, array_size), reference_getref(data)); + temp = script->get_val2(st, reference_uid(id, array_size), reference_getref(data)); len = strlen(temp); memcpy(&output[k], temp, len); k += len; @@ -15370,12 +15458,12 @@ BUILDIN(sscanf) { if(sscanf(str, buf, ref_str)==0) { break; } - script->set_reg(st, sd, reference_uid( reference_getid(data), reference_getindex(data) ), buf_p, (void *)(ref_str), reference_getref(data)); + script->set_reg(st, sd, reference_uid( reference_getid(data), reference_getindex(data) ), buf_p, ref_str, reference_getref(data)); } else { // Number if(sscanf(str, buf, &ref_int)==0) { break; } - script->set_reg(st, sd, reference_uid( reference_getid(data), reference_getindex(data) ), buf_p, (void *)h64BPTRSIZE(ref_int), reference_getref(data)); + script->set_reg(st, sd, reference_uid( reference_getid(data), reference_getindex(data) ), buf_p, (const void *)h64BPTRSIZE(ref_int), reference_getref(data)); } arg++; @@ -15815,8 +15903,8 @@ BUILDIN(swap) value2 = script_getstr(st,3); if (strcmpi(value1, value2)) { - script->set_reg(st, sd, uid1, varname1, (void*)(value2), script_getref(st,3)); - script->set_reg(st, sd, uid2, varname2, (void*)(value1), script_getref(st,2)); + script->set_reg(st, sd, uid1, varname1, value2, script_getref(st,3)); + script->set_reg(st, sd, uid2, varname2, value1, script_getref(st,2)); } } else { @@ -15826,8 +15914,8 @@ BUILDIN(swap) value2 = script_getnum(st,3); if (value1 != value2) { - script->set_reg(st, sd, uid1, varname1, (void*)h64BPTRSIZE(value2), script_getref(st,3)); - script->set_reg(st, sd, uid2, varname2, (void*)h64BPTRSIZE(value1), script_getref(st,2)); + script->set_reg(st, sd, uid1, varname1, (const void *)h64BPTRSIZE(value2), script_getref(st,3)); + script->set_reg(st, sd, uid2, varname2, (const void *)h64BPTRSIZE(value1), script_getref(st,2)); } } return true; @@ -15856,16 +15944,16 @@ BUILDIN(setd) } } - if( is_string_variable(varname) ) { - script->setd_sub(st, sd, varname, elem, (void *)script_getstr(st, 3), NULL); + if (is_string_variable(varname)) { + script->setd_sub(st, sd, varname, elem, script_getstr(st, 3), NULL); } else { - script->setd_sub(st, sd, varname, elem, (void *)h64BPTRSIZE(script_getnum(st, 3)), NULL); + script->setd_sub(st, sd, varname, elem, (const void *)h64BPTRSIZE(script_getnum(st, 3)), NULL); } return true; } -int buildin_query_sql_sub(struct script_state* st, Sql* handle) +int buildin_query_sql_sub(struct script_state *st, struct Sql *handle) { int i, j; struct map_session_data *sd = NULL; @@ -16404,7 +16492,7 @@ BUILDIN(checkchatting) { sd = script->rid2sd(st); if (sd != NULL) - script_pushint(st,(sd->chatID != 0)); + script_pushint(st, (sd->chat_id != 0)); else script_pushint(st,0); @@ -16481,7 +16569,7 @@ BUILDIN(searchitem) for( i = 0; i < count; ++start, ++i ) {// Set array - void* v = (void*)h64BPTRSIZE((int)items[i]->nameid); + const void *v = (const void *)h64BPTRSIZE((int)items[i]->nameid); script->set_reg(st, sd, reference_uid(id, start), name, v, reference_getref(data)); } @@ -16770,8 +16858,12 @@ BUILDIN(unittalk) { bl = map->id2bl(unit_id); if( bl != NULL ) { struct StringBuf sbuf; + char blname[NAME_LENGTH]; StrBuf->Init(&sbuf); - StrBuf->Printf(&sbuf, "%s : %s", status->get_name(bl), message); + safestrncpy(blname, clif->get_bl_name(bl), sizeof(blname)); + if(bl->type == BL_NPC) + strtok(blname, "#"); + StrBuf->Printf(&sbuf, "%s : %s", blname, message); clif->disp_overhead(bl, StrBuf->Value(&sbuf)); StrBuf->Destroy(&sbuf); } @@ -16924,8 +17016,9 @@ BUILDIN(sleep2) { /// Awakes all the sleep timers of the target npc /// /// awake "<npc name>"; -BUILDIN(awake) { - DBIterator *iter; +BUILDIN(awake) +{ + struct DBIterator *iter; struct script_state *tst; struct npc_data* nd; @@ -17937,7 +18030,8 @@ BUILDIN(instance_init) { return true; } -BUILDIN(instance_announce) { +BUILDIN(instance_announce) +{ int instance_id = script_getnum(st,2); const char *mes = script_getstr(st,3); int flag = script_getnum(st,4); @@ -17946,8 +18040,9 @@ BUILDIN(instance_announce) { int fontSize = script_hasdata(st,7) ? script_getnum(st,7) : 12; // default fontSize int fontAlign = script_hasdata(st,8) ? script_getnum(st,8) : 0; // default fontAlign int fontY = script_hasdata(st,9) ? script_getnum(st,9) : 0; // default fontY - int i; + size_t len = strlen(mes); + Assert_retr(false, len < INT_MAX); if( instance_id == -1 ) { if( st->instance_id >= 0 ) @@ -17961,7 +18056,7 @@ BUILDIN(instance_announce) { for( i = 0; i < instance->list[instance_id].num_map; i++ ) map->foreachinmap(script->buildin_announce_sub, instance->list[instance_id].map[i], BL_PC, - mes, strlen(mes)+1, flag&BC_COLOR_MASK, fontColor, fontType, fontSize, fontAlign, fontY); + mes, (int)len+1, flag&BC_COLOR_MASK, fontColor, fontType, fontSize, fontAlign, fontY); return true; } @@ -18551,22 +18646,11 @@ BUILDIN(getcharip) { return false; } - /* check for IP */ - if (!sockt->session[sd->fd]->client_addr) { + if (sd->fd == 0 || sockt->session[sd->fd] == NULL || sockt->session[sd->fd]->client_addr == 0) { script_pushconststr(st, ""); - return true; - } - - /* return the client ip_addr converted for output */ - if (sd && sd->fd && sockt->session[sd->fd]) - { - /* initiliaze */ - const char *ip_addr = NULL; - uint32 ip; - - /* set ip, ip_addr and convert to ip and push str */ - ip = sockt->session[sd->fd]->client_addr; - ip_addr = sockt->ip2str(ip, NULL); + } else { + uint32 ip = sockt->session[sd->fd]->client_addr; + const char *ip_addr = sockt->ip2str(ip, NULL); script_pushstrcopy(st, ip_addr); } @@ -18789,68 +18873,6 @@ BUILDIN(useatcmd) { return true; } -BUILDIN(checkre) -{ - int num; - - num=script_getnum(st,2); - switch(num) { - case 0: -#ifdef RENEWAL - script_pushint(st, 1); -#else - script_pushint(st, 0); -#endif - break; - case 1: -#ifdef RENEWAL_CAST - script_pushint(st, 1); -#else - script_pushint(st, 0); -#endif - break; - case 2: -#ifdef RENEWAL_DROP - script_pushint(st, 1); -#else - script_pushint(st, 0); -#endif - break; - case 3: -#ifdef RENEWAL_EXP - script_pushint(st, 1); -#else - script_pushint(st, 0); -#endif - break; - case 4: -#ifdef RENEWAL_LVDMG - script_pushint(st, 1); -#else - script_pushint(st, 0); -#endif - break; - case 5: -#ifdef RENEWAL_EDP - script_pushint(st, 1); -#else - script_pushint(st, 0); -#endif - break; - case 6: -#ifdef RENEWAL_ASPD - script_pushint(st, 1); -#else - script_pushint(st, 0); -#endif - break; - default: - ShowWarning("buildin_checkre: unknown parameter.\n"); - break; - } - return true; -} - /* getrandgroupitem <container_item_id>,<quantity> */ BUILDIN(getrandgroupitem) { struct item_data *data = NULL; @@ -19695,9 +19717,10 @@ BUILDIN(checkbound) /* bg_match_over( arena_name {, optional canceled } ) */ /* returns 0 when successful, 1 otherwise */ -BUILDIN(bg_match_over) { +BUILDIN(bg_match_over) +{ bool canceled = script_hasdata(st,3) ? true : false; - struct bg_arena *arena = bg->name2arena((const char*)script_getstr(st, 2)); + struct bg_arena *arena = bg->name2arena(script_getstr(st, 2)); if( arena ) { bg->match_over(arena,canceled); @@ -21098,6 +21121,7 @@ void script_defaults(void) { script->get_val_npc_num = get_val_npcscope_num; script->get_val_instance_num = get_val_instance_num; script->push_str = push_str; + script->push_conststr = push_conststr; script->push_copy = push_copy; script->pop_stack = pop_stack; script->set_constant = script_set_constant; @@ -21161,6 +21185,7 @@ void script_defaults(void) { script->parse_line = parse_line; script->read_constdb = read_constdb; script->constdb_comment = script_constdb_comment; + script->load_parameters = script_load_parameters; script->print_line = script_print_line; script->errorwarning_sub = script_errorwarning_sub; script->set_reg = set_reg; diff --git a/src/map/script.h b/src/map/script.h index 351ccd02a..a1fbe31f0 100644 --- a/src/map/script.h +++ b/src/map/script.h @@ -25,7 +25,6 @@ #include "common/hercules.h" #include "common/db.h" #include "common/mmo.h" // struct item -#include "common/sql.h" // Sql #include "common/strlib.h" //StringBuf #include <errno.h> @@ -34,6 +33,7 @@ /** * Declarations **/ +struct Sql; // common/sql.h struct eri; struct item_data; @@ -94,11 +94,11 @@ struct item_data; /// Pushes an int into the stack #define script_pushint(st,val) (script->push_val((st)->stack, C_INT, (val),NULL)) /// Pushes a string into the stack (script engine frees it automatically) -#define script_pushstr(st,val) (script->push_str((st)->stack, C_STR, (val))) +#define script_pushstr(st,val) (script->push_str((st)->stack, (val))) /// Pushes a copy of a string into the stack -#define script_pushstrcopy(st,val) (script->push_str((st)->stack, C_STR, aStrdup(val))) +#define script_pushstrcopy(st,val) (script->push_str((st)->stack, aStrdup(val))) /// Pushes a constant string into the stack (must never change or be freed) -#define script_pushconststr(st,val) (script->push_str((st)->stack, C_CONSTSTR, (val))) +#define script_pushconststr(st,val) (script->push_conststr((st)->stack, (val))) /// Pushes a nil into the stack #define script_pushnil(st) (script->push_val((st)->stack, C_NOP, 0,NULL)) /// Pushes a copy of the data in the target index @@ -380,14 +380,18 @@ struct script_retinfo { int defsp; ///< default stack pointer }; +/** + * Represents a variable in the script stack. + */ struct script_data { - enum c_op type; + enum c_op type; ///< Data type union script_data_val { - int64 num; - char *str; - struct script_retinfo* ri; - } u; - struct reg_db *ref; + int64 num; ///< Numeric data + char *mutstr; ///< Mutable string + const char *str; ///< Constant string + struct script_retinfo *ri; ///< Function return information + } u; ///< Data (field depends on `type`) + struct reg_db *ref; ///< Reference to the scope's variables }; // Moved defsp from script_state to script_stack since @@ -490,8 +494,8 @@ struct script_syntax_data { int last_func; // buildin index of the last parsed function unsigned int nested_call; //Dont really know what to call this bool lang_macro_active; - DBMap *strings; // string map parsed (used when exporting strings only) - DBMap *translation_db; //non-null if this npc has any translated strings to be linked + struct DBMap *strings; // string map parsed (used when exporting strings only) + struct DBMap *translation_db; //non-null if this npc has any translated strings to be linked }; struct casecheck_data { @@ -530,7 +534,7 @@ struct string_translation { **/ struct script_interface { /* */ - DBMap *st_db; + struct DBMap *st_db; unsigned int active_scripts; unsigned int next_id; struct eri *st_ers; @@ -598,8 +602,8 @@ struct script_interface { /* */ /* Caches compiled autoscript item code. */ /* Note: This is not cleared when reloading itemdb. */ - DBMap* autobonus_db; // char* script -> char* bytecode - DBMap* userfunc_db; // const char* func_name -> struct script_code* + struct DBMap *autobonus_db; // char* script -> char* bytecode + struct DBMap *userfunc_db; // const char* func_name -> struct script_code* /* */ int potion_flag; //For use on Alchemist improved potions/Potion Pitcher. [Skotlex] int potion_hp, potion_per_hp, potion_sp, potion_per_sp; @@ -617,7 +621,7 @@ struct script_interface { int buildin_select_offset; int buildin_lang_macro_offset; /* */ - DBMap *translation_db;/* npc_name => DBMap (strings) */ + struct DBMap *translation_db;/* npc_name => DBMap (strings) */ char **translation_buf;/* */ uint32 translation_buf_size; /* */ @@ -660,9 +664,10 @@ struct script_interface { int (*get_val_scope_num) (struct script_state* st, struct reg_db *n, struct script_data* data); int (*get_val_npc_num) (struct script_state* st, struct reg_db *n, struct script_data* data); int (*get_val_instance_num) (struct script_state* st, const char* name, struct script_data* data); - void* (*get_val2) (struct script_state* st, int64 uid, struct reg_db *ref); - struct script_data* (*push_str) (struct script_stack* stack, enum c_op type, char* str); - struct script_data* (*push_copy) (struct script_stack* stack, int pos); + const void *(*get_val2) (struct script_state *st, int64 uid, struct reg_db *ref); + struct script_data *(*push_str) (struct script_stack *stack, char *str); + struct script_data *(*push_conststr) (struct script_stack *stack, const char *str); + struct script_data *(*push_copy) (struct script_stack *stack, int pos); void (*pop_stack) (struct script_state* st, int start, int end); void (*set_constant) (const char *name, int value, bool is_parameter, bool is_deprecated); void (*set_constant2) (const char *name, int value, bool is_parameter, bool is_deprecated); @@ -687,7 +692,7 @@ struct script_interface { int (*add_str) (const char* p); const char* (*get_str) (int id); int (*search_str) (const char* p); - void (*setd_sub) (struct script_state *st, struct map_session_data *sd, const char *varname, int elem, void *value, struct reg_db *ref); + void (*setd_sub) (struct script_state *st, struct map_session_data *sd, const char *varname, int elem, const void *value, struct reg_db *ref); void (*attach_state) (struct script_state* st); /* */ struct script_queue *(*queue) (int idx); @@ -725,6 +730,7 @@ struct script_interface { const char* (*parse_line) (const char *p); void (*read_constdb) (void); void (*constdb_comment) (const char *comment); + void (*load_parameters) (void); const char* (*print_line) (StringBuf *buf, const char *p, const char *mark, int line); void (*errorwarning_sub) (StringBuf *buf, const char *src, const char *file, int start_line, const char *error_msg, const char *error_pos); int (*set_reg) (struct script_state *st, struct map_session_data *sd, int64 num, const char *name, const void *value, struct reg_db *ref); @@ -745,7 +751,7 @@ struct script_interface { void (*op_1) (struct script_state *st, int op); void (*check_buildin_argtype) (struct script_state *st, int func); void (*detach_state) (struct script_state *st, bool dequeue_event); - int (*db_free_code_sub) (DBKey key, DBData *data, va_list ap); + int (*db_free_code_sub) (union DBKey key, struct DBData *data, va_list ap); void (*add_autobonus) (const char *autobonus); int (*menu_countoptions) (const char *str, int max_count, int *total); int (*buildin_areawarp_sub) (struct block_list *bl, va_list ap); @@ -767,7 +773,7 @@ struct script_interface { int (*playbgm_sub) (struct block_list *bl, va_list ap); int (*playbgm_foreachpc_sub) (struct map_session_data *sd, va_list args); int (*soundeffect_sub) (struct block_list *bl, va_list ap); - int (*buildin_query_sql_sub) (struct script_state *st, Sql *handle); + int (*buildin_query_sql_sub) (struct script_state *st, struct Sql *handle); int (*buildin_instance_warpall_sub) (struct block_list *bl, va_list ap); int (*buildin_mobuseskill_sub) (struct block_list *bl, va_list ap); int (*cleanfloor_sub) (struct block_list *bl, va_list ap); @@ -788,11 +794,11 @@ struct script_interface { void (*array_add_member) (struct script_array *sa, unsigned int idx); unsigned int (*array_size) (struct script_state *st, struct map_session_data *sd, const char *name, struct reg_db *ref); unsigned int (*array_highest_key) (struct script_state *st, struct map_session_data *sd, const char *name, struct reg_db *ref); - int (*array_free_db) (DBKey key, DBData *data, va_list ap); + int (*array_free_db) (union DBKey key, struct DBData *data, va_list ap); void (*array_ensure_zero) (struct script_state *st, struct map_session_data *sd, int64 uid, struct reg_db *ref); /* */ void (*reg_destroy_single) (struct map_session_data *sd, int64 reg, struct script_reg_state *data); - int (*reg_destroy) (DBKey key, DBData *data, va_list ap); + int (*reg_destroy) (union DBKey key, struct DBData *data, va_list ap); /* */ void (*generic_ui_array_expand) (unsigned int plus); unsigned int *(*array_cpy_list) (struct script_array *sa); @@ -802,7 +808,7 @@ struct script_interface { int (*string_dup) (char *str); void (*load_translations) (void); void (*load_translation) (const char *file, uint8 lang_id, uint32 *total); - int (*translation_db_destroyer) (DBKey key, DBData *data, va_list ap); + int (*translation_db_destroyer) (union DBKey key, struct DBData *data, va_list ap); void (*clear_translations) (bool reload); int (*parse_cleanup_timer) (int tid, int64 tick, int id, intptr_t data); uint8 (*add_language) (const char *name); diff --git a/src/map/skill.c b/src/map/skill.c index de5368cdf..51d0792e3 100644 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -7505,7 +7505,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin memset(&item_tmp,0,sizeof(item_tmp)); item_tmp.nameid = skill->dbs->db[su->group->skill_id].itemid[i]; item_tmp.identify = 1; - if (item_tmp.nameid && (success=pc->additem(sd,&item_tmp,skill->dbs->db[su->group->skill_id].amount[i],LOG_TYPE_OTHER)) != 0) { + if (item_tmp.nameid && (success=pc->additem(sd,&item_tmp,skill->dbs->db[su->group->skill_id].amount[i],LOG_TYPE_SKILL)) != 0) { clif->additem(sd,0,0,success); map->addflooritem(&sd->bl, &item_tmp, skill->dbs->db[su->group->skill_id].amount[i], sd->bl.m, sd->bl.x, sd->bl.y, 0, 0, 0, 0); } @@ -7517,7 +7517,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin memset(&item_tmp,0,sizeof(item_tmp)); item_tmp.nameid = su->group->item_id?su->group->item_id:ITEMID_TRAP; item_tmp.identify = 1; - if (item_tmp.nameid && (flag=pc->additem(sd,&item_tmp,1,LOG_TYPE_OTHER)) != 0) { + if (item_tmp.nameid && (flag=pc->additem(sd,&item_tmp,1,LOG_TYPE_SKILL)) != 0) { clif->additem(sd,0,0,flag); map->addflooritem(&sd->bl, &item_tmp, 1, sd->bl.m, sd->bl.x, sd->bl.y, 0, 0, 0, 0); } @@ -9280,7 +9280,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin improv_skill_lv = 4 + skill_lv; clif->skill_nodamage (src, bl, skill_id, skill_lv, 1); - if (sd == NULL) { + if (sd != NULL) { sd->state.abra_flag = 2; sd->skillitem = improv_skill_id; sd->skillitemlv = improv_skill_lv; @@ -9667,7 +9667,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin if(sd) { struct mob_data *summon_md; - summon_md = mob->once_spawn_sub(src, src->m, src->x, src->y, status->get_name(src), MOBID_KO_KAGE, "", SZ_SMALL, AI_NONE); + summon_md = mob->once_spawn_sub(src, src->m, src->x, src->y, clif->get_bl_name(src), MOBID_KO_KAGE, "", SZ_SMALL, AI_NONE); if( summon_md ) { summon_md->master_id = src->id; summon_md->special_state.ai = AI_ZANZOU; @@ -9847,7 +9847,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin break; for (i = 0; i < summons[skill_lv-1].quantity; i++) { - struct mob_data *summon_md = mob->once_spawn_sub(src, src->m, src->x, src->y, status->get_name(src), + struct mob_data *summon_md = mob->once_spawn_sub(src, src->m, src->x, src->y, clif->get_bl_name(src), summons[skill_lv-1].mob_id, "", SZ_SMALL, AI_ATTACK); if (summon_md != NULL) { summon_md->master_id = src->id; @@ -10588,7 +10588,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui } // Correct info, don't change any of this! [Celest] - md = mob->once_spawn_sub(src, src->m, x, y, status->get_name(src), class_, "", SZ_SMALL, AI_NONE); + md = mob->once_spawn_sub(src, src->m, x, y, clif->get_bl_name(src), class_, "", SZ_SMALL, AI_NONE); if (md) { md->master_id = src->id; md->special_state.ai = (skill_id == AM_SPHEREMINE) ? AI_SPHERE : AI_FLORA; @@ -10833,7 +10833,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui case NC_SILVERSNIPER: { - struct mob_data *md = mob->once_spawn_sub(src, src->m, x, y, status->get_name(src), MOBID_SILVERSNIPER, "", SZ_SMALL, AI_NONE); + struct mob_data *md = mob->once_spawn_sub(src, src->m, x, y, clif->get_bl_name(src), MOBID_SILVERSNIPER, "", SZ_SMALL, AI_NONE); if (md) { md->master_id = src->id; md->special_state.ai = AI_FLORA; @@ -11716,7 +11716,7 @@ int skill_unit_onplace(struct skill_unit *src, struct block_list *bl, int64 tick if (bl->type == BL_PC && !working) { struct map_session_data *sd = BL_UCAST(BL_PC, bl); - if ((!sd->chatID || battle_config.chat_warpportal) && sd->ud.to_x == src->bl.x && sd->ud.to_y == src->bl.y) { + if ((sd->chat_id == 0 || battle_config.chat_warpportal) && sd->ud.to_x == src->bl.x && sd->ud.to_y == src->bl.y) { int x = sg->val2>>16; int y = sg->val2&0xffff; int count = sg->val1>>16; @@ -13122,7 +13122,8 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id nullpo_ret(sd); - if (sd->chatID) return 0; + if (sd->chat_id != 0) + return 0; if (pc_has_permission(sd, PC_PERM_SKILL_UNCONDITIONAL) && sd->skillitem != skill_id) { //GMs don't override the skillItem check, otherwise they can use items without them being consumed! [Skotlex] @@ -14088,7 +14089,7 @@ int skill_check_condition_castend(struct map_session_data* sd, uint16 skill_id, nullpo_ret(sd); - if( sd->chatID ) + if (sd->chat_id != 0) return 0; if( pc_has_permission(sd, PC_PERM_SKILL_UNCONDITIONAL) && sd->skillitem != skill_id ) { @@ -15313,12 +15314,12 @@ void skill_weaponrefine (struct map_session_data *sd, int idx) else per += 5 * ((signed int)sd->status.job_level - 50); - pc->delitem(sd, i, 1, 0, DELITEM_NORMAL, LOG_TYPE_OTHER); // FIXME: is this the correct reason flag? + pc->delitem(sd, i, 1, 0, DELITEM_NORMAL, LOG_TYPE_REFINE); // FIXME: is this the correct reason flag? if (per > rnd() % 1000) { int ep = 0; - logs->pick_pc(sd, LOG_TYPE_OTHER, -1, item, ditem); + logs->pick_pc(sd, LOG_TYPE_REFINE, -1, item, ditem); item->refine++; - logs->pick_pc(sd, LOG_TYPE_OTHER, 1, item, ditem); + logs->pick_pc(sd, LOG_TYPE_REFINE, 1, item, ditem); if(item->equip) { ep = item->equip; pc->unequipitem(sd, idx, PCUNEQUIPITEM_RECALC|PCUNEQUIPITEM_FORCE); @@ -15351,7 +15352,7 @@ void skill_weaponrefine (struct map_session_data *sd, int idx) if(item->equip) pc->unequipitem(sd, idx, PCUNEQUIPITEM_RECALC|PCUNEQUIPITEM_FORCE); clif->refine(sd->fd,1,idx,item->refine); - pc->delitem(sd, idx, 1, 0, DELITEM_NORMAL, LOG_TYPE_OTHER); + pc->delitem(sd, idx, 1, 0, DELITEM_NORMAL, LOG_TYPE_REFINE); clif->misceffect(&sd->bl,2); clif->emotion(&sd->bl, E_OMG); } @@ -15994,14 +15995,14 @@ int skill_enchant_elemental_end (struct block_list *bl, int type) { bool skill_check_cloaking(struct block_list *bl, struct status_change_entry *sce) { - static int dx[] = { 0, 1, 0, -1, -1, 1, 1, -1}; - static int dy[] = {-1, 0, 1, 0, -1, -1, 1, 1}; bool wall = true; if( (bl->type == BL_PC && battle_config.pc_cloak_check_type&1) || (bl->type != BL_PC && battle_config.monster_cloak_check_type&1) ) { //Check for walls. + static int dx[] = { 0, 1, 0, -1, -1, 1, 1, -1}; + static int dy[] = {-1, 0, 1, 0, -1, -1, 1, 1}; int i; ARR_FIND( 0, 8, i, map->getcell(bl->m, bl, bl->x+dx[i], bl->y+dy[i], CELL_CHKNOPASS) != 0 ); if( i == 8 ) @@ -16059,11 +16060,11 @@ int skill_check_cloaking_end(struct block_list *bl, va_list ap) bool skill_check_camouflage(struct block_list *bl, struct status_change_entry *sce) { - static int dx[] = { 0, 1, 0, -1, -1, 1, 1, -1}; - static int dy[] = {-1, 0, 1, 0, -1, -1, 1, 1}; bool wall = true; if( bl->type == BL_PC ) { //Check for walls. + static int dx[] = { 0, 1, 0, -1, -1, 1, 1, -1}; + static int dy[] = {-1, 0, 1, 0, -1, -1, 1, 1}; int i; ARR_FIND( 0, 8, i, map->getcell(bl->m, bl, bl->x+dx[i], bl->y+dy[i], CELL_CHKNOPASS) != 0 ); if( i == 8 ) @@ -16554,7 +16555,8 @@ int skill_unit_timer_sub_onplace(struct block_list* bl, va_list ap) { /** * @see DBApply */ -int skill_unit_timer_sub(DBKey key, DBData *data, va_list ap) { +int skill_unit_timer_sub(union DBKey key, struct DBData *data, va_list ap) +{ struct skill_unit* su = DB->data2ptr(data); struct skill_unit_group* group = su->group; int64 tick = va_arg(ap,int64); diff --git a/src/map/skill.h b/src/map/skill.h index fb2acfb62..35fddafa4 100644 --- a/src/map/skill.h +++ b/src/map/skill.h @@ -1856,12 +1856,12 @@ struct skill_interface { void (*reload) (void); void (*read_db) (bool minimal); /* */ - DBMap* cd_db; // char_id -> struct skill_cd - DBMap* name2id_db; - DBMap* unit_db; // int id -> struct skill_unit* - DBMap* usave_db; // char_id -> struct skill_unit_save - DBMap* group_db;// int group_id -> struct skill_unit_group* - DBMap* bowling_db;// int mob_id -> struct mob_data*s + struct DBMap *cd_db; // char_id -> struct skill_cd + struct DBMap *name2id_db; + struct DBMap *unit_db; // int id -> struct skill_unit* + struct DBMap *usave_db; // char_id -> struct skill_unit_save + struct DBMap *group_db;// int group_id -> struct skill_unit_group* + struct DBMap *bowling_db;// int mob_id -> struct mob_data*s /* */ struct eri *unit_ers; //For handling skill_unit's [Skotlex] struct eri *timer_ers; //For handling skill_timerskills [Skotlex] @@ -2031,7 +2031,7 @@ struct skill_interface { int (*blockmerc_end) (int tid, int64 tick, int id, intptr_t data); int (*split_atoi) (char *str, int *val); int (*unit_timer) (int tid, int64 tick, int id, intptr_t data); - int (*unit_timer_sub) (DBKey key, DBData *data, va_list ap); + int (*unit_timer_sub) (union DBKey key, struct DBData *data, va_list ap); void (*init_unit_layout) (void); bool (*parse_row_skilldb) (char* split[], int columns, int current); bool (*parse_row_requiredb) (char* split[], int columns, int current); diff --git a/src/map/status.c b/src/map/status.c index 82c427317..34bfd06b5 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -2255,7 +2255,8 @@ int status_calc_pet_(struct pet_data *pd, enum e_status_calc_opt opt) return 1; } -unsigned int status_get_base_maxsp(struct map_session_data* sd, struct status_data *st) { +unsigned int status_get_base_maxsp(const struct map_session_data *sd, const struct status_data *st) +{ uint64 val = pc->class2idx(sd->status.class_); val = status->dbs->SP_table[val][sd->status.base_level]; @@ -2272,7 +2273,8 @@ unsigned int status_get_base_maxsp(struct map_session_data* sd, struct status_da return (unsigned int)cap_value(val, 0, UINT_MAX); } -unsigned int status_get_base_maxhp(struct map_session_data *sd, struct status_data *st) { +unsigned int status_get_base_maxhp(const struct map_session_data *sd, const struct status_data *st) +{ uint64 val = pc->class2idx(sd->status.class_); val = status->dbs->HP_table[val][sd->status.base_level]; @@ -2718,7 +2720,7 @@ int status_calc_pc_(struct map_session_data* sd, enum e_status_calc_opt opt) { // Base batk value is set on status->calc_misc // weapon-type bonus (FIXME: Why is the weapon_atk bonus applied to base attack?) - if (sd->status.weapon < MAX_WEAPON_TYPE && sd->weapon_atk[sd->status.weapon]) + if (sd->status.weapon < MAX_SINGLE_WEAPON_TYPE && sd->weapon_atk[sd->status.weapon]) bstatus->batk += sd->weapon_atk[sd->status.weapon]; // Absolute modifiers from passive skills #ifndef RENEWAL @@ -3518,10 +3520,18 @@ void status_calc_regen_rate(struct block_list *bl, struct regen_data *regen, str regen->flag &=~RGN_SP; //No natural SP regen } + + // Tension relax allows the user to recover HP while overweight + // at 1x speed. Other SC ignored? [csnv] if (sc->data[SC_TENSIONRELAX]) { - regen->rate.hp += 2; - if (regen->sregen) - regen->sregen->rate.hp += 3; + if (sc->data[SC_WEIGHTOVER50] || sc->data[SC_WEIGHTOVER90]) { + regen->flag &= ~RGN_SP; + regen->rate.hp = 1; + } else { + regen->rate.hp += 2; + if (regen->sregen) + regen->sregen->rate.hp += 3; + } } if (sc->data[SC_MAGNIFICAT]) { @@ -4189,10 +4199,10 @@ int status_base_amotion_pc(struct map_session_data *sd, struct status_data *st) float temp; int skill_lv, val = 0; amotion = status->dbs->aspd_base[pc->class2idx(sd->status.class_)][sd->weapontype1]; - if ( sd->status.weapon > MAX_WEAPON_TYPE ) + if ( sd->status.weapon > MAX_SINGLE_WEAPON_TYPE) amotion += status->dbs->aspd_base[pc->class2idx(sd->status.class_)][sd->weapontype2] / 4; if ( sd->status.shield ) - amotion += status->dbs->aspd_base[pc->class2idx(sd->status.class_)][MAX_WEAPON_TYPE]; + amotion += status->dbs->aspd_base[pc->class2idx(sd->status.class_)][MAX_SINGLE_WEAPON_TYPE]; switch ( sd->status.weapon ) { case W_BOW: case W_MUSICAL: @@ -4215,7 +4225,7 @@ int status_base_amotion_pc(struct map_session_data *sd, struct status_data *st) amotion = ((int)(temp + ((float)(status->calc_aspd(&sd->bl, &sd->sc, 1) + val) * st->agi / 200)) - min(amotion, 200)); #else // base weapon delay - amotion = (sd->status.weapon < MAX_WEAPON_TYPE) + amotion = (sd->status.weapon < MAX_SINGLE_WEAPON_TYPE) ? (status->dbs->aspd_base[pc->class2idx(sd->status.class_)][sd->status.weapon]) // single weapon : (status->dbs->aspd_base[pc->class2idx(sd->status.class_)][sd->weapontype1] + status->dbs->aspd_base[pc->class2idx(sd->status.class_)][sd->weapontype2]) * 7 / 10; // dual-wield @@ -5566,9 +5576,9 @@ unsigned short status_calc_speed(struct block_list *bl, struct status_change *sc { int val = 0; - if( sd && sc->data[SC_HIDING] && pc->checkskill(sd,RG_TUNNELDRIVE) > 0 ) + if ( sd && sc->data[SC_HIDING] && pc->checkskill(sd,RG_TUNNELDRIVE) > 0 ) { val = 120 - 6 * pc->checkskill(sd,RG_TUNNELDRIVE); - else + } else { if( sd && sc->data[SC_CHASEWALK] && sc->data[SC_CHASEWALK]->val3 < 0 ) val = sc->data[SC_CHASEWALK]->val3; else @@ -5638,8 +5648,8 @@ unsigned short status_calc_speed(struct block_list *bl, struct status_change *sc if( sd && sd->bonus.speed_rate + sd->bonus.speed_add_rate > 0 ) // permanent item-based speedup val = max( val, sd->bonus.speed_rate + sd->bonus.speed_add_rate ); } - - speed_rate += val; + } + speed_rate += val; } //GetMoveHasteValue1() @@ -6241,7 +6251,13 @@ uint32 status_calc_mode(const struct block_list *bl, const struct status_change return mode & MD_MASK; } -const char *status_get_name(struct block_list *bl) +/** + * Returns the name of the given bl. + * + * @param bl The requested bl. + * @return The bl's name or NULL if not available. + */ +const char *status_get_name(const struct block_list *bl) { nullpo_ret(bl); switch (bl->type) { @@ -6257,7 +6273,7 @@ const char *status_get_name(struct block_list *bl) case BL_HOM: return BL_UCCAST(BL_HOM, bl)->homunculus.name; case BL_NPC: return BL_UCCAST(BL_NPC, bl)->name; } - return "Unknown"; + return NULL; } /*========================================== @@ -6266,7 +6282,7 @@ const char *status_get_name(struct block_list *bl) * 0 = fail * class_id = success *------------------------------------------*/ -int status_get_class(struct block_list *bl) +int status_get_class(const struct block_list *bl) { nullpo_ret(bl); switch (bl->type) { @@ -6286,7 +6302,7 @@ int status_get_class(struct block_list *bl) * 1 = fail * level = success *------------------------------------------*/ -int status_get_lv(struct block_list *bl) +int status_get_lv(const struct block_list *bl) { nullpo_ret(bl); switch (bl->type) { @@ -6376,7 +6392,8 @@ unsigned short status_get_speed(struct block_list *bl) return status->get_status_data(bl)->speed; } -int status_get_party_id(struct block_list *bl) { +int status_get_party_id(const struct block_list *bl) +{ nullpo_ret(bl); switch (bl->type) { case BL_PC: @@ -6431,7 +6448,7 @@ int status_get_party_id(struct block_list *bl) { return 0; } -int status_get_guild_id(struct block_list *bl) +int status_get_guild_id(const struct block_list *bl) { nullpo_ret(bl); switch (bl->type) { @@ -6497,7 +6514,8 @@ int status_get_guild_id(struct block_list *bl) return 0; } -int status_get_emblem_id(struct block_list *bl) { +int status_get_emblem_id(const struct block_list *bl) +{ nullpo_ret(bl); switch (bl->type) { case BL_PC: @@ -6558,7 +6576,7 @@ int status_get_emblem_id(struct block_list *bl) { return 0; } -int status_get_mexp(struct block_list *bl) +int status_get_mexp(const struct block_list *bl) { nullpo_ret(bl); if (bl->type == BL_MOB) @@ -6568,7 +6586,7 @@ int status_get_mexp(struct block_list *bl) return 0; } -int status_get_race2(struct block_list *bl) +int status_get_race2(const struct block_list *bl) { nullpo_ret(bl); if (bl->type == BL_MOB) @@ -7477,8 +7495,9 @@ int status_change_start(struct block_list *src, struct block_list *bl, enum sc_t if (tick == 1) return 1; //Minimal duration: Only strip without causing the SC break; case SC_NOEQUIPSHIELD: - if( val2 == 1 ) val2 = 0; //GX effect. Do not take shield off.. - else + if (val2 == 1) { + val2 = 0; //GX effect. Do not take shield off.. + } else { if (sd && !(flag&SCFLAG_LOADED)) { int i; if(sd->bonus.unstripable_equip&EQP_SHIELD) @@ -7488,8 +7507,10 @@ int status_change_start(struct block_list *src, struct block_list *bl, enum sc_t return 0; pc->unequipitem(sd, i, PCUNEQUIPITEM_RECALC|PCUNEQUIPITEM_FORCE); } - if (tick == 1) return 1; //Minimal duration: Only strip without causing the SC - break; + } + if (tick == 1) + return 1; //Minimal duration: Only strip without causing the SC + break; case SC_NOEQUIPARMOR: if (sd && !(flag&SCFLAG_LOADED)) { int i; @@ -11592,7 +11613,7 @@ int status_change_timer(int tid, int64 tick, int id, intptr_t data) { if( --(sce->val4) > 0 ) { struct block_list *src = map->id2bl(sce->val2); int damage; - if( !src || (src && (status->isdead(src) || src->m != bl->m || distance_bl(src, bl) >= 12)) ) + if (src == NULL || (status->isdead(src) || src->m != bl->m || distance_bl(src, bl) >= 12)) break; map->freeblock_lock(); damage = sce->val3; @@ -12432,8 +12453,10 @@ int status_natural_heal(struct block_list* bl, va_list args) { } } - if (flag && regen->state.overweight) - flag=0; + // SC_TENSIONRELAX allows HP to be recovered even when overweight. [csnv] + if (flag && regen->state.overweight && (sc == NULL || sc->data[SC_TENSIONRELAX] == NULL)) { + flag = 0; + } ud = unit->bl2ud(bl); @@ -12603,7 +12626,7 @@ void status_read_job_db_sub(int idx, const char *name, struct config_setting_t * { "FuumaShuriken", W_HUUMA }, { "TwoHandRod", W_2HSTAFF }, #ifdef RENEWAL_ASPD - { "Shield", MAX_WEAPON_TYPE } + { "Shield", MAX_SINGLE_WEAPON_TYPE } #endif }; @@ -12941,7 +12964,7 @@ int status_readdb_refine_libconfig(const char *filename) { struct config_t refine_db_conf; struct config_setting_t *r; char filepath[256]; - int i = 0, count = 0,type = 0; + int i = 0, count = 0; sprintf(filepath, "%s/%s", map->db_path, filename); if (!libconfig->load_file(&refine_db_conf, filepath)) @@ -12951,10 +12974,13 @@ int status_readdb_refine_libconfig(const char *filename) { while((r = libconfig->setting_get_elem(refine_db_conf.root,i++))) { char *name = config_setting_name(r); - if((type=status->readdb_refine_libconfig_sub(r, name, filename))) { - if( duplicate[type-1] ) { + int type = status->readdb_refine_libconfig_sub(r, name, filename); + if (type != 0) { + if (duplicate[type-1]) { ShowWarning("status_readdb_refine_libconfig: duplicate entry for %s in \"%s\", overwriting previous entry...\n", name, filename); - } else duplicate[type-1] = true; + } else { + duplicate[type-1] = true; + } count++; } } @@ -12999,10 +13025,10 @@ int status_readdb(void) memset(status->dbs->job_bonus,0,sizeof(status->dbs->job_bonus)); // Job-specific stats bonus } for ( i = 0; i < CLASS_COUNT; i++ ) { - for ( j = 0; j < MAX_WEAPON_TYPE; j++ ) + for ( j = 0; j < MAX_SINGLE_WEAPON_TYPE; j++ ) status->dbs->aspd_base[i][j] = 2000; #ifdef RENEWAL_ASPD - status->dbs->aspd_base[i][MAX_WEAPON_TYPE] = 0; + status->dbs->aspd_base[i][MAX_SINGLE_WEAPON_TYPE] = 0; #endif } diff --git a/src/map/status.h b/src/map/status.h index 4e2f1bdc0..2b932b149 100644 --- a/src/map/status.h +++ b/src/map/status.h @@ -1789,9 +1789,13 @@ enum si_type { //SI_DORAM_BUF_01 = 935, //SI_DORAM_BUF_02 = 936, //SI_SPRITEMABLE = 937, + //SI_EP16_2_BUFF_SS = 963, + //SI_EP16_2_BUFF_SC = 964, + //SI_EP16_2_BUFF_AC = 965, SI_MAX, }; + // JOINTBEAT stackable ailments enum e_joint_break { @@ -1804,7 +1808,6 @@ enum e_joint_break BREAK_FLAGS = BREAK_ANKLE | BREAK_WRIST | BREAK_KNEE | BREAK_SHOULDER | BREAK_WAIST | BREAK_NECK, }; - /** * Mob mode definitions. [Skotlex] * @@ -2159,7 +2162,7 @@ BEGIN_ZEROED_BLOCK; /* Everything within this block will be memset to 0 when sta int max_weight_base[CLASS_COUNT]; int HP_table[CLASS_COUNT][MAX_LEVEL + 1]; int SP_table[CLASS_COUNT][MAX_LEVEL + 1]; - int aspd_base[CLASS_COUNT][MAX_WEAPON_TYPE+1]; // +1 for RENEWAL_ASPD + int aspd_base[CLASS_COUNT][MAX_SINGLE_WEAPON_TYPE+1]; // +1 for RENEWAL_ASPD sc_type Skill2SCTable[MAX_SKILL]; // skill -> status int IconChangeTable[SC_MAX]; // status -> "icon" (icon is a bit of a misnomer, since there exist values with no icon associated) unsigned int ChangeFlagTable[SC_MAX]; // status -> flags @@ -2216,17 +2219,17 @@ struct status_interface { struct regen_data * (*get_regen_data) (struct block_list *bl); struct status_data * (*get_status_data) (struct block_list *bl); struct status_data * (*get_base_status) (struct block_list *bl); - const char * (*get_name) (struct block_list *bl); - int (*get_class) (struct block_list *bl); - int (*get_lv) (struct block_list *bl); + const char *(*get_name) (const struct block_list *bl); + int (*get_class) (const struct block_list *bl); + int (*get_lv) (const struct block_list *bl); defType (*get_def) (struct block_list *bl); unsigned short (*get_speed) (struct block_list *bl); unsigned char (*calc_attack_element) (struct block_list *bl, struct status_change *sc, int element); - int (*get_party_id) (struct block_list *bl); - int (*get_guild_id) (struct block_list *bl); - int (*get_emblem_id) (struct block_list *bl); - int (*get_mexp) (struct block_list *bl); - int (*get_race2) (struct block_list *bl); + int (*get_party_id) (const struct block_list *bl); + int (*get_guild_id) (const struct block_list *bl); + int (*get_emblem_id) (const struct block_list *bl); + int (*get_mexp) (const struct block_list *bl); + int (*get_race2) (const struct block_list *bl); struct view_data * (*get_viewdata) (struct block_list *bl); void (*set_viewdata) (struct block_list *bl, int class_); void (*change_init) (struct block_list *bl); @@ -2272,8 +2275,8 @@ struct status_interface { void (*initDummyData) (void); int (*base_amotion_pc) (struct map_session_data *sd, struct status_data *st); unsigned short (*base_atk) (const struct block_list *bl, const struct status_data *st); - unsigned int (*get_base_maxhp) (struct map_session_data *sd, struct status_data *st); - unsigned int (*get_base_maxsp) (struct map_session_data *sd, struct status_data *st); + unsigned int (*get_base_maxhp) (const struct map_session_data *sd, const struct status_data *st); + unsigned int (*get_base_maxsp) (const struct map_session_data *sd, const struct status_data *st); int (*calc_npc_) (struct npc_data *nd, enum e_status_calc_opt opt); unsigned short (*calc_str) (struct block_list *bl, struct status_change *sc, int str); unsigned short (*calc_agi) (struct block_list *bl, struct status_change *sc, int agi); diff --git a/src/map/storage.c b/src/map/storage.c index ceac85916..91b37eb19 100644 --- a/src/map/storage.c +++ b/src/map/storage.c @@ -52,8 +52,8 @@ struct guild_storage_interface *gstorage; *------------------------------------------*/ int storage_comp_item(const void *i1_, const void *i2_) { - const struct item *i1 = (const struct item *)i1_; - const struct item *i2 = (const struct item *)i2_; + const struct item *i1 = i1_; + const struct item *i2 = i2_; if (i1->nameid == i2->nameid) return 0; @@ -79,7 +79,7 @@ void storage_sortitem(struct item* items, unsigned int size) * Parses storage and saves 'dirty' ones upon reconnect. [Skotlex] * @see DBApply */ -int storage_reconnect_sub(DBKey key, DBData *data, va_list ap) +int storage_reconnect_sub(union DBKey key, struct DBData *data, va_list ap) { struct guild_storage *stor = DB->data2ptr(data); if (stor->dirty && stor->storage_status == 0) //Save closed storages. @@ -366,7 +366,7 @@ void storage_storage_quit(struct map_session_data* sd, int flag) { /** * @see DBCreateData */ -DBData create_guildstorage(DBKey key, va_list args) +struct DBData create_guildstorage(union DBKey key, va_list args) { struct guild_storage *gs = NULL; gs = (struct guild_storage *) aCalloc(sizeof(struct guild_storage), 1); diff --git a/src/map/storage.h b/src/map/storage.h index bddd03770..94512c456 100644 --- a/src/map/storage.h +++ b/src/map/storage.h @@ -52,11 +52,11 @@ struct storage_interface { void (*pc_quit) (struct map_session_data *sd, int flag); int (*comp_item) (const void *i1_, const void *i2_); void (*sortitem) (struct item* items, unsigned int size); - int (*reconnect_sub) (DBKey key, DBData *data, va_list ap); + int (*reconnect_sub) (union DBKey key, struct DBData *data, va_list ap); }; struct guild_storage_interface { - struct DBMap* db; // int guild_id -> struct guild_storage* + struct DBMap *db; // int guild_id -> struct guild_storage* /* */ struct guild_storage *(*ensure) (int guild_id); /* */ @@ -75,7 +75,7 @@ struct guild_storage_interface { int (*pc_quit) (struct map_session_data *sd,int flag); int (*save) (int account_id, int guild_id, int flag); int (*saved) (int guild_id); //Ack from char server that guild store was saved. - DBData (*create) (DBKey key, va_list args); + struct DBData (*create) (union DBKey key, va_list args); }; #ifdef HERCULES_CORE diff --git a/src/map/unit.c b/src/map/unit.c index 9a698b77e..ac1e3e9b5 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -1220,6 +1220,7 @@ int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill_id, ui ud = unit->bl2ud(src); if(ud == NULL) return 0; + sc = status->get_sc(src); if (sc && !sc->count) sc = NULL; //Unneeded @@ -2289,11 +2290,18 @@ int unit_skillcastcancel(struct block_list *bl,int type) // unit_data initialization process void unit_dataset(struct block_list *bl) { - struct unit_data *ud; - nullpo_retv(ud = unit->bl2ud(bl)); + struct unit_data *ud = unit->bl2ud(bl); + nullpo_retv(ud); + + unit->init_ud(ud); + ud->bl = bl; +} + +void unit_init_ud(struct unit_data *ud) +{ + nullpo_retv(ud); - memset( ud, 0, sizeof( struct unit_data) ); - ud->bl = bl; + memset (ud, 0, sizeof(struct unit_data)); ud->walktimer = INVALID_TIMER; ud->skilltimer = INVALID_TIMER; ud->attacktimer = INVALID_TIMER; @@ -2433,7 +2441,7 @@ int unit_remove_map(struct block_list *bl, clr_type clrtype, const char* file, i status_change_end(d_bl,SC__SHADOWFORM,INVALID_TIMER); } //Leave/reject all invitations. - if(sd->chatID) + if (sd->chat_id != 0) chat->leave(sd, false); if(sd->trade_partner) trade->cancel(sd); @@ -2895,6 +2903,7 @@ void unit_defaults(void) { /* */ unit->bl2ud = unit_bl2ud; unit->bl2ud2 = unit_bl2ud2; + unit->init_ud = unit_init_ud; unit->attack_timer = unit_attack_timer; unit->walktoxy_timer = unit_walktoxy_timer; unit->walktoxy_sub = unit_walktoxy_sub; diff --git a/src/map/unit.h b/src/map/unit.h index 0279d73c1..8c4c34696 100644 --- a/src/map/unit.h +++ b/src/map/unit.h @@ -105,6 +105,7 @@ struct unit_interface { /* */ struct unit_data* (*bl2ud) (struct block_list *bl); struct unit_data* (*bl2ud2) (struct block_list *bl); + void (*init_ud) (struct unit_data *ud); int (*attack_timer) (int tid, int64 tick, int id, intptr_t data); int (*walktoxy_timer) (int tid, int64 tick, int id, intptr_t data); int (*walktoxy_sub) (struct block_list *bl); diff --git a/src/map/vending.c b/src/map/vending.c index 2346932ba..e3a62bea7 100644 --- a/src/map/vending.c +++ b/src/map/vending.c @@ -118,7 +118,7 @@ void vending_purchasereq(struct map_session_data* sd, int aid, unsigned int uid, // some checks z = 0; // zeny counter w = 0; // weight counter - for( i = 0; i < count; i++ ) { + for (i = 0; i < count; i++) { short amount = *(const uint16*)(data + 4*i + 0); short idx = *(const uint16*)(data + 4*i + 2); idx -= 2; @@ -184,7 +184,7 @@ void vending_purchasereq(struct map_session_data* sd, int aid, unsigned int uid, z -= apply_percentrate64(z, battle_config.vending_tax, 10000); pc->getzeny(vsd, (int)z, LOG_TYPE_VENDING, sd); - for( i = 0; i < count; i++ ) { + for (i = 0; i < count; i++) { short amount = *(const uint16*)(data + 4*i + 0); short idx = *(const uint16*)(data + 4*i + 2); idx -= 2; @@ -199,7 +199,7 @@ void vending_purchasereq(struct map_session_data* sd, int aid, unsigned int uid, if( battle_config.buyer_name ) { char temp[256]; sprintf(temp, msg_sd(vsd,265), sd->status.name); - clif_disp_onlyself(vsd,temp,strlen(temp)); + clif_disp_onlyself(vsd, temp); } } @@ -265,7 +265,7 @@ void vending_openvending(struct map_session_data* sd, const char* message, const // filter out invalid items i = 0; - for( j = 0; j < count; j++ ) { + for (j = 0; j < count; j++) { short index = *(const uint16*)(data + 8*j + 0); short amount = *(const uint16*)(data + 8*j + 2); unsigned int value = *(const uint32*)(data + 8*j + 4); diff --git a/src/map/vending.h b/src/map/vending.h index 6684ed256..1d2135076 100644 --- a/src/map/vending.h +++ b/src/map/vending.h @@ -22,8 +22,9 @@ #define MAP_VENDING_H #include "common/hercules.h" -#include "common/db.h" +/* Forward Declarations */ +struct DBMap; // common/db.h struct map_session_data; struct s_search_store_search; @@ -35,7 +36,7 @@ struct s_vending { struct vending_interface { unsigned int next_id;/* next vender id */ - DBMap *db; + struct DBMap *db; /* */ void (*init) (bool minimal); void (*final) (void); |