diff options
Diffstat (limited to 'src/map')
42 files changed, 3215 insertions, 2577 deletions
diff --git a/src/map/Makefile.in b/src/map/Makefile.in index ff582d2f9..3c6a3f806 100644 --- a/src/map/Makefile.in +++ b/src/map/Makefile.in @@ -23,7 +23,7 @@ CONFIG_D = ../config CONFIG_H = $(wildcard $(CONFIG_D)/*.h) $(wildcard $(CONFIG_D)/*/*.h) COMMON_D = ../common -COMMON_H = $(filter-out %.p.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.. diff --git a/src/map/atcommand.c b/src/map/atcommand.c index 3da5c203f..eef67189a 100644 --- a/src/map/atcommand.c +++ b/src/map/atcommand.c @@ -132,7 +132,6 @@ bool msg_config_read(const char *cfg_name, bool allow_override) { int msg_number; char line[1024], w1[1024], w2[1024]; FILE *fp; - static int called = 1; nullpo_retr(false, cfg_name); if ((fp = fopen(cfg_name, "r")) == NULL) { @@ -170,21 +169,6 @@ bool msg_config_read(const char *cfg_name, bool allow_override) { } fclose(fp); - if( ++called == 1 ) { //Original - if( script->lang_export_fp ) { - int i; - for(i = 0; i < MAX_MSG;i++) { - if( atcommand->msg_table[0][i] != NULL ) { - fprintf(script->lang_export_fp, "msgctxt \"messages.conf\"\n" - "msgid \"%s\"\n" - "msgstr \"\"\n", - atcommand->msg_table[0][i] - ); - } - } - } - } - return true; } @@ -266,22 +250,22 @@ ACMD(send) clif->message(fd, atcmd_output); return false; } - + if (len) { // show packet length safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd,904), type, clif->packet(type)->len); // Packet 0x%x length: %d clif->message(fd, atcmd_output); return true; } - + len = clif->packet(type)->len; - + if (len == -1) { // dynamic packet len = SHRT_MAX-4; // maximum length off = 4; } - + WFIFOHEAD(sd->fd, len); WFIFOW(sd->fd,0)=TOW(type); @@ -1091,9 +1075,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 +1088,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; } @@ -3748,7 +3732,7 @@ ACMD(reloadscript) { * 1 = Show users in that map and their location * 2 = Shows NPCs in that map * 3 = Shows the chats in that map - TODO# add the missing mapflags e.g. adjust_skill_damage to display + * TODO# add the missing mapflags e.g. adjust_skill_damage to display *------------------------------------------*/ ACMD(mapinfo) { @@ -3793,7 +3777,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++; } } @@ -3972,7 +3956,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); @@ -4153,8 +4137,9 @@ ACMD(repairall) count = 0; for (i = 0; i < MAX_INVENTORY; i++) { - if (sd->status.inventory[i].nameid && sd->status.inventory[i].attribute == 1) { - sd->status.inventory[i].attribute = 0; + if (sd->status.inventory[i].nameid && (sd->status.inventory[i].attribute & ATTR_BROKEN) != 0) { + sd->status.inventory[i].attribute |= ATTR_BROKEN; + sd->status.inventory[i].attribute ^= ATTR_BROKEN; clif->produce_effect(sd, 0, sd->status.inventory[i].nameid); count++; } @@ -4911,7 +4896,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; } @@ -4930,7 +4915,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; } @@ -6779,7 +6764,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 ) @@ -7836,7 +7821,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 @@ -7844,7 +7829,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. @@ -7855,7 +7840,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 @@ -7863,7 +7848,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. @@ -7958,7 +7943,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; } diff --git a/src/map/atcommand.h b/src/map/atcommand.h index 0e7895825..ef8be7807 100644 --- a/src/map/atcommand.h +++ b/src/map/atcommand.h @@ -152,7 +152,8 @@ void atcommand_defaults(void); HPShared struct atcommand_interface *atcommand; /* stay here */ -#define ACMD(x) static bool atcommand_ ## x (const int fd, struct map_session_data* sd, const char* command, const char* message, struct AtCommandInfo *info) __attribute__((nonnull (2, 3, 4, 5))); \ - static bool atcommand_ ## x (const int fd, struct map_session_data* sd, const char* command, const char* message, struct AtCommandInfo *info) +#define ACMD(x) \ + static bool atcommand_ ## x (const int fd, struct map_session_data* sd, const char* command, const char* message, struct AtCommandInfo *info) __attribute__((nonnull (2, 3, 4, 5))); \ + static bool atcommand_ ## x (const int fd, struct map_session_data* sd, const char* command, const char* message, struct AtCommandInfo *info) #endif /* MAP_ATCOMMAND_H */ diff --git a/src/map/battle.c b/src/map/battle.c index a7a6f4719..944271efa 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. @@ -6010,6 +6009,46 @@ int battle_damage_area(struct block_list *bl, va_list ap) { return 0; } + +bool battle_check_arrows(struct map_session_data *sd) +{ + int index = sd->equip_index[EQI_AMMO]; + if (index < 0) { + if (sd->weapontype1 > W_KATAR && sd->weapontype1 < W_HUUMA) + clif->skill_fail(sd, 0, USESKILL_FAIL_NEED_MORE_BULLET, 0); + else + clif->arrow_fail(sd, 0); + return false; + } + //Ammo check by Ishizu-chan + if (sd->inventory_data[index]) { + switch (sd->status.weapon) { + case W_BOW: + if (sd->inventory_data[index]->look != A_ARROW) { + clif->arrow_fail(sd, 0); + return false; + } + break; + case W_REVOLVER: + case W_RIFLE: + case W_GATLING: + case W_SHOTGUN: + if (sd->inventory_data[index]->look != A_BULLET) { + clif->skill_fail(sd, 0, USESKILL_FAIL_NEED_MORE_BULLET, 0); + return false; + } + break; + case W_GRENADE: + if (sd->inventory_data[index]->look != A_GRENADE) { + clif->skill_fail(sd, 0, USESKILL_FAIL_NEED_MORE_BULLET, 0); + return false; + } + break; + } + } + return true; +} + /*========================================== * Do a basic physical attack (call trough unit_attack_timer) *------------------------------------------*/ @@ -6047,39 +6086,8 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t sd->state.arrow_atk = (sd->status.weapon == W_BOW || (sd->status.weapon >= W_REVOLVER && sd->status.weapon <= W_GRENADE)); if (sd->state.arrow_atk) { - int index = sd->equip_index[EQI_AMMO]; - if (index<0) { - if ( sd->weapontype1 > W_KATAR && sd->weapontype1 < W_HUUMA ) - clif->skill_fail(sd, 0, USESKILL_FAIL_NEED_MORE_BULLET, 0); - else - clif->arrow_fail(sd, 0); + if (battle->check_arrows(sd) == false) return ATK_NONE; - } - //Ammo check by Ishizu-chan - if (sd->inventory_data[index]) - switch (sd->status.weapon) { - case W_BOW: - if (sd->inventory_data[index]->look != A_ARROW) { - clif->arrow_fail(sd,0); - return ATK_NONE; - } - break; - case W_REVOLVER: - case W_RIFLE: - case W_GATLING: - case W_SHOTGUN: - if (sd->inventory_data[index]->look != A_BULLET) { - clif->skill_fail(sd, 0, USESKILL_FAIL_NEED_MORE_BULLET, 0); - return ATK_NONE; - } - break; - case W_GRENADE: - if (sd->inventory_data[index]->look != A_GRENADE) { - clif->skill_fail(sd, 0, USESKILL_FAIL_NEED_MORE_BULLET, 0); - return ATK_NONE; - } - break; - } } } if (sc && sc->count) { @@ -7606,6 +7614,7 @@ void battle_defaults(void) { battle->calc_gvg_damage = battle_calc_gvg_damage; battle->calc_bg_damage = battle_calc_bg_damage; battle->weapon_attack = battle_weapon_attack; + battle->check_arrows = battle_check_arrows; battle->calc_weapon_attack = battle_calc_weapon_attack; battle->delay_damage = battle_delay_damage; battle->drain = battle_drain; diff --git a/src/map/battle.h b/src/map/battle.h index 49abdc730..6fa600ada 100644 --- a/src/map/battle.h +++ b/src/map/battle.h @@ -593,6 +593,8 @@ struct battle_interface { int64 (*calc_bg_damage) (struct block_list *src, struct block_list *bl, int64 damage, int div_, uint16 skill_id, uint16 skill_lv, int flag); /* normal weapon attack */ enum damage_lv (*weapon_attack) (struct block_list *bl, struct block_list *target, int64 tick, int flag); + /* check is equipped ammo and this ammo allowed */ + bool (*check_arrows) (struct map_session_data *sd); /* calculate weapon attack */ struct Damage (*calc_weapon_attack) (struct block_list *src,struct block_list *target,uint16 skill_id,uint16 skill_lv,int wflag); /* delays damage or skills by a timer */ diff --git a/src/map/battleground.c b/src/map/battleground.c index 629122c87..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,14 +265,15 @@ 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; } diff --git a/src/map/battleground.h b/src/map/battleground.h index 8657beaf8..4c3d4878f 100644 --- a/src/map/battleground.h +++ b/src/map/battleground.h @@ -130,7 +130,7 @@ 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); + 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); diff --git a/src/map/channel.c b/src/map/channel.c index 3d1b3f975..ee8242b23 100644 --- a/src/map/channel.c +++ b/src/map/channel.c @@ -609,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"; @@ -640,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) @@ -699,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 ) 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/chrif.c b/src/map/chrif.c index 52af1137e..51e8e5143 100644 --- a/src/map/chrif.c +++ b/src/map/chrif.c @@ -236,11 +236,13 @@ void chrif_setpasswd(char *pwd) { // security check, prints warning if using default password void chrif_checkdefaultlogin(void) { +#ifndef BUILDBOT if (strcmp(chrif->userid, "s1")==0 && strcmp(chrif->passwd, "p1")==0) { ShowWarning("Using the default user/password s1/p1 is NOT RECOMMENDED.\n"); ShowNotice("Please edit your 'login' table to create a proper inter-server user/password (gender 'S')\n"); ShowNotice("and then edit your user/password in conf/map-server.conf (or conf/import/map_conf.txt)\n"); } +#endif } // sets char-server's ip address diff --git a/src/map/clif.c b/src/map/clif.c index e1b4be8f4..0f6e985fd 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -190,7 +190,7 @@ static inline void RFIFOPOS2(int fd, unsigned short pos, short* x0, short* y0, s #endif // 0 //To identify disguised characters. -static inline bool disguised(struct block_list* bl) +bool clif_isdisguised(struct block_list* bl) { struct map_session_data *sd = BL_CAST(BL_PC, bl); if (sd == NULL || sd->disguise == -1) @@ -265,24 +265,50 @@ uint32 clif_refresh_ip(void) return 0; } +unsigned char clif_bl_type(struct block_list *bl) +{ #if PACKETVER >= 20071106 -static inline unsigned char clif_bl_type(struct block_list *bl) { - nullpo_retr(0x1, bl); + struct view_data *vd; + nullpo_retr(CLUT_NPC, bl); + switch (bl->type) { - case BL_PC: return (disguised(bl) && !pc->db_checkid(status->get_viewdata(bl)->class_))? 0x1:0x0; //PC_TYPE - case BL_ITEM: return 0x2; //ITEM_TYPE - case BL_SKILL: return 0x3; //SKILL_TYPE - case BL_CHAT: return 0x4; //UNKNOWN_TYPE - case BL_MOB: return pc->db_checkid(status->get_viewdata(bl)->class_)?0x0:0x5; //NPC_MOB_TYPE - case BL_NPC: return pc->db_checkid(status->get_viewdata(bl)->class_)?0x0:0x6; //NPC_EVT_TYPE - case BL_PET: return pc->db_checkid(status->get_viewdata(bl)->class_)?0x0:0x7; //NPC_PET_TYPE - case BL_HOM: return 0x8; //NPC_HOM_TYPE - case BL_MER: return 0x9; //NPC_MERSOL_TYPE - case BL_ELEM: return 0xa; //NPC_ELEMENTAL_TYPE - default: return 0x1; //NPC_TYPE + case BL_PC: + vd = status->get_viewdata(bl); + nullpo_retr(CLUT_NPC, vd); + + if (clif->isdisguised(bl) && !pc->db_checkid(vd->class_)) + return CLUT_NPC; + return CLUT_PC; + case BL_ITEM: + return CLUT_ITEM; + case BL_SKILL: + return CLUT_SKILL; + case BL_CHAT: + return CLUT_UNKNOWN; + case BL_MOB: + vd = status->get_viewdata(bl); + nullpo_retr(CLUT_NPC, vd); + return pc->db_checkid(vd->class_) ? CLUT_PC : CLUT_MOB; + case BL_NPC: + vd = status->get_viewdata(bl); + nullpo_retr(CLUT_NPC, vd); + return pc->db_checkid(vd->class_) ? CLUT_PC : CLUT_EVENT; + case BL_PET: + vd = status->get_viewdata(bl); + nullpo_retr(CLUT_NPC, vd); + return pc->db_checkid(vd->class_) ? CLUT_PC : CLUT_PET; + case BL_HOM: + return CLUT_HOMNUCLUS; + case BL_MER: + return CLUT_MERCNARY; + case BL_ELEM: + return CLUT_ELEMENTAL; + default: + return CLUT_NPC; } -} #endif + return CLUT_UNKNOWN; +} /*========================================== * sub process of clif_send @@ -319,17 +345,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 +461,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); } @@ -823,7 +849,7 @@ void clif_clearunit_area(struct block_list* bl, clr_type type) clif->send(buf, packet_len(0x80), bl, type == CLR_DEAD ? AREA : AREA_WOS); - if(disguised(bl)) { + if (clif->isdisguised(bl)) { WBUFL(buf,2) = -bl->id; clif->send(buf, packet_len(0x80), bl, SELF); } @@ -928,7 +954,7 @@ void clif_set_unit_idle2(struct block_list* bl, struct map_session_data *tsd, en p.PacketType = idle_unit2Type; #if PACKETVER >= 20071106 - p.objecttype = clif_bl_type(bl); + p.objecttype = clif->bl_type(bl); #endif p.GID = bl->id; p.speed = status->get_speed(bl); @@ -990,7 +1016,7 @@ void clif_set_unit_idle(struct block_list* bl, struct map_session_data *tsd, enu p.PacketType = idle_unitType; #if PACKETVER >= 20091103 p.PacketLength = sizeof(p); - p.objecttype = clif_bl_type(bl); + p.objecttype = clif->bl_type(bl); #endif #if PACKETVER >= 20131223 p.AID = bl->id; @@ -1054,7 +1080,7 @@ void clif_set_unit_idle(struct block_list* bl, struct map_session_data *tsd, enu clif->send(&p,sizeof(p),tsd?&tsd->bl:bl,target); - if( disguised(bl) ) { + if (clif->isdisguised(bl)) { #if PACKETVER >= 20091103 p.objecttype = pc->db_checkid(status->get_viewdata(bl)->class_) ? 0x0 : 0x5; //PC_TYPE : NPC_MOB_TYPE p.GID = -bl->id; @@ -1079,7 +1105,7 @@ void clif_spawn_unit2(struct block_list* bl, enum send_target target) { p.PacketType = spawn_unit2Type; #if PACKETVER >= 20071106 - p.objecttype = clif_bl_type(bl); + p.objecttype = clif->bl_type(bl); #endif p.GID = bl->id; p.speed = status->get_speed(bl); @@ -1132,7 +1158,7 @@ void clif_spawn_unit(struct block_list* bl, enum send_target target) { p.PacketType = spawn_unitType; #if PACKETVER >= 20091103 p.PacketLength = sizeof(p); - p.objecttype = clif_bl_type(bl); + p.objecttype = clif->bl_type(bl); #endif #if PACKETVER >= 20131223 p.AID = bl->id; @@ -1192,7 +1218,7 @@ void clif_spawn_unit(struct block_list* bl, enum send_target target) { p.body = vd->body_style; safestrncpy(p.name, clif->get_bl_name(bl), NAME_LENGTH); #endif - if( disguised(bl) ) { + if (clif->isdisguised(bl)) { nullpo_retv(sd); if( sd->status.class_ != sd->disguise ) clif->send(&p,sizeof(p),bl,target); @@ -1228,7 +1254,7 @@ void clif_set_unit_walking(struct block_list* bl, struct map_session_data *tsd, p.PacketLength = sizeof(p); #endif #if PACKETVER >= 20071106 - p.objecttype = clif_bl_type(bl); + p.objecttype = clif->bl_type(bl); #endif #if PACKETVER >= 20131223 p.AID = bl->id; @@ -1287,7 +1313,7 @@ void clif_set_unit_walking(struct block_list* bl, struct map_session_data *tsd, clif->send(&p,sizeof(p),tsd?&tsd->bl:bl,target); - if( disguised(bl) ) { + if (clif->isdisguised(bl)) { #if PACKETVER >= 20091103 p.objecttype = pc->db_checkid(status->get_viewdata(bl)->class_) ? 0x0 : 0x5; //PC_TYPE : NPC_MOB_TYPE p.GID = -bl->id; @@ -1756,7 +1782,7 @@ void clif_move(struct unit_data *ud) clif->send(buf, packet_len(0x86), bl, AREA_WOS); - if (disguised(bl)) { + if (clif->isdisguised(bl)) { WBUFL(buf,2)=-bl->id; clif->send(buf, packet_len(0x86), bl, SELF); } @@ -1849,7 +1875,7 @@ void clif_fixpos(struct block_list *bl) { WBUFW(buf,8) = bl->y; clif->send(buf, packet_len(0x88), bl, AREA); - if( disguised(bl) ) { + if (clif->isdisguised(bl)) { WBUFL(buf,2) = -bl->id; clif->send(buf, packet_len(0x88), bl, SELF); } @@ -1957,21 +1983,38 @@ 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; +#ifdef SCRIPT_MES_STRIP_LINEBREAK + char *stripmes = NULL; + int i; +#endif 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; +#ifdef SCRIPT_MES_STRIP_LINEBREAK + stripmes = aStrdup(mes); + for (i = 0; stripmes[i] != '\0'; ++i) { + if (stripmes[i] == '\r') + stripmes[i] = ' '; + } + memcpy(WFIFOP(fd,8), stripmes, slen-8); + aFree(stripmes); +#else // ! SCRIPT_MES_STRIP_LINEBREAK memcpy(WFIFOP(fd,8), mes, slen-8); +#endif // SCRIPT_MES_STRIP_LINEBREAK WFIFOSET(fd,WFIFOW(fd,2)); } @@ -2072,24 +2115,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)); } @@ -2359,7 +2405,7 @@ void clif_additem(struct map_session_data *sd, int n, int amount, int fail) { p.nameid = sd->status.inventory[n].nameid; p.IsIdentified = sd->status.inventory[n].identify ? 1 : 0; - p.IsDamaged = sd->status.inventory[n].attribute ? 1 : 0; + p.IsDamaged = (sd->status.inventory[n].attribute & ATTR_BROKEN) != 0 ? 1 : 0; p.refiningLevel =sd->status.inventory[n].refine; clif->addcards2(&p.slot.card[0], &sd->status.inventory[n]); p.location = pc->equippoint(sd,n); @@ -2474,7 +2520,7 @@ void clif_item_equip(short idx, struct EQUIPITEM_INFO *p, struct item *i, struct p->location = eqp_pos; p->WearState = i->equip; #if PACKETVER < 20120925 - p->IsDamaged = i->attribute ? 1 : 0; + p->IsDamaged = (i->attribute & ATTR_BROKEN) != 0 ? 1 : 0; #endif p->RefiningLevel = i->refine; @@ -2494,7 +2540,7 @@ void clif_item_equip(short idx, struct EQUIPITEM_INFO *p, struct item *i, struct #if PACKETVER >= 20120925 p->Flag.IsIdentified = i->identify ? 1 : 0; - p->Flag.IsDamaged = i->attribute ? 1 : 0; + p->Flag.IsDamaged = (i->attribute & ATTR_BROKEN) != 0 ? 1 : 0; p->Flag.PlaceETCTab = i->favorite ? 1 : 0; p->Flag.SpareBits = 0; #endif @@ -3192,7 +3238,7 @@ void clif_changelook(struct block_list *bl,int type,int val) } // prevent leaking the presence of GM-hidden objects - if( sc && sc->option&OPTION_INVISIBLE && !disguised(bl) ) + if (sc && sc->option&OPTION_INVISIBLE && !clif->isdisguised(bl)) target = SELF; #if PACKETVER < 4 clif->sendlook(bl, bl->id, type, val, 0, target); @@ -3203,11 +3249,12 @@ void clif_changelook(struct block_list *bl,int type,int val) val = vd->weapon; val2 = vd->shield; } - if( disguised(bl) ) { + if (clif->isdisguised(bl)) { clif->sendlook(bl, bl->id, type, val, val2, AREA_WOS); clif->sendlook(bl, -bl->id, type, val, val2, SELF); - } else + } else { clif->sendlook(bl, bl->id, type, val, val2, target); + } #endif } @@ -3488,15 +3535,16 @@ void clif_changeoption(struct block_list* bl) WBUFW(buf,8) = (sc) ? sc->opt2 : 0; WBUFL(buf,10) = (sc != NULL) ? sc->option : ((bl->type == BL_NPC) ? BL_UCCAST(BL_NPC, bl)->option : 0); WBUFB(buf,14) = (sd)? sd->status.karma : 0; - if(disguised(bl)) { + if (clif->isdisguised(bl)) { clif->send(buf,packet_len(0x229),bl,AREA_WOS); WBUFL(buf,2) = -bl->id; clif->send(buf,packet_len(0x229),bl,SELF); WBUFL(buf,2) = bl->id; WBUFL(buf,10) = OPTION_INVISIBLE; clif->send(buf,packet_len(0x229),bl,SELF); - } else + } else { clif->send(buf,packet_len(0x229),bl,AREA); + } #else WBUFW(buf,0) = 0x119; WBUFL(buf,2) = bl->id; @@ -3504,15 +3552,16 @@ void clif_changeoption(struct block_list* bl) WBUFW(buf,8) = (sc) ? sc->opt2 : 0; WBUFL(buf,10) = (sc != NULL) ? sc->option : ((bl->type == BL_NPC) ? BL_UCCAST(BL_NPC, bl)->option : 0); WBUFB(buf,12) = (sd)? sd->status.karma : 0; - if(disguised(bl)) { + if (clif->isdisguised(bl)) { clif->send(buf,packet_len(0x119),bl,AREA_WOS); WBUFL(buf,2) = -bl->id; clif->send(buf,packet_len(0x119),bl,SELF); WBUFL(buf,2) = bl->id; WBUFW(buf,10) = OPTION_INVISIBLE; clif->send(buf,packet_len(0x119),bl,SELF); - } else + } else { clif->send(buf,packet_len(0x119),bl,AREA); + } #endif } @@ -3530,15 +3579,16 @@ void clif_changeoption2(struct block_list* bl) { WBUFL(buf,6) = (sc != NULL) ? sc->option : ((bl->type == BL_NPC) ? BL_UCCAST(BL_NPC, bl)->option : 0); WBUFL(buf,10) = clif_setlevel(bl); WBUFL(buf,14) = (sc) ? sc->opt3 : 0; - if(disguised(bl)) { + if (clif->isdisguised(bl)) { clif->send(buf,packet_len(0x28a),bl,AREA_WOS); WBUFL(buf,2) = -bl->id; clif->send(buf,packet_len(0x28a),bl,SELF); WBUFL(buf,2) = bl->id; WBUFL(buf,6) = OPTION_INVISIBLE; clif->send(buf,packet_len(0x28a),bl,SELF); - } else + } else { clif->send(buf,packet_len(0x28a),bl,AREA); + } } /// Notifies the client about the result of an item use request. @@ -3610,26 +3660,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)); @@ -3647,10 +3700,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; @@ -3658,15 +3712,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); } @@ -4115,8 +4171,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 ) @@ -4320,16 +4376,17 @@ int clif_damage(struct block_list* src, struct block_list* dst, int sdelay, int p.is_sp_damaged = 0; // TODO: IsSPDamage - Displays blue digits. #endif - if(disguised(dst)) { + if (clif->isdisguised(dst)) { clif->send(&p,sizeof(p),dst,AREA_WOS); p.targetGID = -dst->id; clif->send(&p,sizeof(p),dst,SELF); - } else + } else { clif->send(&p,sizeof(p),dst,AREA); + } - if(disguised(src)) { + if (clif->isdisguised(src)) { p.GID = -src->id; - if (disguised(dst)) + if (clif->isdisguised(dst)) p.targetGID = dst->id; if(damage > 0) p.damage = -1; @@ -4378,7 +4435,7 @@ void clif_sitting(struct block_list* bl) WBUFB(buf,26) = 2; clif->send(buf, packet_len(0x8a), bl, AREA); - if(disguised(bl)) { + if (clif->isdisguised(bl)) { WBUFL(buf, 2) = - bl->id; clif->send(buf, packet_len(0x8a), bl, SELF); } @@ -4397,7 +4454,7 @@ void clif_standing(struct block_list* bl) WBUFB(buf,26) = 3; clif->send(buf, packet_len(0x8a), bl, AREA); - if(disguised(bl)) { + if (clif->isdisguised(bl)) { WBUFL(buf, 2) = - bl->id; clif->send(buf, packet_len(0x8a), bl, SELF); } @@ -4618,9 +4675,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 ) @@ -4895,12 +4952,13 @@ void clif_skillcasting(struct block_list* bl, int src_id, int dst_id, int dst_x, WBUFB(buf,24) = 0; // isDisposable #endif - if (disguised(bl)) { + if (clif->isdisguised(bl)) { clif->send(buf,packet_len(cmd), bl, AREA_WOS); WBUFL(buf,2) = -src_id; clif->send(buf,packet_len(cmd), bl, SELF); - } else + } else { clif->send(buf,packet_len(cmd), bl, AREA); + } } /// Notifies clients in area, that an object canceled casting (ZC_DISPEL). @@ -5030,16 +5088,17 @@ int clif_skill_damage(struct block_list *src, struct block_list *dst, int64 tick WBUFW(buf, 26) = skill_lv; WBUFW(buf, 28) = div; WBUFB(buf, 30) = type; - if (disguised(dst)) { + if (clif->isdisguised(dst)) { clif->send(buf, packet_len(0x114), dst, AREA_WOS); WBUFL(buf, 8) = -dst->id; clif->send(buf, packet_len(0x114), dst, SELF); - } else + } else { clif->send(buf, packet_len(0x114), dst, AREA); + } - if (disguised(src)) { + if (clif->isdisguised(src)) { WBUFL(buf, 4) = -src->id; - if (disguised(dst)) + if (clif->isdisguised(dst)) WBUFL(buf, 8) = dst->id; if (damage > 0) WBUFW(buf, 24) = -1; @@ -5069,16 +5128,17 @@ int clif_skill_damage(struct block_list *src, struct block_list *dst, int64 tick #else WBUFB(buf, 32) = (type == BDT_SKILL) ? BDT_MULTIHIT : type; #endif - if (disguised(dst)) { + if (clif->isdisguised(dst)) { clif->send(buf, packet_len(0x1de), dst, AREA_WOS); WBUFL(buf,8)=-dst->id; clif->send(buf, packet_len(0x1de), dst, SELF); - } else + } else { clif->send(buf, packet_len(0x1de), dst, AREA); + } - if (disguised(src)) { + if (clif->isdisguised(src)) { WBUFL(buf, 4) = -src->id; - if (disguised(dst)) + if (clif->isdisguised(dst)) WBUFL(buf, 8) = dst->id; if (damage > 0) WBUFL(buf, 24) = -1; @@ -5127,15 +5187,15 @@ int clif_skill_damage2(struct block_list *src, struct block_list *dst, int64 tic WBUFW(buf,32)=div; WBUFB(buf,34)=type; clif->send(buf,packet_len(0x115),src,AREA); - if(disguised(src)) { + if (clif->isdisguised(src)) { WBUFL(buf,4)=-src->id; if(damage > 0) WBUFW(buf,28)=-1; clif->send(buf,packet_len(0x115),src,SELF); } - if (disguised(dst)) { + if (clif->isdisguised(dst)) { WBUFL(buf,8)=-dst->id; - if (disguised(src)) + if (clif->isdisguised(src)) WBUFL(buf,4)=src->id; else if(damage > 0) WBUFW(buf,28)=-1; @@ -5162,16 +5222,16 @@ int clif_skill_nodamage(struct block_list *src,struct block_list *dst,uint16 ski WBUFL(buf,10)=src?src->id:0; WBUFB(buf,14)=fail; - if (disguised(dst)) { + if (clif->isdisguised(dst)) { clif->send(buf,packet_len(0x11a),dst,AREA_WOS); WBUFL(buf,6)=-dst->id; clif->send(buf,packet_len(0x11a),dst,SELF); } else clif->send(buf,packet_len(0x11a),dst,AREA); - if(src && disguised(src)) { + if (src && clif->isdisguised(src)) { WBUFL(buf,10)=-src->id; - if (disguised(dst)) + if (clif->isdisguised(dst)) WBUFL(buf,6)=dst->id; clif->send(buf,packet_len(0x11a),src,SELF); } @@ -5193,12 +5253,13 @@ void clif_skill_poseffect(struct block_list *src, uint16 skill_id, int val, int WBUFW(buf,10)=x; WBUFW(buf,12)=y; WBUFL(buf,14)=(uint32)tick; - if(disguised(src)) { + if (clif->isdisguised(src)) { clif->send(buf,packet_len(0x117),src,AREA_WOS); WBUFL(buf,4)=-src->id; clif->send(buf,packet_len(0x117),src,SELF); - } else + } else { clif->send(buf,packet_len(0x117),src,AREA); + } } /// Presents a list of available warp destinations (ZC_WARPLIST). @@ -5478,23 +5539,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); } @@ -5516,7 +5578,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 ) { @@ -5570,7 +5632,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; @@ -5594,38 +5656,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; @@ -5669,7 +5731,7 @@ void clif_resurrection(struct block_list *bl,int type) WBUFW(buf,6)=0; clif->send(buf,packet_len(0x148),bl, type == 1 ? AREA : AREA_WOS); - if (disguised(bl)) { + if (clif->isdisguised(bl)) { struct map_session_data *sd = BL_UCAST(BL_PC, bl); if (sd->fontcolor) { WBUFL(buf,2)=-bl->id; @@ -5793,7 +5855,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; @@ -5802,21 +5864,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 } @@ -5966,7 +6028,7 @@ void clif_item_repair_list(struct map_session_data *sd,struct map_session_data * WFIFOW(fd,0)=0x1fc; for (i = c = 0; i < MAX_INVENTORY; i++) { int nameid = dstsd->status.inventory[i].nameid; - if (nameid > 0 && dstsd->status.inventory[i].attribute != 0) { // && skill_can_repair(sd,nameid)) { + if (nameid > 0 && (dstsd->status.inventory[i].attribute & ATTR_BROKEN) != 0) { // && skill_can_repair(sd,nameid)) { WFIFOW(fd,c*13+4) = i; WFIFOW(fd,c*13+6) = nameid; WFIFOB(fd,c*13+8) = dstsd->status.inventory[i].refine; @@ -6602,7 +6664,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; @@ -6610,22 +6672,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); } } @@ -7937,19 +8001,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; @@ -8154,7 +8220,7 @@ void clif_specialeffect(struct block_list* bl, int type, enum send_target target clif->send(buf, packet_len(0x1f3), bl, target); - if (disguised(bl)) { + if (clif->isdisguised(bl)) { WBUFL(buf,2) = -bl->id; clif->send(buf, packet_len(0x1f3), bl, SELF); } @@ -8186,8 +8252,7 @@ void clif_specialeffect_value(struct block_list* bl, int effect_id, int num, sen clif->send(buf, packet_len(0x284), bl, target); - if( disguised(bl) ) - { + if (clif->isdisguised(bl)) { WBUFL(buf,2) = -bl->id; clif->send(buf, packet_len(0x284), bl, SELF); } @@ -8203,10 +8268,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; @@ -8226,17 +8292,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; @@ -8316,7 +8384,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); @@ -8332,7 +8400,7 @@ void clif_refresh(struct map_session_data *sd) mail->clear(sd); - if( disguised(&sd->bl) ) {/* refresh-da */ + if (clif->isdisguised(&sd->bl)) {/* refresh-da */ short disguise = sd->disguise; pc->disguise(sd, -1); pc->disguise(sd, disguise); @@ -8547,8 +8615,7 @@ void clif_slide(struct block_list *bl, int x, int y) WBUFW(buf, 8) = y; clif->send(buf, packet_len(0x1ff), bl, AREA); - if( disguised(bl) ) - { + if (clif->isdisguised(bl)) { WBUFL(buf,2) = -bl->id; clif->send(buf, packet_len(0x1ff), bl, SELF); } @@ -8556,34 +8623,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); } - } /*========================== @@ -8867,105 +8933,137 @@ 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; + } - message = name + namelen + 3; - messagelen = textlen - namelen - 3; // this should be the message length (w/ zero byte included) + srcmessage = packet->message + namelen + 3; // <name> " : " <message> + messagelen = textlen - namelen - 3; + + 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; } @@ -8973,14 +9071,15 @@ void clif_channel_msg(struct channel_data *chan, struct map_session_data *sd, ch { 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); @@ -9008,13 +9107,14 @@ void clif_channel_msg2(struct channel_data *chan, char *msg) 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; @@ -9380,7 +9480,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 @@ -9687,7 +9787,7 @@ void clif_parse_GetCharNameRequest(int fd, struct map_session_data *sd) { // 'see people in GM hide' cheat detection #if 0 /* disabled due to false positives (network lag + request name of char that's about to hide = race condition) */ sc = status->get_sc(bl); - if (sc && sc->option&OPTION_INVISIBLE && !disguised(bl) && + if (sc && sc->option&OPTION_INVISIBLE && !clif->isdisguised(bl) && bl->type != BL_NPC && //Skip hidden NPCs which can be seen using Maya Purple pc_get_group_level(sd) < battle_config.hack_info_GM_level ) { @@ -9712,144 +9812,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 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; - const char *name = NULL, *message = NULL; - char *fakename = NULL; - size_t namelen, messagelen; - - 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))); @@ -9893,7 +9957,7 @@ void clif_changed_dir(struct block_list *bl, enum send_target target) clif->send(buf, packet_len(0x9c), bl, target); - if (disguised(bl)) { + if (clif->isdisguised(bl)) { WBUFL(buf,2) = -bl->id; WBUFW(buf,6) = 0; clif->send(buf, packet_len(0x9c), bl, SELF); @@ -10122,37 +10186,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; + char target[NAME_LENGTH], message[CHAT_SIZE_MAX + 1]; + const struct packet_whisper_message *packet = RP2PTR(fd); - if ( atcommand->exec(fd, sd, message, true) ) + if (!clif->process_whisper_message(sd, packet, target, message, sizeof message)) return; - // Statuses that prevent the player from whispering - if( !pc->can_talk(sd) ) - 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); @@ -10222,7 +10277,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; } @@ -10236,10 +10291,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; } @@ -10256,7 +10311,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))); @@ -10373,7 +10428,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] @@ -10733,10 +10788,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))); @@ -10747,7 +10802,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] @@ -11145,7 +11200,7 @@ void clif_parse_UseSkillToId(int fd, struct map_session_data *sd) sd->skillitem = sd->skillitemlv = 0; - if( skill_id >= GD_SKILLBASE ) { + if (skill_id >= GD_SKILLBASE && skill_id < GD_MAX) { if( sd->state.gmaster_flag ) skill_lv = guild->checkskill(sd->guild, skill_id); else @@ -11519,10 +11574,10 @@ void clif_parse_OneClick_ItemIdentify(int fd, struct map_session_data *sd) int cmd = RFIFOW(fd,0); short idx = RFIFOW(fd, packet_db[cmd].pos[0]) - 2; int n; - + if (idx < 0 || idx >= MAX_INVENTORY || sd->inventory_data[idx] == NULL || sd->status.inventory[idx].nameid <= 0) return; - + if ((n = pc->have_magnifier(sd) ) != INDEX_NOT_FOUND && pc->delitem(sd, n, 1, 0, DELITEM_NORMAL, LOG_TYPE_CONSUME) == 0) skill->identify(sd, idx); @@ -11952,36 +12007,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 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); - - 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))); @@ -12823,7 +12868,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) @@ -13060,39 +13105,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))); @@ -14674,7 +14709,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); } } @@ -14712,11 +14747,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; @@ -14744,7 +14784,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); @@ -14778,7 +14818,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; @@ -14802,6 +14841,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; @@ -16151,58 +16191,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; + const struct packet_chat_message *packet = RP2PTR(fd); + char message[CHAT_SIZE_MAX + NAME_LENGTH + 3 + 1]; - 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); - - bg->send_message(sd, text, textlen); + bg->send_message(sd, message); } /// Notifies client of a battleground score change (ZC_BATTLEFIELD_NOTIFY_POINT). @@ -17697,26 +17732,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) { @@ -17811,7 +17847,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 { @@ -18062,7 +18097,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); } } @@ -19365,7 +19400,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; @@ -19602,6 +19638,9 @@ void clif_defaults(void) { clif->ackmergeitems = clif_ackmergeitems; /* Cart Deco */ clif->selectcart = clif_selectcart; + /* */ + clif->isdisguised = clif_isdisguised; + clif->bl_type = clif_bl_type; /*------------------------ *- Parse Incoming Packet diff --git a/src/map/clif.h b/src/map/clif.h index f930e4ca1..df8b8f59c 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) @@ -520,7 +520,7 @@ enum CLOSE_ROULETTE_ACK { /** * Reason for item deletion (clif->delitem) - */ + **/ enum delitem_reason { DELITEM_NORMAL = 0, /// Normal DELITEM_SKILLUSE = 1, /// Item used for a skill @@ -532,9 +532,9 @@ enum delitem_reason { DELITEM_ANALYSIS = 7, /// Consumed by Four Spirit Analysis (SO_EL_ANALYSIS) skill }; -/* -* Merge items reasons -*/ +/** + * Merge items reasons + **/ enum mergeitem_reason { MERGEITEM_SUCCESS = 0x0, @@ -543,6 +543,23 @@ enum mergeitem_reason { }; /** + * Clif Unit Type + **/ +enum clif_unittype { + CLUT_PC = 0x0, + CLUT_NPC = 0x1, + CLUT_ITEM = 0x2, + CLUT_SKILL = 0x3, + CLUT_UNKNOWN = 0x4, + CLUT_MOB = 0x5, + CLUT_EVENT = 0x6, + CLUT_PET = 0x7, + CLUT_HOMNUCLUS = 0x8, + CLUT_MERCNARY = 0x9, + CLUT_ELEMENTAL = 0xa, +}; + +/** * Structures **/ typedef void (*pFunc)(int, struct map_session_data *); //cant help but put it first @@ -563,8 +580,8 @@ struct cdelayed_damage { }; struct merge_item { - int16 position; - int16 nameid; + int16 position; + int16 nameid; }; /** @@ -841,11 +858,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 +873,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 +960,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); @@ -1090,7 +1108,9 @@ struct clif_interface { void (*cancelmergeitem) (int fd, struct map_session_data *sd); int (*comparemergeitem) (const void *a, const void *b); void (*ackmergeitems) (int fd, struct map_session_data *sd); - + /* */ + bool (*isdisguised) (struct block_list* bl); + unsigned char (*bl_type) (struct block_list *bl); /*------------------------ *- Parse Incoming Packet *------------------------*/ 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 39d580bb7..ae3887aca 100644 --- a/src/map/guild.c +++ b/src/map/guild.c @@ -399,8 +399,11 @@ int guild_created(int account_id,int guild_id) { //struct guild *g; sd->status.guild_id=guild_id; clif->guild_created(sd,0); // Success - if(battle_config.guild_emperium_check) - pc->delitem(sd, pc->search_inventory(sd, ITEMID_EMPERIUM), 1, 0, DELITEM_NORMAL, LOG_TYPE_CONSUME); //emperium consumption + if (battle_config.guild_emperium_check) { + int n = pc->search_inventory(sd, ITEMID_EMPERIUM); + if (n != INDEX_NOT_FOUND) + pc->delitem(sd, n, 1, 0, DELITEM_NORMAL, LOG_TYPE_CONSUME); //emperium consumption + } return 0; } @@ -1060,14 +1063,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); @@ -1828,7 +1832,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; } diff --git a/src/map/guild.h b/src/map/guild.h index 1f3b74543..4fe7106d3 100644 --- a/src/map/guild.h +++ b/src/map/guild.h @@ -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); 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 ec0251dad..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; @@ -658,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; @@ -986,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 } @@ -1005,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; @@ -1023,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); @@ -1654,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); } } /*------------------------------------------ @@ -2489,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..54f462e35 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 c59f627cc..350697a08 100644 --- a/src/map/itemdb.c +++ b/src/map/itemdb.c @@ -342,7 +342,7 @@ const char* itemdb_typename(int type) return "Unknown Type"; } - /** +/** * Converts the JobID to the format used by map-server to check item * restriction as per job. * @@ -1658,7 +1658,7 @@ int itemdb_validate_entry(struct item_data *entry, int n, const char *source) { void itemdb_readdb_additional_fields(int itemid, struct config_setting_t *it, int n, const char *source) { - // do nothing. plugins can do own work + // do nothing. plugins can do own work } /** diff --git a/src/map/map.c b/src/map/map.c index 3a7d752c3..30c849ed1 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -6002,22 +6002,6 @@ static CMDLINEARG(loadscript) } /** - * --generate-translations - * - * Creates "./generated_translations.pot" - * @see cmdline->exec - **/ -static CMDLINEARG(generatetranslations) { - script->lang_export_file = aStrdup("./generated_translations.pot"); - - if( !(script->lang_export_fp = fopen(script->lang_export_file,"wb")) ) { - ShowError("export-dialog: failed to open '%s' for writing\n",script->lang_export_file); - } - core->runflag = CORE_ST_STOP; - return true; -} - -/** * Defines the local command line arguments */ void cmdline_args_init_local(void) @@ -6033,7 +6017,6 @@ void cmdline_args_init_local(void) CMDLINEARG_DEF2(log-config, logconfig, "Alternative logging configuration.", CMDLINE_OPT_NORMAL|CMDLINE_OPT_PARAM); CMDLINEARG_DEF2(script-check, scriptcheck, "Doesn't run the server, only tests the scripts passed through --load-script.", CMDLINE_OPT_SILENT); CMDLINEARG_DEF2(load-script, loadscript, "Loads an additional script (can be repeated).", CMDLINE_OPT_NORMAL|CMDLINE_OPT_PARAM); - CMDLINEARG_DEF2(generate-translations, generatetranslations, "Creates './generated_translations.pot' file with all translateable strings from scripts, server terminates afterwards.", CMDLINE_OPT_NORMAL); } int do_init(int argc, char *argv[]) @@ -6079,7 +6062,9 @@ int do_init(int argc, char *argv[]) char ip_str[16]; sockt->ip2str(sockt->addr_[0], ip_str); +#ifndef BUILDBOT ShowWarning("Not all IP addresses in /conf/map-server.conf configured, auto-detecting...\n"); +#endif if (sockt->naddr_ == 0) ShowError("Unable to determine your IP address...\n"); diff --git a/src/map/mob.c b/src/map/mob.c index c765e7d63..b6b36dd61 100644 --- a/src/map/mob.c +++ b/src/map/mob.c @@ -421,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; } @@ -430,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; } @@ -2337,11 +2337,6 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) { if(flag) { if(base_exp || job_exp) { if( md->dmglog[i].flag != MDLF_PET || battle_config.pet_attack_exp_to_master ) { -#ifdef RENEWAL_EXP - int rate = pc->level_penalty_mod(md->level - (tmpsd[i])->status.base_level, md->status.race, md->status.mode, 1); - base_exp = (unsigned int)cap_value(base_exp * rate / 100, 1, UINT_MAX); - job_exp = (unsigned int)cap_value(job_exp * rate / 100, 1, UINT_MAX); -#endif pc->gainexp(tmpsd[i], &md->bl, base_exp, job_exp, false); } } @@ -2447,7 +2442,7 @@ 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, @@ -2556,60 +2551,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; } } diff --git a/src/map/npc.c b/src/map/npc.c index 1b784b0c8..945a84957 100644 --- a/src/map/npc.c +++ b/src/map/npc.c @@ -62,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]; @@ -132,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..."); @@ -2509,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) { @@ -2527,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; } @@ -2545,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); } @@ -2785,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); @@ -2930,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 @@ -3136,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); //----------------------------------------- @@ -3206,7 +3195,7 @@ bool npc_duplicate_script_sub(struct npc_data *nd, const struct npc_data *snd, i nullpo_retr(false, nd); nullpo_retr(false, snd); - ++npc_script; + ++npc->npc_script; nd->u.scr.xs = xs; nd->u.scr.ys = ys; nd->u.scr.script = snd->u.scr.script; @@ -3253,7 +3242,7 @@ bool npc_duplicate_shop_sub(struct npc_data *nd, const struct npc_data *snd, int nullpo_retr(false, nd); nullpo_retr(false, snd); - ++npc_shop; + ++npc->npc_shop; nd->u.shop.shop_item = snd->u.shop.shop_item; nd->u.shop.count = snd->u.shop.count; @@ -3271,7 +3260,7 @@ bool npc_duplicate_warp_sub(struct npc_data *nd, const struct npc_data *snd, int nullpo_retr(false, nd); nullpo_retr(false, snd); - ++npc_warp; + ++npc->npc_warp; nd->u.warp.xs = xs; nd->u.warp.ys = ys; nd->u.warp.mapindex = snd->u.warp.mapindex; @@ -3770,7 +3759,7 @@ const char *npc_parse_function(const char *w1, const char *w2, const char *w3, c struct script_code *oldscript = (struct script_code*)DB->data2ptr(&old_data); ShowWarning("npc_parse_function: Overwriting user function [%s] in file '%s', line '%d'.\n", w3, filepath, strline(buffer,start-buffer)); script->free_vars(oldscript->local.vars); - aFree(oldscript->script_buf); + VECTOR_CLEAR(oldscript->script_buf); aFree(oldscript); } @@ -3967,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, @@ -3978,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 } @@ -4778,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; @@ -4799,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(); @@ -4841,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(); @@ -4965,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)); @@ -4988,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] @@ -5019,12 +5002,6 @@ int do_init_npc(bool minimal) { timer->add_func_list(npc->timerevent,"npc_timerevent"); } - if( script->lang_export_fp ) { - ShowInfo("Lang exported to '%s'\n",script->lang_export_file); - fclose(script->lang_export_fp); - script->lang_export_fp = NULL; - } - // Init dummy NPC CREATE(npc->fake_nd, struct npc_data, 1); npc->fake_nd->bl.m = -1; @@ -5034,7 +5011,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; @@ -5048,6 +5025,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 8ee59e410..24ea9ea59 100644 --- a/src/map/npc.h +++ b/src/map/npc.h @@ -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); diff --git a/src/map/npc_chat.c b/src/map/npc_chat.c index 6726c65a9..4bd7d416d 100644 --- a/src/map/npc_chat.c +++ b/src/map/npc_chat.c @@ -100,6 +100,7 @@ struct pcre_interface *libpcre; */ void finalize_pcrematch_entry(struct pcrematch_entry* e) { + nullpo_retv(e); libpcre->free(e->pcre_); libpcre->free(e->pcre_extra_); aFree(e->pattern); @@ -111,7 +112,10 @@ void finalize_pcrematch_entry(struct pcrematch_entry* e) */ struct pcrematch_set* lookup_pcreset(struct npc_data* nd, int setid) { struct pcrematch_set *pcreset; - struct npc_parse *npcParse = nd->chatdb; + struct npc_parse *npcParse; + + nullpo_retr(NULL, nd); + npcParse = nd->chatdb; if (npcParse == NULL) nd->chatdb = npcParse = (struct npc_parse *)aCalloc(sizeof(struct npc_parse), 1); @@ -151,7 +155,9 @@ struct pcrematch_set* lookup_pcreset(struct npc_data* nd, int setid) { void activate_pcreset(struct npc_data* nd, int setid) { struct pcrematch_set *pcreset; - struct npc_parse *npcParse = nd->chatdb; + struct npc_parse *npcParse; + nullpo_retv(nd); + npcParse = nd->chatdb; if (npcParse == NULL) return; // Nothing to activate... pcreset = npcParse->inactive; @@ -184,7 +190,9 @@ void activate_pcreset(struct npc_data* nd, int setid) void deactivate_pcreset(struct npc_data* nd, int setid) { struct pcrematch_set *pcreset; - struct npc_parse *npcParse = nd->chatdb; + struct npc_parse *npcParse; + nullpo_retv(nd); + npcParse = nd->chatdb; if (npcParse == NULL) return; // Nothing to deactivate... if (setid == -1) { @@ -221,7 +229,9 @@ void delete_pcreset(struct npc_data* nd, int setid) { int active = 1; struct pcrematch_set *pcreset; - struct npc_parse *npcParse = nd->chatdb; + struct npc_parse *npcParse; + nullpo_retv(nd); + npcParse = nd->chatdb; if (npcParse == NULL) return; // Nothing to deactivate... pcreset = npcParse->active; @@ -269,8 +279,12 @@ void delete_pcreset(struct npc_data* nd, int setid) */ struct pcrematch_entry* create_pcrematch_entry(struct pcrematch_set* set) { - struct pcrematch_entry * e = (struct pcrematch_entry *) aCalloc(sizeof(struct pcrematch_entry), 1); - struct pcrematch_entry * last = set->head; + struct pcrematch_entry *e; + struct pcrematch_entry *last; + + nullpo_retr(NULL, set); + e = (struct pcrematch_entry *)aCalloc(sizeof(struct pcrematch_entry), 1); + last = set->head; // Normally we would have just stuck it at the end of the list but // this doesn't sink up with peoples usage pattern. They wanted @@ -303,6 +317,7 @@ void npc_chat_def_pattern(struct npc_data* nd, int setid, const char* pattern, c struct pcrematch_set * s = npc_chat->lookup_pcreset(nd, setid); struct pcrematch_entry *e = npc_chat->create_pcrematch_entry(s); + nullpo_retv(e); e->pattern = aStrdup(pattern); e->label = aStrdup(label); e->pcre_ = libpcre->compile(pattern, PCRE_CASELESS, &err, &erroff, NULL); @@ -317,7 +332,10 @@ void npc_chat_def_pattern(struct npc_data* nd, int setid, const char* pattern, c */ void npc_chat_finalize(struct npc_data* nd) { - struct npc_parse *npcParse = nd->chatdb; + struct npc_parse *npcParse; + + nullpo_retv(nd); + npcParse = nd->chatdb; if (npcParse == NULL) return; @@ -358,6 +376,8 @@ int npc_chat_sub(struct block_list* bl, va_list ap) len = va_arg(ap,int); sd = va_arg(ap,struct map_session_data *); + nullpo_ret(sd); + // iterate across all active sets for (pcreset = npcParse->active; pcreset != NULL; pcreset = pcreset->next) { @@ -373,7 +393,7 @@ int npc_chat_sub(struct block_list* bl, va_list ap) // save out the matched strings for (i = 0; i < r; i++) { - char var[6], val[255]; + char var[12], val[255]; snprintf(var, sizeof(var), "$@p%i$", i); libpcre->copy_substring(msg, offsets, r, i, val, sizeof(val)); script->set_var(sd, var, val); diff --git a/src/map/packets_struct.h b/src/map/packets_struct.h index 25b20cddf..e461eebe9 100644 --- a/src/map/packets_struct.h +++ b/src/map/packets_struct.h @@ -312,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]; @@ -447,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 @@ -499,473 +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 @@ -973,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 @@ -982,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 @@ -1108,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] @@ -1144,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; @@ -1215,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 551c4d56f..d0d466083 100644 --- a/src/map/party.c +++ b/src/map/party.c @@ -58,6 +58,9 @@ struct party_interface *party; * Used when creating/adding people to a party. [Skotlex] *------------------------------------------*/ void party_fill_member(struct party_member* member, struct map_session_data* sd, unsigned int leader) { + nullpo_retv(member); + nullpo_retv(sd); + member->account_id = sd->status.account_id; member->char_id = sd->status.char_id; safestrncpy(member->name, sd->status.name, NAME_LENGTH); @@ -162,6 +165,9 @@ int party_create(struct map_session_data *sd, const char *name,int item,int item struct party_member leader; char tname[NAME_LENGTH]; + nullpo_retr(0, sd); + nullpo_retr(0, name); + safestrncpy(tname, name, NAME_LENGTH); trim(tname); @@ -228,6 +234,7 @@ int party_recv_noinfo(int party_id, int char_id) { void party_check_state(struct party_data *p) { int i; + nullpo_retv(p); memset(&p->state, 0, sizeof(p->state)); for (i = 0; i < MAX_PARTY; i ++) { if (!p->party.member[i].online) continue; //Those not online shouldn't apart to skill usage and all that. @@ -407,6 +414,8 @@ void party_reply_invite(struct map_session_data *sd,int party_id,int flag) { struct map_session_data* tsd; struct party_member member; + nullpo_retv(sd); + if( sd->party_invite != party_id ) {// forged sd->party_invite = 0; @@ -436,8 +445,11 @@ void party_reply_invite(struct map_session_data *sd,int party_id,int flag) { //- Player must be authed/active and belong to a party before calling this method void party_member_joined(struct map_session_data *sd) { - struct party_data* p = party->search(sd->status.party_id); + struct party_data* p; int i; + + nullpo_retv(sd); + p = party->search(sd->status.party_id); if (!p) { party->request_info(sd->status.party_id, sd->status.char_id); return; @@ -536,6 +548,7 @@ int party_removemember(struct map_session_data* sd, int account_id, const char * if( !p->party.member[i].leader ) return 0; // only party leader may remove members + nullpo_retr(0, name); ARR_FIND( 0, MAX_PARTY, i, p->party.member[i].account_id == account_id && strncmp(p->party.member[i].name,name,NAME_LENGTH) == 0 ); if( i == MAX_PARTY ) return 0; // no such char in party @@ -550,6 +563,7 @@ int party_leave(struct map_session_data *sd) struct party_data *p; int i; + nullpo_ret(sd); p = party->search(sd->status.party_id); if( p == NULL ) return 0; @@ -743,6 +757,8 @@ void party_send_movemap(struct map_session_data *sd) { struct party_data *p; + nullpo_retv(sd); + if( sd->status.party_id==0 ) return; @@ -782,6 +798,8 @@ int party_send_logout(struct map_session_data *sd) struct party_data *p; int i; + nullpo_ret(sd); + if(!sd->status.party_id) return 0; @@ -798,12 +816,19 @@ 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; + + nullpo_ret(sd); + nullpo_ret(mes); + + len = (int)strlen(mes); + + 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); @@ -843,6 +868,8 @@ int party_skill_check(struct map_session_data *sd, int party_id, uint16 skill_id return 0; //Unknown case? } + nullpo_ret(sd); + for(i=0;i<MAX_PARTY;i++){ if ((p_sd = p->data[i].sd) == NULL) continue; @@ -930,11 +957,9 @@ int party_exp_share(struct party_data* p, struct block_list* src, unsigned int b { struct map_session_data* sd[MAX_PARTY]; unsigned int i, c; -#ifdef RENEWAL_EXP - unsigned int job_exp_bonus, base_exp_bonus; -#endif nullpo_ret(p); + nullpo_ret(src); // count the number of players eligible for exp sharing for (i = c = 0; i < MAX_PARTY; i++) { @@ -959,21 +984,7 @@ int party_exp_share(struct party_data* p, struct block_list* src, unsigned int b zeny = (unsigned int) cap_value(zeny * bonus/100, INT_MIN, INT_MAX); } -#ifdef RENEWAL_EXP - base_exp_bonus = base_exp; - job_exp_bonus = job_exp; -#endif - for (i = 0; i < c; i++) { -#ifdef RENEWAL_EXP - struct mob_data *md = BL_CAST(BL_MOB, src); - if (md != NULL && md->db->mexp == 0) { - int rate = pc->level_penalty_mod(md->level - (sd[i])->status.base_level, md->status.race, md->status.mode, 1); - - base_exp = (unsigned int)cap_value(base_exp_bonus * rate / 100, 1, UINT_MAX); - job_exp = (unsigned int)cap_value(job_exp_bonus * rate / 100, 1, UINT_MAX); - } -#endif pc->gainexp(sd[i], src, base_exp, job_exp, false); if (zeny) // zeny from mobs [Valaris] @@ -987,8 +998,12 @@ int party_share_loot(struct party_data* p, struct map_session_data* sd, struct i { struct map_session_data *target = NULL; int i; + + nullpo_ret(item_data); + if (p && p->party.item&2 && (first_charid || !(battle_config.party_share_type&1))) { + nullpo_ret(sd); //item distribution to party members. if (battle_config.party_share_type&2) { //Round Robin @@ -1050,6 +1065,7 @@ int party_share_loot(struct party_data* p, struct map_session_data* sd, struct i int party_send_dot_remove(struct map_session_data *sd) { + nullpo_ret(sd); if (sd->status.party_id) clif->party_xy_remove(sd); return 0; @@ -1065,6 +1081,7 @@ int party_sub_count(struct block_list *bl, va_list ap) nullpo_ret(bl); Assert_ret(bl->type == BL_PC); sd = BL_UCCAST(BL_PC, bl); + nullpo_ret(sd); if (sd->state.autotrade) return 0; @@ -1177,6 +1194,9 @@ void party_recruit_register(struct map_session_data *sd, short level, const char #ifdef PARTY_RECRUIT struct party_booking_ad_info *pb_ad; + nullpo_retv(sd); + nullpo_retv(notice); + pb_ad = (struct party_booking_ad_info*)idb_get(party->booking_db, sd->status.char_id); if( pb_ad == NULL ) @@ -1207,6 +1227,9 @@ void party_booking_register(struct map_session_data *sd, short level, short mapi struct party_booking_ad_info *pb_ad; int i; + nullpo_retv(sd); + nullpo_retv(job); + pb_ad = (struct party_booking_ad_info*)idb_get(party->booking_db, sd->status.char_id); if( pb_ad == NULL ) { @@ -1240,6 +1263,7 @@ void party_recruit_update(struct map_session_data *sd, const char *notice) { #ifdef PARTY_RECRUIT struct party_booking_ad_info *pb_ad; + nullpo_retv(sd); pb_ad = (struct party_booking_ad_info*)idb_get(party->booking_db, sd->status.char_id); if( pb_ad == NULL ) @@ -1261,6 +1285,9 @@ void party_booking_update(struct map_session_data *sd, short* job) { int i; struct party_booking_ad_info *pb_ad; + nullpo_retv(sd); + nullpo_retv(job); + pb_ad = (struct party_booking_ad_info*)idb_get(party->booking_db, sd->status.char_id); if( pb_ad == NULL ) @@ -1287,6 +1314,7 @@ void party_recruit_search(struct map_session_data *sd, short level, short mapid, bool more_result = false; struct DBIterator *iter = db_iterator(party->booking_db); + nullpo_retv(sd); memset(result_list, 0, sizeof(result_list)); for( pb_ad = dbi_first(iter); dbi_exists(iter); pb_ad = dbi_next(iter) ) @@ -1318,6 +1346,8 @@ void party_booking_search(struct map_session_data *sd, short level, short mapid, bool more_result = false; struct DBIterator *iter = db_iterator(party->booking_db); + nullpo_retv(sd); + memset(result_list, 0, sizeof(result_list)); for( pb_ad = dbi_first(iter); dbi_exists(iter); pb_ad = dbi_next(iter) ) { @@ -1353,6 +1383,8 @@ bool party_booking_delete(struct map_session_data *sd) { struct party_booking_ad_info* pb_ad; + nullpo_retr(false, sd); + if((pb_ad = (struct party_booking_ad_info*)idb_get(party->booking_db, sd->status.char_id))!=NULL) { #ifdef PARTY_RECRUIT diff --git a/src/map/party.h b/src/map/party.h index 253f074bb..05037eb04 100644 --- a/src/map/party.h +++ b/src/map/party.h @@ -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); diff --git a/src/map/path.c b/src/map/path.c index 543497c33..f5e08d4df 100644 --- a/src/map/path.c +++ b/src/map/path.c @@ -89,6 +89,7 @@ int path_blownpos(struct block_list *bl, int16 m,int16 x0,int16 y0,int16 dx,int1 { struct map_data *md; + Assert_retr(-1, m >= 0 && m < map->count); if( !map->list[m].cell ) return -1; md = &map->list[m]; @@ -126,6 +127,8 @@ bool path_search_long(struct shootpath_data *spd,struct block_list *bl,int16 m,i struct map_data *md; struct shootpath_data s_spd; + Assert_retr(false, m >= 0 && m < map->count); + if( spd == NULL ) spd = &s_spd; // use dummy output variable @@ -254,10 +257,12 @@ 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; + Assert_retr(false, m >= 0 && m < map->count); + if (wpd == NULL) wpd = &s_wpd; // use dummy output variable @@ -315,8 +320,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 +335,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 +412,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 57b2fe19a..2206dbb80 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -81,8 +81,10 @@ struct pc_interface *pc; //Note that it does not do a validity check for speed purposes, where parsing //player input make sure to use a pc->db_checkid first! int pc_class2idx(int class_) { - if (class_ >= JOB_NOVICE_HIGH) - return class_- JOB_NOVICE_HIGH+JOB_MAX_BASIC; + if (class_ >= JOB_NOVICE_HIGH) { + class_ += - JOB_NOVICE_HIGH + JOB_MAX_BASIC; + } + Assert_ret(class_ >= 0 && class_ < CLASS_COUNT); return class_; } @@ -109,6 +111,7 @@ struct map_session_data* pc_get_dummy_sd(void) int pc_set_group(struct map_session_data *sd, int group_id) { GroupSettings *group = pcg->id2group(group_id); + nullpo_retr(1, sd); if (group == NULL) return 1; sd->group_id = group_id; @@ -121,6 +124,7 @@ int pc_set_group(struct map_session_data *sd, int group_id) */ bool pc_should_log_commands(struct map_session_data *sd) { + nullpo_retr(true, sd); return pcg->should_log_commands(sd->group); } @@ -141,7 +145,8 @@ int pc_invincible_timer(int tid, int64 tick, int id, intptr_t data) return 0; } -void pc_setinvincibletimer(struct map_session_data* sd, int val) { +void pc_setinvincibletimer(struct map_session_data* sd, int val) +{ nullpo_retv(sd); val += map->list[sd->bl.m].invincible_time_inc; @@ -466,6 +471,7 @@ int pc_inventory_rental_end(int tid, int64 tick, int id, intptr_t data) { int pc_inventory_rental_clear(struct map_session_data *sd) { + nullpo_ret(sd); if( sd->rental_timer != INVALID_TIMER ) { timer->delete(sd->rental_timer, pc->inventory_rental_end); @@ -476,7 +482,11 @@ int pc_inventory_rental_clear(struct map_session_data *sd) } /* assumes i is valid (from default areas where it is called, it is) */ void pc_rental_expire(struct map_session_data *sd, int i) { - short nameid = sd->status.inventory[i].nameid; + short nameid; + + nullpo_retv(sd); + Assert_retv(i >= 0 && i < MAX_INVENTORY); + nameid = sd->status.inventory[i].nameid; /* Soon to be dropped, we got plans to integrate it with item db */ switch( nameid ) { @@ -547,6 +557,7 @@ void pc_inventory_rentals(struct map_session_data *sd) int i, c = 0; int64 expire_tick, next_tick = INT64_MAX; + nullpo_retv(sd); for( i = 0; i < MAX_INVENTORY; i++ ) { // Check for Rentals on Inventory if( sd->status.inventory[i].nameid == 0 ) @@ -686,6 +697,7 @@ int pc_equippoint(struct map_session_data *sd,int n) int ep = 0; nullpo_ret(sd); + Assert_ret(n >= 0 && n < MAX_INVENTORY); if(!sd->inventory_data[n]) return 0; @@ -812,6 +824,7 @@ bool pc_isequipped(struct map_session_data *sd, int nameid) { int i, j; + nullpo_retr(false, sd); for (i = 0; i < EQI_MAX; i++) { int index = sd->equip_index[i]; if( index < 0 ) continue; @@ -891,6 +904,7 @@ bool pc_adoption(struct map_session_data *p1_sd, struct map_session_data *p2_sd, if( !pc->can_Adopt(p1_sd, p2_sd, b_sd) ) return false; + nullpo_retr(false, b_sd); // Preserve current job levels and progress joblevel = b_sd->status.job_level; jobexp = b_sd->status.job_exp; @@ -1039,7 +1053,10 @@ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_tim { int i; int64 tick = timer->gettick(); - uint32 ip = sockt->session[sd->fd]->client_addr; + uint32 ip; + + nullpo_retr(false, sd); + ip = sockt->session[sd->fd]->client_addr; sd->login_id2 = login_id2; @@ -1269,6 +1286,7 @@ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_tim *------------------------------------------*/ void pc_authfail(struct map_session_data *sd) { + nullpo_retv(sd); clif->authfail_fd(sd->fd, 0); return; } @@ -1306,6 +1324,7 @@ int pc_reg_received(struct map_session_data *sd) { int i, idx = 0; + nullpo_ret(sd); sd->vars_ok = true; sd->change_level_2nd = pc_readglobalreg(sd,script->add_str("jobchange_level")); @@ -1632,6 +1651,7 @@ void pc_check_skilltree(struct map_session_data *sd, int skill_id) if(battle_config.skillfree) return; //Function serves no purpose if this is set + nullpo_retv(sd); i = pc->calc_skilltree_normalize_job(sd); c = pc->mapid2jobid(i, sd->status.sex); if (c == -1) { //Unable to normalize job?? @@ -1697,6 +1717,7 @@ void pc_check_skilltree(struct map_session_data *sd, int skill_id) int pc_clean_skilltree(struct map_session_data *sd) { int i; + nullpo_ret(sd); for (i = 0; i < MAX_SKILL; i++){ if (sd->status.skill[i].flag == SKILL_FLAG_TEMPORARY || sd->status.skill[i].flag == SKILL_FLAG_PLAGIARIZED) { sd->status.skill[i].id = 0; @@ -1714,8 +1735,10 @@ int pc_clean_skilltree(struct map_session_data *sd) int pc_calc_skilltree_normalize_job(struct map_session_data *sd) { int skill_point, novice_skills; - int c = sd->class_; + int c; + nullpo_ret(sd); + c = sd->class_; if (!battle_config.skillup_limit || pc_has_permission(sd, PC_PERM_ALL_SKILL)) return c; @@ -1822,6 +1845,7 @@ int pc_updateweightstatus(struct map_session_data *sd) } int pc_disguise(struct map_session_data *sd, int class_) { + nullpo_ret(sd); if (class_ == -1 && sd->disguise == -1) return 0; if (class_ >= 0 && sd->disguise == class_) @@ -1864,8 +1888,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); @@ -1881,6 +1905,8 @@ int pc_bonus_autospell(struct s_autospell *spell, int max, short id, short lv, s if( !rate ) return 0; + nullpo_ret(spell); + Assert_ret(max <= 15); // autospell array size for( i = 0; i < max && spell[i].id; i++ ) { if( (spell[i].card_id == card_id || spell[i].rate < 0 || rate < 0) && spell[i].id == id && spell[i].lv == lv ) @@ -1917,6 +1943,8 @@ int pc_bonus_autospell_onskill(struct s_autospell *spell, int max, short src_ski if( !rate ) return 0; + nullpo_ret(spell); + Assert_ret(max <= 15); // autospell array size for( i = 0; i < max && spell[i].id; i++ ) { ; // each autospell works independently @@ -1952,6 +1980,8 @@ int pc_bonus_autospell_onskill(struct s_autospell *spell, int max, short src_ski int pc_bonus_addeff(struct s_addeffect* effect, int max, enum sc_type id, int16 rate, int16 arrow_rate, uint8 flag, uint16 duration) { int i; + + nullpo_ret(effect); if (!(flag&(ATF_SHORT|ATF_LONG))) flag|=ATF_SHORT|ATF_LONG; //Default range: both if (!(flag&(ATF_TARGET|ATF_SELF))) @@ -1981,6 +2011,8 @@ int pc_bonus_addeff(struct s_addeffect* effect, int max, enum sc_type id, int16 int pc_bonus_addeff_onskill(struct s_addeffectonskill* effect, int max, enum sc_type id, short rate, short skill_id, unsigned char target) { int i; + + nullpo_ret(effect); for( i = 0; i < max && effect[i].skill; i++ ) { if( effect[i].id == id && effect[i].skill == skill_id && effect[i].target == target ) { effect[i].rate += rate; @@ -2001,6 +2033,7 @@ int pc_bonus_addeff_onskill(struct s_addeffectonskill* effect, int max, enum sc_ int pc_bonus_item_drop(struct s_add_drop *drop, const short max, short id, short group, int race_mask, int rate) { int i; + nullpo_ret(drop); //Apply config rate adjustment settings. if (rate >= 0) { //Absolute drop. if (battle_config.item_rate_adddrop != 100) @@ -2048,6 +2081,8 @@ int pc_bonus_item_drop(struct s_add_drop *drop, const short max, short id, short int pc_addautobonus(struct s_autobonus *bonus,char max,const char *bonus_script,short rate,unsigned int dur,short flag,const char *other_script,unsigned short pos,bool onskill) { int i; + nullpo_ret(bonus); + nullpo_ret(bonus_script); ARR_FIND(0, max, i, bonus[i].rate == 0); if( i == max ) { @@ -2084,6 +2119,7 @@ int pc_delautobonus(struct map_session_data* sd, struct s_autobonus *autobonus,c { int i; nullpo_ret(sd); + nullpo_ret(autobonus); for( i = 0; i < max; i++ ) { @@ -2155,6 +2191,7 @@ int pc_bonus_addele(struct map_session_data* sd, unsigned char ele, short rate, int i; struct weapon_data* wd; + nullpo_ret(sd); wd = (sd->state.lr_flag ? &sd->left_weapon : &sd->right_weapon); ARR_FIND(0, MAX_PC_BONUS, i, wd->addele2[i].rate == 0); @@ -2188,6 +2225,7 @@ int pc_bonus_subele(struct map_session_data* sd, unsigned char ele, short rate, { int i; + nullpo_ret(sd); ARR_FIND(0, MAX_PC_BONUS, i, sd->subele2[i].rate == 0); if (i == MAX_PC_BONUS) @@ -4093,7 +4131,7 @@ bool pc_can_insert_card_into(struct map_session_data* sd, int idx_card, int idx_ 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 false; // no free slots - return true; + return true; } /** @@ -4113,7 +4151,7 @@ bool pc_can_insert_card(struct map_session_data* sd, int idx_card) return false; // target card missing if (sd->inventory_data[idx_card]->type != IT_CARD) return false; // must be a card - return true; + return true; } /*========================================== @@ -4276,7 +4314,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; @@ -4318,7 +4356,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; } @@ -4343,7 +4381,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; } @@ -4366,7 +4404,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; } @@ -4404,7 +4442,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; @@ -4563,6 +4601,7 @@ int pc_additem(struct map_session_data *sd,struct item *item_data,int amount,e_l int pc_delitem(struct map_session_data *sd,int n,int amount,int type, short reason, e_log_pick_type log_type) { nullpo_retr(1, sd); + Assert_retr(1, n >= 0 && n < MAX_INVENTORY); if(sd->status.inventory[n].nameid==0 || amount <= 0 || sd->status.inventory[n].amount<amount || sd->inventory_data[n] == NULL) return 1; @@ -4706,6 +4745,7 @@ int pc_isUseitem(struct map_session_data *sd,int n) int nameid; nullpo_ret(sd); + Assert_ret(n >= 0 && n < MAX_INVENTORY); item = sd->inventory_data[n]; nameid = sd->status.inventory[n].nameid; @@ -4892,6 +4932,7 @@ int pc_useitem(struct map_session_data *sd,int n) { bool removeItem = false; nullpo_ret(sd); + Assert_ret(n >= 0 && n < MAX_INVENTORY); if( sd->npc_id || sd->state.workinprogress&1 ){ /* TODO: add to clif->messages enum */ @@ -5112,6 +5153,7 @@ int pc_cart_additem(struct map_session_data *sd,struct item *item_data,int amoun int pc_cart_delitem(struct map_session_data *sd,int n,int amount,int type,e_log_pick_type log_type) { struct item_data * data; nullpo_retr(1, sd); + Assert_retr(1, n >= 0 && n < MAX_INVENTORY); if( sd->status.cart[n].nameid == 0 || sd->status.cart[n].amount < amount || !(data = itemdb->exists(sd->status.cart[n].nameid)) ) return 1; @@ -5170,6 +5212,7 @@ int pc_cartitem_amount(struct map_session_data* sd, int idx, int amount) struct item* item_data; nullpo_retr(-1, sd); + Assert_retr(-1, idx >= 0 && idx < MAX_CART); item_data = &sd->status.cart[idx]; if( item_data->nameid == 0 || item_data->amount == 0 ) @@ -5204,9 +5247,12 @@ int pc_getitemfromcart(struct map_session_data *sd,int idx,int amount) return flag; } -void pc_bound_clear(struct map_session_data *sd, enum e_item_bound_type type) { + +void pc_bound_clear(struct map_session_data *sd, enum e_item_bound_type type) +{ int i; + nullpo_retv(sd); switch( type ) { /* both restricted to inventory */ case IBT_PARTY: @@ -5341,7 +5387,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; } @@ -6440,6 +6486,7 @@ int pc_check_job_name(const char *name) { { "Rebellion", JOB_REBELLION }, }; + nullpo_retr(-1, name); len = ARRAYLENGTH(names); ARR_FIND(0, len, i, strcmpi(names[i].name, name) == 0); @@ -6506,6 +6553,7 @@ int pc_stop_following (struct map_session_data *sd) int pc_follow(struct map_session_data *sd,int target_id) { struct block_list *bl = map->id2bl(target_id); + nullpo_retr(1, sd); if (bl == NULL /*|| bl->type != BL_PC*/) return 1; if (sd->followtimer != INVALID_TIMER) @@ -6520,6 +6568,7 @@ int pc_follow(struct map_session_data *sd,int target_id) { int pc_checkbaselevelup(struct map_session_data *sd) { unsigned int next = pc->nextbaseexp(sd); + nullpo_ret(sd); if (!next || sd->status.base_exp < next) return 0; @@ -6569,6 +6618,7 @@ int pc_checkbaselevelup(struct map_session_data *sd) { void pc_baselevelchanged(struct map_session_data *sd) { int i; + nullpo_retv(sd); for( i = 0; i < EQI_MAX; i++ ) { if( sd->equip_index[i] >= 0 ) { if( sd->inventory_data[ sd->equip_index[i] ]->elvmax && sd->status.base_level > (unsigned int)sd->inventory_data[ sd->equip_index[i] ]->elvmax ) @@ -6613,34 +6663,72 @@ int pc_checkjoblevelup(struct map_session_data *sd) * Alters EXP based on self bonuses that do not get shared with the party **/ void pc_calcexp(struct map_session_data *sd, unsigned int *base_exp, unsigned int *job_exp, struct block_list *src) { - int bonus = 0; - struct status_data *st = status->get_status_data(src); + int buff_ratio = 0, buff_job_ratio = 0, race_ratio = 0, pk_ratio = 0; + int64 jexp, bexp; - if (sd->expaddrace[st->race]) - bonus += sd->expaddrace[st->race]; - bonus += sd->expaddrace[(st->mode&MD_BOSS) ? RC_BOSS : RC_NONBOSS]; + nullpo_retv(sd); + nullpo_retv(base_exp); + nullpo_retv(job_exp); - if (battle_config.pk_mode - && (int)(status->get_lv(src) - sd->status.base_level) >= 20) - bonus += 15; // pk_mode additional exp if monster >20 levels [Valaris] + jexp = *job_exp; + bexp = *base_exp; - if (sd->sc.data[SC_CASH_PLUSEXP]) - bonus += sd->sc.data[SC_CASH_PLUSEXP]->val1; - if (sd->sc.data[SC_OVERLAPEXPUP]) - bonus += sd->sc.data[SC_OVERLAPEXPUP]->val1; + if (src != NULL) { + const struct status_data *st = status->get_status_data(src); + +#ifdef RENEWAL_EXP //should happen first before we caluclate any modifiers + if (src->type == BL_MOB) { + const struct mob_data *md = BL_UCAST(BL_MOB, src); + int re_mod; + re_mod = pc->level_penalty_mod(md->level - sd->status.base_level, md->status.race, md->status.mode, 1); + jexp = apply_percentrate64(jexp, re_mod, 100); + bexp = apply_percentrate64(bexp, re_mod, 100); + } +#endif + + //Race modifier + if (sd->expaddrace[st->race]) + race_ratio += sd->expaddrace[st->race]; + race_ratio += sd->expaddrace[(st->mode&MD_BOSS) ? RC_BOSS : RC_NONBOSS]; + } - *base_exp = (unsigned int) cap_value(*base_exp + apply_percentrate64(*base_exp, bonus, 100), 1, UINT_MAX); + //PK modifier + /* this doesn't exist in Aegis, instead there's a CrazyKiller check which double all EXP from this point */ + if (battle_config.pk_mode && (int)(status->get_lv(src) - sd->status.base_level) >= 20) + pk_ratio += 15; // pk_mode additional exp if monster >20 levels [Valaris] + + + //Buffs modifier + if (sd->sc.data[SC_CASH_PLUSEXP]) { + buff_job_ratio += sd->sc.data[SC_CASH_PLUSEXP]->val1; + buff_ratio += sd->sc.data[SC_CASH_PLUSEXP]->val1; + } + if (sd->sc.data[SC_OVERLAPEXPUP]) { + buff_job_ratio += sd->sc.data[SC_OVERLAPEXPUP]->val1; + buff_ratio += sd->sc.data[SC_OVERLAPEXPUP]->val1; + } if (sd->sc.data[SC_CASH_PLUSONLYJOBEXP]) - bonus += sd->sc.data[SC_CASH_PLUSONLYJOBEXP]->val1; + buff_job_ratio += sd->sc.data[SC_CASH_PLUSONLYJOBEXP]->val1; - *job_exp = (unsigned int) cap_value(*job_exp + apply_percentrate64(*job_exp, bonus, 100), 1, UINT_MAX); + //Applying Race and PK modifier First then Premium (Perment modifier) and finally buff modifier + jexp += apply_percentrate64(jexp, race_ratio, 100); + jexp += apply_percentrate64(jexp, pk_ratio, 100); + + bexp += apply_percentrate64(bexp, race_ratio, 100); + bexp += apply_percentrate64(bexp, pk_ratio, 100); - if (sd->status.mod_exp != 100) { - *base_exp = (unsigned int) cap_value(apply_percentrate64(*base_exp, sd->status.mod_exp, 100), 1, UINT_MAX); - *job_exp = (unsigned int) cap_value(apply_percentrate64(*job_exp, sd->status.mod_exp, 100), 1, UINT_MAX); + if (sd->status.mod_exp != 100) { + jexp = apply_percentrate64(jexp, sd->status.mod_exp, 100); + bexp = apply_percentrate64(bexp, sd->status.mod_exp, 100); } + + bexp += apply_percentrate64(bexp, buff_ratio, 100); + jexp += apply_percentrate64(jexp, buff_ratio + buff_job_ratio, 100); + + *job_exp = (unsigned int)cap_value(jexp, 1, UINT_MAX); + *base_exp = (unsigned int)cap_value(bexp, 1, UINT_MAX); } /** @@ -6654,24 +6742,25 @@ bool pc_gainexp(struct map_session_data *sd, struct block_list *src, unsigned in unsigned int nextb=0, nextj=0; nullpo_ret(sd); - if(sd->bl.prev == NULL || pc_isdead(sd)) + if (sd->bl.prev == NULL || pc_isdead(sd)) return false; - if(!battle_config.pvp_exp && map->list[sd->bl.m].flag.pvp) // [MouseJstr] + if (!battle_config.pvp_exp && map->list[sd->bl.m].flag.pvp) // [MouseJstr] return false; // no exp on pvp maps - if( pc_has_permission(sd,PC_PERM_DISABLE_EXP) ) + if (pc_has_permission(sd,PC_PERM_DISABLE_EXP)) return false; - if(sd->status.guild_id>0) - base_exp-=guild->payexp(sd,base_exp); + if (src) + pc->calcexp(sd, &base_exp, &job_exp, src); - if(src) pc->calcexp(sd, &base_exp, &job_exp, src); + if (sd->status.guild_id > 0) + base_exp -= guild->payexp(sd,base_exp); nextb = pc->nextbaseexp(sd); nextj = pc->nextjobexp(sd); - if(sd->state.showexp || battle_config.max_exp_gain_rate){ + if (sd->state.showexp || battle_config.max_exp_gain_rate) { if (nextb > 0) nextbp = (float) base_exp / (float) nextb; if (nextj > 0) @@ -6726,7 +6815,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; @@ -7875,6 +7964,7 @@ int pc_dead(struct map_session_data *sd,struct block_list *src) { } void pc_revive(struct map_session_data *sd,unsigned int hp, unsigned int sp) { + nullpo_retv(sd); if(hp) clif->updatestatus(sd,SP_HP); if(sp) clif->updatestatus(sd,SP_SP); @@ -8210,6 +8300,7 @@ int pc_setparam(struct map_session_data *sd,int type,int val) *------------------------------------------*/ void pc_heal(struct map_session_data *sd,unsigned int hp,unsigned int sp, int type) { + nullpo_retv(sd); if (type) { if (hp) clif->heal(sd->fd,SP_HP,hp); @@ -8233,6 +8324,7 @@ int pc_itemheal(struct map_session_data *sd,int itemid, int hp,int sp) { int bonus, tmp; + nullpo_ret(sd); if(hp) { int i; bonus = 100 + (sd->battle_status.vit<<1) @@ -8803,6 +8895,7 @@ int pc_setcart(struct map_session_data *sd,int type) { **/ void pc_setfalcon(struct map_session_data *sd, bool flag) { + nullpo_retv(sd); if (flag) { if (pc->checkskill(sd,HT_FALCON) > 0) // add falcon if he have the skill pc->setoption(sd,sd->sc.option|OPTION_FALCON); @@ -8821,6 +8914,7 @@ void pc_setfalcon(struct map_session_data *sd, bool flag) **/ void pc_setridingpeco(struct map_session_data *sd, bool flag) { + nullpo_retv(sd); if (flag) { if (pc->checkskill(sd, KN_RIDING)) pc->setoption(sd, sd->sc.option|OPTION_RIDING); @@ -8839,6 +8933,7 @@ void pc_setridingpeco(struct map_session_data *sd, bool flag) **/ void pc_setmadogear(struct map_session_data *sd, bool flag) { + nullpo_retv(sd); if (flag) { if ((sd->class_&MAPID_THIRDMASK) == MAPID_MECHANIC) pc->setoption(sd, sd->sc.option|OPTION_MADOGEAR); @@ -8857,6 +8952,7 @@ void pc_setmadogear(struct map_session_data *sd, bool flag) **/ void pc_setridingdragon(struct map_session_data *sd, unsigned int type) { + nullpo_retv(sd); if (type&OPTION_DRAGON) { // Ensure only one dragon is set at a time. if (type&OPTION_DRAGON1) @@ -8889,6 +8985,7 @@ void pc_setridingdragon(struct map_session_data *sd, unsigned int type) **/ void pc_setridingwug(struct map_session_data *sd, bool flag) { + nullpo_retv(sd); if (flag) { if (pc->checkskill(sd, RA_WUGRIDER) > 0) pc->setoption(sd,sd->sc.option|OPTION_WUGRIDER); @@ -8956,6 +9053,7 @@ int pc_candrop(struct map_session_data *sd, struct item *item) * For '@type' variables (temporary numeric char reg) **/ int pc_readreg(struct map_session_data* sd, int64 reg) { + nullpo_ret(sd); return i64db_iget(sd->regs.vars, reg); } /** @@ -8964,6 +9062,7 @@ int pc_readreg(struct map_session_data* sd, int64 reg) { void pc_setreg(struct map_session_data* sd, int64 reg, int val) { unsigned int index = script_getvaridx(reg); + nullpo_retv(sd); if( val ) { i64db_iput(sd->regs.vars, reg, val); if( index ) @@ -8981,6 +9080,7 @@ void pc_setreg(struct map_session_data* sd, int64 reg, int val) { char* pc_readregstr(struct map_session_data* sd, int64 reg) { struct script_reg_str *p = NULL; + nullpo_retr(NULL, sd); p = i64db_get(sd->regs.vars, reg); return p ? p->value : NULL; @@ -8993,6 +9093,8 @@ void pc_setregstr(struct map_session_data* sd, int64 reg, const char* str) { unsigned int index = script_getvaridx(reg); struct DBData prev; + nullpo_retv(sd); + nullpo_retv(str); if( str[0] ) { p = ers_alloc(pc->str_reg_ers, struct script_reg_str); @@ -9028,6 +9130,7 @@ void pc_setregstr(struct map_session_data* sd, int64 reg, const char* str) { int pc_readregistry(struct map_session_data *sd, int64 reg) { struct script_reg_num *p = NULL; + nullpo_ret(sd); if (!sd->vars_ok) { ShowError("pc_readregistry: Trying to read reg %s before it's been loaded!\n", script->get_str(script_getvarid(reg))); //This really shouldn't happen, so it's possible the data was lost somewhere, we should request it again. @@ -9049,6 +9152,7 @@ int pc_readregistry(struct map_session_data *sd, int64 reg) { char* pc_readregistry_str(struct map_session_data *sd, int64 reg) { struct script_reg_str *p = NULL; + nullpo_retr(NULL, sd); if (!sd->vars_ok) { ShowError("pc_readregistry_str: Trying to read reg %s before it's been loaded!\n", script->get_str(script_getvarid(reg))); //This really shouldn't happen, so it's possible the data was lost somewhere, we should request it again. @@ -9072,6 +9176,7 @@ int pc_setregistry(struct map_session_data *sd, int64 reg, int val) { const char *regname = script->get_str( script_getvarid(reg) ); unsigned int index = script_getvaridx(reg); + nullpo_ret(sd); /* SAAD! those things should be stored elsewhere e.g. char ones in char table, the cash ones in account_data table! */ switch( regname[0] ) { default: //Char reg @@ -9147,6 +9252,8 @@ int pc_setregistry_str(struct map_session_data *sd, int64 reg, const char *val) const char *regname = script->get_str( script_getvarid(reg) ); unsigned int index = script_getvaridx(reg); + nullpo_ret(sd); + nullpo_ret(val); if ( !pc->reg_load && !sd->vars_ok ) { ShowError("pc_setregistry_str : refusing to set %s until vars are received.\n", regname); return 0; @@ -9224,6 +9331,7 @@ int pc_addeventtimer(struct map_session_data *sd,int tick,const char *name) { int i; nullpo_ret(sd); + nullpo_ret(name); ARR_FIND( 0, MAX_EVENTTIMER, i, sd->eventtimer[i] == INVALID_TIMER ); if( i == MAX_EVENTTIMER ) @@ -9244,6 +9352,7 @@ int pc_deleventtimer(struct map_session_data *sd,const char *name) int i; nullpo_ret(sd); + nullpo_ret(name); if (sd->eventcount <= 0) return 0; @@ -9312,6 +9421,8 @@ int pc_checkcombo(struct map_session_data *sd, struct item_data *data ) { int index, success = 0; struct pc_combos *combo; + nullpo_ret(sd); + nullpo_ret(data); for( i = 0; i < data->combos_count; i++ ) { /* ensure this isn't a duplicate combo */ @@ -9387,6 +9498,8 @@ int pc_checkcombo(struct map_session_data *sd, struct item_data *data ) { int pc_removecombo(struct map_session_data *sd, struct item_data *data ) { int i, retval = 0; + nullpo_ret(sd); + nullpo_ret(data); if( !sd->combos ) return 0;/* nothing to do here, player has no combos */ @@ -9431,6 +9544,7 @@ int pc_removecombo(struct map_session_data *sd, struct item_data *data ) { } int pc_load_combo(struct map_session_data *sd) { int i, ret = 0; + nullpo_ret(sd); for( i = 0; i < EQI_MAX; i++ ) { struct item_data *id = NULL; int idx = sd->equip_index[i]; @@ -9463,6 +9577,7 @@ int pc_load_combo(struct map_session_data *sd) { **/ void pc_equipitem_pos(struct map_session_data *sd, struct item_data *id, int n, int pos) { + nullpo_retv(sd); if ((!map_no_view(sd->bl.m,EQP_SHADOW_WEAPON) && pos & EQP_SHADOW_WEAPON) || (pos & EQP_HAND_R)) { if(id) @@ -9574,7 +9689,7 @@ int pc_equipitem(struct map_session_data *sd,int n,int req_pos) if(battle_config.battle_log) ShowInfo("equip %d(%d) %x:%x\n", sd->status.inventory[n].nameid, n, (unsigned int)(id ? id->equip : 0), (unsigned int)req_pos); - if(!pc->isequip(sd,n) || !(pos&req_pos) || sd->status.inventory[n].equip != 0 || sd->status.inventory[n].attribute==1 ) { // [Valaris] + if(!pc->isequip(sd,n) || !(pos&req_pos) || sd->status.inventory[n].equip != 0 || (sd->status.inventory[n].attribute & ATTR_BROKEN) != 0 ) { // [Valaris] // FIXME: pc->isequip: equip level failure uses 2 instead of 0 clif->equipitemack(sd,n,0,EIA_FAIL); // fail return 0; @@ -9693,6 +9808,7 @@ int pc_equipitem(struct map_session_data *sd,int n,int req_pos) **/ void pc_unequipitem_pos(struct map_session_data *sd, int n, int pos) { + nullpo_retv(sd); if (pos & EQP_HAND_R) { sd->weapontype1 = 0; sd->status.weapon = sd->weapontype2; @@ -10048,6 +10164,7 @@ int pc_calc_pvprank_sub(struct block_list *bl, va_list ap) int pc_calc_pvprank(struct map_session_data *sd) { int old; struct map_data *m; + nullpo_ret(sd); m=&map->list[sd->bl.m]; old=sd->pvp_rank; sd->pvp_rank=1; @@ -10202,6 +10319,7 @@ void pc_bleeding (struct map_session_data *sd, unsigned int diff_tick) { int hp = 0, sp = 0; + nullpo_retv(sd); if( pc_isdead(sd) ) return; @@ -10235,6 +10353,7 @@ void pc_bleeding (struct map_session_data *sd, unsigned int diff_tick) void pc_regen (struct map_session_data *sd, unsigned int diff_tick) { int hp = 0, sp = 0; + nullpo_retv(sd); if (sd->hp_regen.value) { sd->hp_regen.tick += diff_tick; while (sd->hp_regen.tick >= sd->hp_regen.rate) { @@ -10312,6 +10431,7 @@ int pc_autosave(int tid, int64 tick, int id, intptr_t data) { } int pc_daynight_timer_sub(struct map_session_data *sd,va_list ap) { + nullpo_ret(sd); if (sd->state.night != map->night_flag && map->list[sd->bl.m].flag.nightenabled) { //Night/day state does not match. clif->status_change(&sd->bl, SI_SKE, map->night_flag, 0, 0, 0, 0); //New night effect by dynamix [Skotlex] sd->state.night = map->night_flag; @@ -10335,7 +10455,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; } @@ -10355,7 +10475,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; } @@ -10376,6 +10496,7 @@ void pc_overheat(struct map_session_data *sd, int val) { int heat = val, skill_lv, limit[] = { 10, 20, 28, 46, 66 }; + nullpo_retv(sd); if( !pc_ismadogear(sd) || sd->sc.data[SC_OVERHEAT] ) return; // already burning @@ -10401,6 +10522,7 @@ bool pc_isautolooting(struct map_session_data *sd, int nameid) { int i = 0; + nullpo_ret(sd); if (sd->state.autoloottype && sd->state.autoloottype&(1<<itemdb_type(nameid))) return true; @@ -10589,6 +10711,7 @@ int pc_split_str(char *str,char **val,int num) { int i; + nullpo_ret(val); for (i=0; i<num && str; i++){ val[i] = str; str = strchr(str,','); @@ -10601,6 +10724,7 @@ int pc_split_str(char *str,char **val,int num) int pc_split_atoi(char* str, int* val, char sep, int max) { int i,j; + nullpo_ret(val); for (i=0; i<max; i++) { if (!str) break; val[i] = atoi(str); @@ -10618,6 +10742,7 @@ int pc_split_atoui(char* str, unsigned int* val, char sep, int max) { static int warning=0; int i,j; + nullpo_ret(val); for (i=0; i<max; i++) { double f; if (!str) break; @@ -10870,6 +10995,7 @@ bool pc_readdb_levelpenalty(char* fields[], int columns, int current) { #if defined(RENEWAL_DROP) || defined(RENEWAL_EXP) int type, race, diff; + nullpo_retr(false, fields); type = atoi(fields[0]); race = atoi(fields[1]); diff = atoi(fields[2]); @@ -11014,18 +11140,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]); @@ -11037,8 +11163,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 @@ -11046,7 +11172,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++; @@ -11112,6 +11239,7 @@ void pc_itemcd_do(struct map_session_data *sd, bool load) { int i,cursor = 0; struct item_cd* cd = NULL; + nullpo_retv(sd); if( load ) { if( !(cd = idb_get(pc->itemcd_db, sd->status.char_id)) ) { // no skill cooldown is associated with this character @@ -11143,7 +11271,10 @@ void pc_itemcd_do(struct map_session_data *sd, bool load) { } void pc_bank_deposit(struct map_session_data *sd, int money) { - unsigned int limit_check = money+sd->status.bank_vault; + unsigned int limit_check; + + nullpo_retv(sd); + limit_check = money + sd->status.bank_vault; if( money <= 0 || limit_check > MAX_BANK_ZENY ) { clif->bank_deposit(sd,BDA_OVERFLOW); @@ -11163,8 +11294,10 @@ void pc_bank_deposit(struct map_session_data *sd, int money) { } } void pc_bank_withdraw(struct map_session_data *sd, int money) { - unsigned int limit_check = money+sd->status.zeny; + unsigned int limit_check; + nullpo_retv(sd); + limit_check = money + sd->status.zeny; if (money <= 0) { clif->bank_withdraw(sd,BWA_UNKNOWN_ERROR); return; @@ -11188,6 +11321,7 @@ void pc_bank_withdraw(struct map_session_data *sd, int money) { } /* status change data arrived from char-server */ void pc_scdata_received(struct map_session_data *sd) { + nullpo_retv(sd); pc->inventory_rentals(sd); clif->show_modifiers(sd); @@ -11195,7 +11329,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); } @@ -11236,6 +11370,7 @@ int pc_global_expiration_timer(int tid, int64 tick, int id, intptr_t data) { return 0; } void pc_expire_check(struct map_session_data *sd) { + nullpo_retv(sd); /* ongoing timer */ if( sd->expiration_tid != INVALID_TIMER ) return; @@ -11293,6 +11428,7 @@ void pc_autotrade_start(struct map_session_data *sd) { int i; char *data; + nullpo_retv(sd); if (SQL_ERROR == SQL->Query(map->mysql_handle, "SELECT `itemkey`,`amount`,`price` FROM `%s` WHERE `char_id` = '%d'",map->autotrade_data_db,sd->status.char_id)) Sql_ShowDebug(map->mysql_handle); @@ -11337,6 +11473,7 @@ void pc_autotrade_start(struct map_session_data *sd) { void pc_autotrade_update(struct map_session_data *sd, enum e_pc_autotrade_update_action action) { int i; + nullpo_retv(sd); /* either way, this goes down */ if( action != PAUC_START ) { if (SQL_ERROR == SQL->Query(map->mysql_handle, "DELETE FROM `%s` WHERE `char_id` = '%d'",map->autotrade_data_db,sd->status.char_id)) @@ -11390,6 +11527,7 @@ void pc_autotrade_prepare(struct map_session_data *sd) { char title[MESSAGE_SIZE]; unsigned char sex; + nullpo_retv(sd); CREATE(data, struct autotrade_vending, 1); memcpy(data->vending, sd->vending, sizeof(sd->vending)); @@ -11436,6 +11574,7 @@ void pc_autotrade_populate(struct map_session_data *sd) { struct autotrade_vending *data; int i, j, k, cursor = 0; + nullpo_retv(sd); if( !(data = idb_get(pc->at_db,sd->status.char_id)) ) return; @@ -11478,6 +11617,7 @@ void pc_autotrade_populate(struct map_session_data *sd) { int pc_autotrade_final(union DBKey key, struct DBData *data, va_list ap) { struct autotrade_vending* at_v = DB->data2ptr(data); + nullpo_ret(at_v); HPM->data_store_destroy(&at_v->hdata); return 0; } @@ -11516,6 +11656,90 @@ 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) +{ + nullpo_retr(false, sd); + 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; + + nullpo_retv(sd); + nullpo_retv(message); + 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); @@ -11871,6 +12095,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] **/ @@ -11883,6 +12110,6 @@ void pc_defaults(void) { pc->check_job_name = pc_check_job_name; pc->update_idle_time = pc_update_idle_time; - + pc->have_magnifier = pc_have_magnifier; } diff --git a/src/map/pc.h b/src/map/pc.h index b648b7113..58f7a2266 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -258,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; @@ -610,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 ) @@ -1089,8 +1089,11 @@ END_ZEROED_BLOCK; /* End */ 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/script.c b/src/map/script.c index 007c6e0e1..ed38ed1c5 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -83,36 +83,18 @@ struct script_interface script_s; struct script_interface *script; -static inline int GETVALUE(const unsigned char* buf, int i) { - return (int)MakeDWord(MakeWord(buf[i], buf[i+1]), MakeWord(buf[i+2], 0)); -} -static inline void SETVALUE(unsigned char* buf, int i, int n) { - buf[i] = GetByte(n, 0); - buf[i+1] = GetByte(n, 1); - buf[i+2] = GetByte(n, 2); -} - -static inline void script_string_buf_ensure(struct script_string_buf *buf, size_t ensure) { - if( buf->pos+ensure >= buf->size ) { - do { - buf->size += 512; - } while ( buf->pos+ensure >= buf->size ); - RECREATE(buf->ptr, char, buf->size); - } -} - -static inline void script_string_buf_addb(struct script_string_buf *buf,uint8 b) { - if( buf->pos+1 >= buf->size ) { - buf->size += 512; - RECREATE(buf->ptr, char, buf->size); - } - buf->ptr[buf->pos++] = b; +static inline int GETVALUE(const struct script_buf *buf, int i) +{ + Assert_ret(VECTOR_LENGTH(*buf) > i + 2); + return (int)MakeDWord(MakeWord(VECTOR_INDEX(*buf, i), VECTOR_INDEX(*buf, i+1)), + MakeWord(VECTOR_INDEX(*buf, i+2), 0)); } - -static inline void script_string_buf_destroy(struct script_string_buf *buf) { - if( buf->ptr ) - aFree(buf->ptr); - memset(buf,0,sizeof(struct script_string_buf)); +static inline void SETVALUE(struct script_buf *buf, int i, int n) +{ + Assert_retv(VECTOR_LENGTH(*buf) > i + 2); + VECTOR_INDEX(*buf, i) = GetByte(n, 0); + VECTOR_INDEX(*buf, i+1) = GetByte(n, 1); + VECTOR_INDEX(*buf, i+2) = GetByte(n, 2); } const char* script_op2name(int op) { @@ -606,21 +588,26 @@ int script_add_str(const char* p) return script->str_num++; } -/// Appends 1 byte to the script buffer. +/** + * Appends 1 byte to the script buffer. + * + * @param a The byte to append. + */ void add_scriptb(int a) { - if( script->pos+1 >= script->size ) - { - script->size += SCRIPT_BLOCK_SIZE; - RECREATE(script->buf,unsigned char,script->size); - } - script->buf[script->pos++] = (uint8)(a); + VECTOR_ENSURE(script->buf, 1, SCRIPT_BLOCK_SIZE); + VECTOR_PUSH(script->buf, (uint8)a); } -/// Appends a c_op value to the script buffer. -/// The value is variable-length encoded into 8-bit blocks. -/// The encoding scheme is ( 01?????? )* 00??????, LSB first. -/// All blocks but the last hold 7 bits of data, topmost bit is always 1 (carries). +/** + * Appends a c_op value to the script buffer. + * + * The value is variable-length encoded into 8-bit blocks. + * The encoding scheme is ( 01?????? )* 00??????, LSB first. + * All blocks but the last hold 7 bits of data, topmost bit is always 1 (carries). + * + * @param a The value to append. + */ void add_scriptc(int a) { while( a >= 0x40 ) @@ -632,10 +619,15 @@ void add_scriptc(int a) script->addb(a); } -/// Appends an integer value to the script buffer. -/// The value is variable-length encoded into 8-bit blocks. -/// The encoding scheme is ( 11?????? )* 10??????, LSB first. -/// All blocks but the last hold 7 bits of data, topmost bit is always 1 (carries). +/** + * Appends an integer value to the script buffer. + * + * The value is variable-length encoded into 8-bit blocks. + * The encoding scheme is ( 11?????? )* 10??????, LSB first. + * All blocks but the last hold 7 bits of data, topmost bit is always 1 (carries). + * + * @param a The value to append. + */ void add_scripti(int a) { while( a >= 0x40 ) @@ -646,11 +638,11 @@ void add_scripti(int a) script->addb(a|0x80); } -/// Appends a script->str_data object (label/function/variable/integer) to the script buffer. - -/// -/// @param l The id of the script->str_data entry -// Maximum up to 16M +/** + * Appends a script->str_data object (label/function/variable/integer) to the script buffer. + * + * @param l The id of the script->str_data entry (Maximum up to 16M) + */ void add_scriptl(int l) { int backpatch = script->str_data[l].backpatch; @@ -667,7 +659,7 @@ void add_scriptl(int l) case C_USERFUNC: // Embedded data backpatch there is a possibility of label script->addc(C_NAME); - script->str_data[l].backpatch = script->pos; + script->str_data[l].backpatch = VECTOR_LENGTH(script->buf); script->addb(backpatch); script->addb(backpatch>>8); script->addb(backpatch>>16); @@ -705,9 +697,9 @@ void set_label(int l,int pos, const char* script_pos) script->str_data[l].type=(script->str_data[l].type == C_USERFUNC ? C_USERFUNC_POS : C_POS); script->str_data[l].label=pos; for (i = script->str_data[l].backpatch; i >= 0 && i != 0x00ffffff; ) { - int next = GETVALUE(script->buf,i); - script->buf[i-1]=(script->str_data[l].type == C_USERFUNC ? C_USERFUNC_POS : C_POS); - SETVALUE(script->buf,i,pos); + int next = GETVALUE(&script->buf, i); + VECTOR_INDEX(script->buf, i-1) = (script->str_data[l].type == C_USERFUNC ? C_USERFUNC_POS : C_POS); + SETVALUE(&script->buf, i, pos); i = next; } } @@ -811,26 +803,25 @@ const char* parse_callfunc(const char* p, int require_paren, int is_custom) char *arg = NULL; char null_arg = '\0'; int func; - bool nested_call = false, macro = false; + bool macro = false; // is need add check for arg null pointer below? func = script->add_word(p); - if( script->str_data[func].type == C_FUNC ) { - /** only when unset (-1), valid values are >= 0 **/ - if( script->syntax.last_func == -1 ) - script->syntax.last_func = script->str_data[func].val; - else { //Nested function call - script->syntax.nested_call++; - nested_call = true; - - if( script->str_data[func].val == script->buildin_lang_macro_offset ) { + if (script->str_data[func].type == C_FUNC) { + script->syntax.nested_call++; + if (script->syntax.last_func != -1) { + if (script->str_data[func].val == script->buildin_lang_macro_offset) { script->syntax.lang_macro_active = true; macro = true; + } else if (script->str_data[func].val == script->buildin_lang_macro_fmtstring_offset) { + script->syntax.lang_macro_fmtstring_active = true; + macro = true; } } if( !macro ) { // buildin function + script->syntax.last_func = script->str_data[func].val; script->addl(func); script->addc(C_ARG); } @@ -919,18 +910,17 @@ const char* parse_callfunc(const char* p, int require_paren, int is_custom) disp_error_message("parse_callfunc: expected ')' to close argument list",p); ++p; - if( script->str_data[func].val == script->buildin_lang_macro_offset ) + if (script->str_data[func].val == script->buildin_lang_macro_offset) script->syntax.lang_macro_active = false; + else if (script->str_data[func].val == script->buildin_lang_macro_fmtstring_offset) + script->syntax.lang_macro_fmtstring_active = false; } - if( nested_call ) - script->syntax.nested_call--; - - if( !script->syntax.nested_call ) - script->syntax.last_func = -1; - - if( !macro ) + if (!macro) { + if (0 == --script->syntax.nested_call) + script->syntax.last_func = -1; script->addc(C_FUNC); + } return p; } @@ -942,7 +932,7 @@ void parse_nextline(bool first, const char* p) if( !first ) { script->addc(C_EOL); // mark end of line for stack cleanup - script->set_label(LABEL_NEXTLINE, script->pos, p); // fix up '-' labels + script->set_label(LABEL_NEXTLINE, VECTOR_LENGTH(script->buf), p); // fix up '-' labels } // initialize data for new '-' label fix up scheduling @@ -1066,6 +1056,8 @@ const char* parse_variable(const char* p) } // push the set function onto the stack + script->syntax.nested_call++; + script->syntax.last_func = script->str_data[script->buildin_set_ref].val; script->addl(script->buildin_set_ref); script->addc(C_ARG); @@ -1117,6 +1109,8 @@ const char* parse_variable(const char* p) // close the script by appending the function operator script->addc(C_FUNC); + if (--script->syntax.nested_call == 0) + script->syntax.last_func = -1; // push the buffer from the method return p; @@ -1159,13 +1153,19 @@ bool is_number(const char *p) { } /** + * Duplicates a script string into the script string list. * - **/ -int script_string_dup(char *str) { - size_t len = strlen(str); + * Grows the script string list as needed. + * + * @param str The string to insert. + * @return the string position in the script string list. + */ +int script_string_dup(char *str) +{ + int len = (int)strlen(str); int pos = script->string_list_pos; - while( pos+len+1 >= script->string_list_size ) { + while (pos+len+1 >= script->string_list_size) { script->string_list_size += (1024*1024)/2; RECREATE(script->string_list,char,script->string_list_size); } @@ -1179,231 +1179,194 @@ int script_string_dup(char *str) { /*========================================== * Analysis section *------------------------------------------*/ -const char* parse_simpleexpr(const char *p) +const char *parse_simpleexpr(const char *p) { p=script->skip_space(p); - if(*p==';' || *p==',') + if (*p == ';' || *p == ',') disp_error_message("parse_simpleexpr: unexpected end of expression",p); - if(*p=='(') { - int i = script->syntax.curly_count-1; - if (i >= 0 && script->syntax.curly[i].type == TYPE_ARGLIST) - ++script->syntax.curly[i].count; - p=script->parse_subexpr(p+1,-1); - p=script->skip_space(p); - if( (i=script->syntax.curly_count-1) >= 0 && script->syntax.curly[i].type == TYPE_ARGLIST - && script->syntax.curly[i].flag == ARGLIST_UNDEFINED && --script->syntax.curly[i].count == 0 - ) { - if( *p == ',' ) { - script->syntax.curly[i].flag = ARGLIST_PAREN; - return p; - } else { - script->syntax.curly[i].flag = ARGLIST_NO_PAREN; - } - } - if( *p != ')' ) - disp_error_message("parse_simpleexpr: unmatched ')'",p); - ++p; - } else if(is_number(p)) { - char *np; - long long lli; - while(*p == '0' && ISDIGIT(p[1])) p++; // Skip leading zeros, we don't support octal literals - lli=strtoll(p,&np,0); - if( lli < INT_MIN ) { - lli = INT_MIN; - script->disp_warning_message("parse_simpleexpr: underflow detected, capping value to INT_MIN",p); - } else if( lli > INT_MAX ) { - lli = INT_MAX; - script->disp_warning_message("parse_simpleexpr: overflow detected, capping value to INT_MAX",p); - } - script->addi((int)lli); // Cast is safe, as it's already been checked for overflows - p=np; - } else if(*p=='"') { - struct string_translation *st = NULL; - const char *start_point = p; - bool duplicate = true; - struct script_string_buf *sbuf = &script->parse_simpleexpr_str; - - do { - p++; - while( *p && *p != '"' ) { - if( (unsigned char)p[-1] <= 0x7e && *p == '\\' ) { - char buf[8]; - size_t len = sv->skip_escaped_c(p) - p; - size_t n = sv->unescape_c(buf, p, len); - if( n != 1 ) - ShowDebug("parse_simpleexpr: unexpected length %d after unescape (\"%.*s\" -> %.*s)\n", (int)n, (int)len, p, (int)n, buf); - p += len; - script_string_buf_addb(sbuf, *buf); - continue; - } else if( *p == '\n' ) { - disp_error_message("parse_simpleexpr: unexpected newline @ string",p); - } - script_string_buf_addb(sbuf, *p++); - } - if(!*p) - disp_error_message("parse_simpleexpr: unexpected end of file @ string",p); - p++; //'"' - p = script->skip_space(p); - } while( *p && *p == '"' ); - - script_string_buf_addb(sbuf, 0); - - if (!(script->syntax.translation_db && (st = strdb_get(script->syntax.translation_db, sbuf->ptr)) != NULL)) { - script->addc(C_STR); - - if( script->pos+sbuf->pos >= script->size ) { - do { - script->size += SCRIPT_BLOCK_SIZE; - } while( script->pos+sbuf->pos >= script->size ); - RECREATE(script->buf,unsigned char,script->size); - } + if (*p == '(') { + return script->parse_simpleexpr_paren(p); + } else if (is_number(p)) { + return script->parse_simpleexpr_number(p); + } else if(*p == '"') { + return script->parse_simpleexpr_string(p); + } else { + return script->parse_simpleexpr_name(p); + } +} - memcpy(script->buf+script->pos, sbuf->ptr, sbuf->pos); - script->pos += sbuf->pos; +const char *parse_simpleexpr_paren(const char *p) +{ + int i = script->syntax.curly_count - 1; + if (i >= 0 && script->syntax.curly[i].type == TYPE_ARGLIST) + ++script->syntax.curly[i].count; + p = script->parse_subexpr(p + 1, -1); + p = script->skip_space(p); + if ((i = script->syntax.curly_count - 1) >= 0 + && script->syntax.curly[i].type == TYPE_ARGLIST + && script->syntax.curly[i].flag == ARGLIST_UNDEFINED + && --script->syntax.curly[i].count == 0 + ) { + if (*p == ',') { + script->syntax.curly[i].flag = ARGLIST_PAREN; + return p; } else { - int expand = sizeof(int) + sizeof(uint8); - unsigned char j; - unsigned int st_cursor = 0; + script->syntax.curly[i].flag = ARGLIST_NO_PAREN; + } + } + if (*p != ')') + disp_error_message("parse_simpleexpr: unmatched ')'", p); - script->addc(C_LSTR); + return p + 1; +} - expand += (sizeof(char*) + sizeof(uint8)) * st->translations; +const char *parse_simpleexpr_number(const char *p) +{ + char *np = NULL; + long long lli; - while( script->pos+expand >= script->size ) { - script->size += SCRIPT_BLOCK_SIZE; - RECREATE(script->buf,unsigned char,script->size); - } + while (*p == '0' && ISDIGIT(p[1])) + p++; // Skip leading zeros, we don't support octal literals - *((int *)(&script->buf[script->pos])) = st->string_id; - *((uint8 *)(&script->buf[script->pos + sizeof(int)])) = st->translations; + lli = strtoll(p, &np, 0); + if (lli < INT_MIN) { + lli = INT_MIN; + script->disp_warning_message("parse_simpleexpr: underflow detected, capping value to INT_MIN", p); + } else if (lli > INT_MAX) { + lli = INT_MAX; + script->disp_warning_message("parse_simpleexpr: overflow detected, capping value to INT_MAX", p); + } + script->addi((int)lli); // Cast is safe, as it's already been checked for overflows - script->pos += sizeof(int) + sizeof(uint8); + return np; +} - for(j = 0; j < st->translations; j++) { - *((uint8 *)(&script->buf[script->pos])) = RBUFB(st->buf, st_cursor); - *((char **)(&script->buf[script->pos+sizeof(uint8)])) = &st->buf[st_cursor + sizeof(uint8)]; - script->pos += sizeof(char*) + sizeof(uint8); - st_cursor += sizeof(uint8); - while(st->buf[st_cursor++]); - st_cursor += sizeof(uint8); - } - } +const char *parse_simpleexpr_string(const char *p) +{ + const char *start_point = p; - /* When exporting we don't know what is a translation and what isn't */ - if( script->lang_export_fp && sbuf->pos > 1 ) {//sbuf->pos will always be at least 1 because of the '\0' - if( !script->syntax.strings ) { - script->syntax.strings = strdb_alloc(DB_OPT_DUP_KEY|DB_OPT_ALLOW_NULL_DATA, 0); + do { + p++; + while (*p != '\0' && *p != '"') { + if ((unsigned char)p[-1] <= 0x7e && *p == '\\') { + char buf[8]; + size_t len = sv->skip_escaped_c(p) - p; + size_t n = sv->unescape_c(buf, p, len); + if (n != 1) + ShowDebug("parse_simpleexpr: unexpected length %d after unescape (\"%.*s\" -> %.*s)\n", (int)n, (int)len, p, (int)n, buf); + p += len; + VECTOR_ENSURE(script->parse_simpleexpr_strbuf, 1, 512); + VECTOR_PUSH(script->parse_simpleexpr_strbuf, buf[0]); + continue; } - - if( !strdb_exists(script->syntax.strings,sbuf->ptr) ) { - strdb_put(script->syntax.strings, sbuf->ptr, NULL); - duplicate = false; + if (*p == '\n') { + disp_error_message("parse_simpleexpr: unexpected newline @ string", p); } + VECTOR_ENSURE(script->parse_simpleexpr_strbuf, 1, 512); + VECTOR_PUSH(script->parse_simpleexpr_strbuf, *p++); } + if (*p == '\0') + disp_error_message("parse_simpleexpr: unexpected end of file @ string", p); + p++; //'"' + p = script->skip_space(p); + } while (*p != '\0' && *p == '"'); - if( script->lang_export_fp && !duplicate && - ( ( ( script->syntax.last_func == script->buildin_mes_offset || - script->syntax.last_func == script->buildin_select_offset ) && !script->syntax.nested_call - ) || script->syntax.lang_macro_active ) ) { - const char *line_start = start_point; - const char *line_end = start_point; - struct script_string_buf *lbuf = &script->lang_export_line_buf; - struct script_string_buf *ubuf = &script->lang_export_unescaped_buf; - size_t line_length, cursor; + VECTOR_ENSURE(script->parse_simpleexpr_strbuf, 1, 512); + VECTOR_PUSH(script->parse_simpleexpr_strbuf, '\0'); - while( line_start > script->parser_current_src ) { - if( *line_start != '\n' ) - line_start--; - else - break; - } + script->add_translatable_string(&script->parse_simpleexpr_strbuf, start_point); - while( *line_end != '\n' && *line_end != '\0' ) - line_end++; + VECTOR_TRUNCATE(script->parse_simpleexpr_strbuf); - line_length = (size_t)(line_end - line_start); - if( line_length > 0 ) { - script_string_buf_ensure(lbuf,line_length + 1); + return p; +} - memcpy(lbuf->ptr, line_start, line_length); - lbuf->pos = line_length; - script_string_buf_addb(lbuf, 0); +const char *parse_simpleexpr_name(const char *p) +{ + int l; + const char *pv = NULL; - normalize_name(lbuf->ptr, "\r\n\t "); - } + // label , register , function etc + if (script->skip_word(p) == p) + disp_error_message("parse_simpleexpr: unexpected character", p); - for(cursor = 0; cursor < sbuf->pos; cursor++) { - if( sbuf->ptr[cursor] == '"' ) - script_string_buf_addb(ubuf, '\\'); - script_string_buf_addb(ubuf, sbuf->ptr[cursor]); - } - script_string_buf_addb(ubuf, 0); - - fprintf(script->lang_export_fp, "#: %s\n" - "# %s\n" - "msgctxt \"%s\"\n" - "msgid \"%s\"\n" - "msgstr \"\"\n", - script->parser_current_file ? script->parser_current_file : "Unknown File", - lbuf->ptr, - script->parser_current_npc_name ? script->parser_current_npc_name : "Unknown NPC", - ubuf->ptr - ); - lbuf->pos = 0; - ubuf->pos = 0; + l = script->add_word(p); + if (script->str_data[l].type == C_FUNC || script->str_data[l].type == C_USERFUNC || script->str_data[l].type == C_USERFUNC_POS) { + return script->parse_callfunc(p,1,0); +#ifdef SCRIPT_CALLFUNC_CHECK + } else { + const char *name = script->get_str(l); + if (strdb_get(script->userfunc_db,name) != NULL) { + return script->parse_callfunc(p, 1, 1); } - sbuf->pos = 0; +#endif + } + + if ((pv = script->parse_variable(p)) != NULL) { + // successfully processed a variable assignment + return pv; + } + + if (script->str_data[l].type == C_INT && script->str_data[l].deprecated) { + disp_warning_message("This constant is deprecated and it will be removed in a future version. Please see the script documentation and constants.conf for an alternative.\n", p); + } + + p = script->skip_word(p); + if (*p == '[') { + // array(name[i] => getelementofarray(name,i) ) + script->addl(script->buildin_getelementofarray_ref); + script->addc(C_ARG); + script->addl(l); + + p = script->parse_subexpr(p + 1, -1); + p = script->skip_space(p); + if (*p != ']') + disp_error_message("parse_simpleexpr: unmatched ']'", p); + ++p; + script->addc(C_FUNC); } else { - int l; - const char* pv; + script->addl(l); + } - // label , register , function etc - if(script->skip_word(p)==p) - disp_error_message("parse_simpleexpr: unexpected character",p); + return p; +} - l=script->add_word(p); - if( script->str_data[l].type == C_FUNC || script->str_data[l].type == C_USERFUNC || script->str_data[l].type == C_USERFUNC_POS) { - return script->parse_callfunc(p,1,0); -#ifdef SCRIPT_CALLFUNC_CHECK - } else { - const char* name = script->get_str(l); - if( strdb_get(script->userfunc_db,name) != NULL ) { - return script->parse_callfunc(p,1,1); - } -#endif - } +void script_add_translatable_string(const struct script_string_buf *string, const char *start_point) +{ + struct string_translation *st = NULL; - if( (pv = script->parse_variable(p)) ) { - // successfully processed a variable assignment - return pv; - } + if (script->syntax.translation_db == NULL + || (st = strdb_get(script->syntax.translation_db, VECTOR_DATA(*string))) == NULL) { + script->addc(C_STR); - if (script->str_data[l].type == C_INT && script->str_data[l].deprecated) { - disp_warning_message("This constant is deprecated and it will be removed in a future version. Please see the script documentation and constants.conf for an alternative.\n", p); - } + VECTOR_ENSURE(script->buf, VECTOR_LENGTH(*string), SCRIPT_BLOCK_SIZE); - p=script->skip_word(p); - if( *p == '[' ) { - // array(name[i] => getelementofarray(name,i) ) - script->addl(script->buildin_getelementofarray_ref); - script->addc(C_ARG); - script->addl(l); + VECTOR_PUSHARRAY(script->buf, VECTOR_DATA(*string), VECTOR_LENGTH(*string)); + } else { + unsigned char u; + int st_cursor = 0; - p=script->parse_subexpr(p+1,-1); - p=script->skip_space(p); - if( *p != ']' ) - disp_error_message("parse_simpleexpr: unmatched ']'",p); - ++p; - script->addc(C_FUNC); - } else { - script->addl(l); - } + script->addc(C_LSTR); - } + VECTOR_ENSURE(script->buf, (int)(sizeof(st->string_id) + sizeof(st->translations)), SCRIPT_BLOCK_SIZE); + VECTOR_PUSHARRAY(script->buf, (void *)&st->string_id, sizeof(st->string_id)); + VECTOR_PUSHARRAY(script->buf, (void *)&st->translations, sizeof(st->translations)); - return p; + for (u = 0; u != st->translations; u++) { + struct string_translation_entry *entry = (void *)(st->buf+st_cursor); + char *stringptr = &entry->string[0]; + st_cursor += sizeof(*entry); + VECTOR_ENSURE(script->buf, (int)(sizeof(entry->lang_id) + sizeof(char *)), SCRIPT_BLOCK_SIZE); + VECTOR_PUSHARRAY(script->buf, (void *)&entry->lang_id, sizeof(entry->lang_id)); + VECTOR_PUSHARRAY(script->buf, (void *)&stringptr, sizeof(stringptr)); + st_cursor += sizeof(uint8); // FIXME: What are we skipping here? + while (st->buf[st_cursor++] != 0) + (void)0; // Skip string + st_cursor += sizeof(uint8); // FIXME: What are we skipping here? + } + } } /*========================================== @@ -1582,7 +1545,7 @@ const char* parse_curly_close(const char* p) // You are here labeled sprintf(label,"__SW%x_%x", (unsigned int)script->syntax.curly[pos].index, (unsigned int)script->syntax.curly[pos].count); l=script->add_str(label); - script->set_label(l,script->pos, p); + script->set_label(l, VECTOR_LENGTH(script->buf), p); if(script->syntax.curly[pos].flag) { //Exists default @@ -1595,7 +1558,7 @@ const char* parse_curly_close(const char* p) // Label end sprintf(label,"__SW%x_FIN", (unsigned int)script->syntax.curly[pos].index); l=script->add_str(label); - script->set_label(l,script->pos, p); + script->set_label(l, VECTOR_LENGTH(script->buf), p); linkdb_final(&script->syntax.curly[pos].case_label); // free the list of case label script->syntax.curly_count--; //Closing decision if, for , while @@ -1674,7 +1637,7 @@ const char* parse_syntax(const char* p) // You are here labeled sprintf(label,"__SW%x_%x", (unsigned int)script->syntax.curly[pos].index, (unsigned int)script->syntax.curly[pos].count); l=script->add_str(label); - script->set_label(l,script->pos, p); + script->set_label(l, VECTOR_LENGTH(script->buf), p); } //Decision statement switch p = script->skip_space(p2); @@ -1714,7 +1677,7 @@ const char* parse_syntax(const char* p) // Label after the completion of FALLTHRU sprintf(label, "__SW%x_%xJ", (unsigned int)script->syntax.curly[pos].index, (unsigned int)script->syntax.curly[pos].count); l=script->add_str(label); - script->set_label(l,script->pos,p); + script->set_label(l, VECTOR_LENGTH(script->buf), p); } // check duplication of case label [Rayce] if(linkdb_search(&script->syntax.curly[pos].case_label, (void*)h64BPTRSIZE(v)) != NULL) @@ -1781,7 +1744,7 @@ const char* parse_syntax(const char* p) } sprintf(label, "__SW%x_%x", (unsigned int)script->syntax.curly[pos].index, (unsigned int)script->syntax.curly[pos].count); l=script->add_str(label); - script->set_label(l,script->pos,p); + script->set_label(l, VECTOR_LENGTH(script->buf), p); // Skip to the next link w/o condition sprintf(label, "goto __SW%x_%x;", (unsigned int)script->syntax.curly[pos].index, (unsigned int)script->syntax.curly[pos].count + 1); @@ -1792,7 +1755,7 @@ const char* parse_syntax(const char* p) // The default label sprintf(label, "__SW%x_DEF", (unsigned int)script->syntax.curly[pos].index); l=script->add_str(label); - script->set_label(l,script->pos,p); + script->set_label(l, VECTOR_LENGTH(script->buf), p); script->syntax.curly[script->syntax.curly_count - 1].flag = 1; script->syntax.curly[pos].count++; @@ -1810,7 +1773,7 @@ const char* parse_syntax(const char* p) // Label of the (do) form here sprintf(label, "__DO%x_BGN", (unsigned int)script->syntax.curly[script->syntax.curly_count].index); l=script->add_str(label); - script->set_label(l,script->pos,p); + script->set_label(l, VECTOR_LENGTH(script->buf), p); script->syntax.curly_count++; return p; } @@ -1841,7 +1804,7 @@ const char* parse_syntax(const char* p) // Form the start of label decision sprintf(label, "__FR%x_J", (unsigned int)script->syntax.curly[pos].index); l=script->add_str(label); - script->set_label(l,script->pos,p); + script->set_label(l, VECTOR_LENGTH(script->buf), p); p=script->skip_space(p); if(*p == ';') { @@ -1870,7 +1833,7 @@ const char* parse_syntax(const char* p) // Labels to form the next loop sprintf(label, "__FR%x_NXT", (unsigned int)script->syntax.curly[pos].index); l=script->add_str(label); - script->set_label(l,script->pos,p); + script->set_label(l, VECTOR_LENGTH(script->buf), p); // Process the next time you enter the loop // A ')' last for; flag to be treated as' @@ -1889,7 +1852,7 @@ const char* parse_syntax(const char* p) // Loop start labeling sprintf(label, "__FR%x_BGN", (unsigned int)script->syntax.curly[pos].index); l=script->add_str(label); - script->set_label(l,script->pos,p); + script->set_label(l, VECTOR_LENGTH(script->buf), p); return p; } else if( p2 - p == 8 && strncmp(p, "function", 8) == 0 ) { // internal script function @@ -1939,9 +1902,9 @@ const char* parse_syntax(const char* p) if( script->str_data[l].type == C_NOP || script->str_data[l].type == C_USERFUNC )// register only, if the name was not used by something else { script->str_data[l].type = C_USERFUNC; - script->set_label(l, script->pos, p); + script->set_label(l, VECTOR_LENGTH(script->buf), p); if( script->parse_options&SCRIPT_USE_LABEL_DB ) - script->label_add(l,script->pos); + script->label_add(l, VECTOR_LENGTH(script->buf)); } else disp_error_message("parse_syntax:function: function name is invalid", func_name); @@ -2021,7 +1984,7 @@ const char* parse_syntax(const char* p) // Form the start of label decision sprintf(label, "__WL%x_NXT", (unsigned int)script->syntax.curly[script->syntax.curly_count].index); l=script->add_str(label); - script->set_label(l,script->pos,p); + script->set_label(l, VECTOR_LENGTH(script->buf), p); // Skip to the end point if the condition is false sprintf(label, "__WL%x_FIN", (unsigned int)script->syntax.curly[script->syntax.curly_count].index); @@ -2078,7 +2041,7 @@ const char* parse_syntax_close_sub(const char* p,int* flag) // Put the label of the location sprintf(label, "__IF%x_%x", (unsigned int)script->syntax.curly[pos].index, (unsigned int)script->syntax.curly[pos].count); l=script->add_str(label); - script->set_label(l,script->pos,p); + script->set_label(l, VECTOR_LENGTH(script->buf), p); script->syntax.curly[pos].count++; p = script->skip_space(p); @@ -2116,7 +2079,7 @@ const char* parse_syntax_close_sub(const char* p,int* flag) // Put the label of the final location sprintf(label, "__IF%x_FIN", (unsigned int)script->syntax.curly[pos].index); l=script->add_str(label); - script->set_label(l,script->pos,p); + script->set_label(l, VECTOR_LENGTH(script->buf), p); if(script->syntax.curly[pos].flag == 1) { // Because the position of the pointer is the same if not else for this return bp; @@ -2129,7 +2092,7 @@ const char* parse_syntax_close_sub(const char* p,int* flag) // (Come here continue) to form the label here sprintf(label, "__DO%x_NXT", (unsigned int)script->syntax.curly[pos].index); l=script->add_str(label); - script->set_label(l,script->pos,p); + script->set_label(l, VECTOR_LENGTH(script->buf), p); } // Skip to the end point if the condition is false @@ -2164,7 +2127,7 @@ const char* parse_syntax_close_sub(const char* p,int* flag) // Form label of the end point conditions sprintf(label, "__DO%x_FIN", (unsigned int)script->syntax.curly[pos].index); l=script->add_str(label); - script->set_label(l,script->pos,p); + script->set_label(l, VECTOR_LENGTH(script->buf), p); p = script->skip_space(p); if(*p != ';') { disp_error_message("parse_syntax: need ';'",p); @@ -2186,7 +2149,7 @@ const char* parse_syntax_close_sub(const char* p,int* flag) // End for labeling sprintf(label, "__FR%x_FIN", (unsigned int)script->syntax.curly[pos].index); l=script->add_str(label); - script->set_label(l,script->pos,p); + script->set_label(l, VECTOR_LENGTH(script->buf), p); script->syntax.curly_count--; return p; } else if(script->syntax.curly[pos].type == TYPE_WHILE) { @@ -2202,7 +2165,7 @@ const char* parse_syntax_close_sub(const char* p,int* flag) // End while labeling sprintf(label, "__WL%x_FIN", (unsigned int)script->syntax.curly[pos].index); l=script->add_str(label); - script->set_label(l,script->pos,p); + script->set_label(l, VECTOR_LENGTH(script->buf), p); script->syntax.curly_count--; return p; } else if(script->syntax.curly[pos].type == TYPE_USERFUNC) { @@ -2215,7 +2178,7 @@ const char* parse_syntax_close_sub(const char* p,int* flag) // Put the label of the location sprintf(label, "__FN%x_FIN", (unsigned int)script->syntax.curly[pos].index); l=script->add_str(label); - script->set_label(l,script->pos,p); + script->set_label(l, VECTOR_LENGTH(script->buf), p); script->syntax.curly_count--; return p; } else { @@ -2544,9 +2507,6 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o script->parse_cleanup_timer_id = timer->add(timer->gettick() + 10, script->parse_cleanup_timer, 0, 0); } - if( script->syntax.strings ) /* used only when generating translation file */ - db_destroy(script->syntax.strings); - memset(&script->syntax,0,sizeof(script->syntax)); script->syntax.last_func = -1;/* as valid values are >= 0 */ if( script->parser_current_npc_name ) { @@ -2556,11 +2516,7 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o script->syntax.translation_db = strdb_get(script->translation_db, script->parser_current_npc_name); } - if( !script->buf ) { - script->buf = (unsigned char *)aMalloc(SCRIPT_BLOCK_SIZE*sizeof(unsigned char)); - script->size = SCRIPT_BLOCK_SIZE; - } - script->pos=0; + VECTOR_TRUNCATE(script->buf); script->parse_nextline(true, NULL); // who called parse_script is responsible for clearing the database after using it, but just in case... lets clear it here @@ -2574,7 +2530,7 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o if( script->error_report ) script->error(src,file,line,script->error_msg,script->error_pos); aFree( script->error_msg ); - script->pos = 0; + VECTOR_TRUNCATE(script->buf); for(i=LABEL_START;i<script->str_num;i++) if(script->str_data[i].type == C_NOP) script->str_data[i].type = C_NAME; for(i=0; i<size; i++) @@ -2594,9 +2550,9 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o p=script->skip_space(p); if( options&SCRIPT_IGNORE_EXTERNAL_BRACKETS ) {// does not require brackets around the script - if( *p == '\0' && !(options&SCRIPT_RETURN_EMPTY_SCRIPT) ) - {// empty script and can return NULL - script->pos = 0; + if (*p == '\0' && !(options&SCRIPT_RETURN_EMPTY_SCRIPT)) { + // empty script and can return NULL + VECTOR_TRUNCATE(script->buf); #ifdef ENABLE_CASE_CHECK script->local_casecheck.clear(); script->parser_current_src = NULL; @@ -2614,9 +2570,9 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o if (retval) *retval = EXIT_FAILURE; } p = script->skip_space(p+1); - if( *p == '}' && !(options&SCRIPT_RETURN_EMPTY_SCRIPT) ) - {// empty script and can return NULL - script->pos = 0; + if (*p == '}' && !(options&SCRIPT_RETURN_EMPTY_SCRIPT)) { + // empty script and can return NULL + VECTOR_TRUNCATE(script->buf); #ifdef ENABLE_CASE_CHECK script->local_casecheck.clear(); script->parser_current_src = NULL; @@ -2648,9 +2604,9 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o tmpp=script->skip_space(script->skip_word(p)); if(*tmpp==':' && !(strncmp(p,"default:",8) == 0 && p + 7 == tmpp)) { i=script->add_word(p); - script->set_label(i,script->pos,p); + script->set_label(i, VECTOR_LENGTH(script->buf), p); if( script->parse_options&SCRIPT_USE_LABEL_DB ) - script->label_add(i,script->pos); + script->label_add(i, VECTOR_LENGTH(script->buf)); p=tmpp+1; p=script->skip_space(p); continue; @@ -2672,8 +2628,8 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o script->str_data[i].type=C_NAME; script->str_data[i].label=i; for (j = script->str_data[i].backpatch; j >= 0 && j != 0x00ffffff; ) { - int next = GETVALUE(script->buf,j); - SETVALUE(script->buf,j,i); + int next = GETVALUE(&script->buf, j); + SETVALUE(&script->buf, j, i); j = next; } } else if(script->str_data[i].type == C_USERFUNC) { @@ -2690,37 +2646,39 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o } #ifdef SCRIPT_DEBUG_DISP - for(i=0;i<script->pos;i++) { - if((i&15)==0) ShowMessage("%04x : ",i); - ShowMessage("%02x ",script->buf[i]); - if((i&15)==15) ShowMessage("\n"); + for (i = 0; i < VECTOR_LENGTH(script->buf); i++) { + if ((i&15) == 0) + ShowMessage("%04x : ",i); + ShowMessage("%02x ", VECTOR_INDEX(script->buf, i)); + if ((i&15) == 15) + ShowMessage("\n"); } ShowMessage("\n"); #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 < VECTOR_LENGTH(script->buf)) { + 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)); + ShowMessage(" %d", script->get_num(&script->buf, &i)); break; case C_POS: - ShowMessage(" 0x%06x", *(int*)(script->buf+i)&0xffffff); + ShowMessage(" 0x%06x", *(int*)(&VECTOR_INDEX(script->buf, i))&0xffffff); i += 3; break; case C_NAME: - j = (*(int*)(script->buf+i)&0xffffff); + j = (*(int*)(&VECTOR_INDEX(script->buf, i))&0xffffff); ShowMessage(" %s", ( j == 0xffffff ) ? "?? unknown ??" : script->get_str(j)); i += 3; break; case C_STR: - j = (int)strlen((char*)script->buf + i); - ShowMessage(" %s", script->buf + i); + j = (int)strlen((char*)&VECTOR_INDEX(script->buf, i)); + ShowMessage(" %s", &VECTOR_INDEX(script->buf, i)); i += j+1; break; } @@ -2729,9 +2687,9 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o #endif CREATE(code,struct script_code,1); - code->script_buf = (unsigned char *)aMalloc(script->pos*sizeof(unsigned char)); - memcpy(code->script_buf, script->buf, script->pos); - code->script_size = script->pos; + VECTOR_INIT(code->script_buf); + VECTOR_ENSURE(code->script_buf, VECTOR_LENGTH(script->buf), 1); + VECTOR_PUSHARRAY(code->script_buf, VECTOR_DATA(script->buf), VECTOR_LENGTH(script->buf)); code->local.vars = NULL; code->local.arrays = NULL; #ifdef ENABLE_CASE_CHECK @@ -3624,7 +3582,7 @@ void script_free_code(struct script_code* code) script->free_vars(code->local.vars); if (code->local.arrays) code->local.arrays->destroy(code->local.arrays,script->array_free_db); - aFree(code->script_buf); + VECTOR_CLEAR(code->script_buf); aFree(code); } @@ -3749,32 +3707,32 @@ void script_add_pending_ref(struct script_state *st, struct reg_db *ref) { /*========================================== * Read command *------------------------------------------*/ -c_op get_com(unsigned char *scriptbuf,int *pos) +c_op get_com(const struct script_buf *scriptbuf, int *pos) { int i = 0, j = 0; - if(scriptbuf[*pos]>=0x80) { + if (VECTOR_INDEX(*scriptbuf, *pos) >= 0x80) { return C_INT; } - while(scriptbuf[*pos]>=0x40) { - i=scriptbuf[(*pos)++]<<j; + while (VECTOR_INDEX(*scriptbuf, *pos) >= 0x40) { + i = VECTOR_INDEX(*scriptbuf, (*pos)++) << j; j+=6; } - return (c_op)(i+(scriptbuf[(*pos)++]<<j)); + return (c_op)(i+(VECTOR_INDEX(*scriptbuf, (*pos)++)<<j)); } /*========================================== * Income figures *------------------------------------------*/ -int get_num(unsigned char *scriptbuf,int *pos) +int get_num(const struct script_buf *scriptbuf, int *pos) { int i,j; i=0; j=0; - while(scriptbuf[*pos]>=0xc0) { - i+=(scriptbuf[(*pos)++]&0x7f)<<j; + while (VECTOR_INDEX(*scriptbuf, *pos) >= 0xc0) { + i+= (VECTOR_INDEX(*scriptbuf, (*pos)++)&0x7f)<<j; j+=6; } - return i+((scriptbuf[(*pos)++]&0x7f)<<j); + return i+((VECTOR_INDEX(*scriptbuf, (*pos)++)&0x7f)<<j); } /// Ternary operators @@ -3834,7 +3792,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); @@ -3875,8 +3833,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); @@ -4083,10 +4042,17 @@ void op_1(struct script_state* st, int op) /// /// @param st Script state whose stack arguments should be inspected. /// @param func Built-in function for which the arguments are intended. -void script_check_buildin_argtype(struct script_state* st, int func) +bool script_check_buildin_argtype(struct script_state* st, int func) { int idx, invalid = 0; - char* sf = script->buildin[script->str_data[func].val]; + char* sf; + if (script->str_data[func].val < 0 || script->str_data[func].val >= script->buildin_count) { + ShowDebug("Function: %s\n", script->get_str(func)); + ShowError("Script data corruption detected!\n"); + script->reportsrc(st); + return false; + } + sf = script->buildin[script->str_data[func].val]; for (idx = 2; script_hasdata(st, idx); idx++) { struct script_data* data = script_getdata(st, idx); @@ -4157,6 +4123,7 @@ void script_check_buildin_argtype(struct script_state* st, int func) ShowDebug("Function: %s\n", script->get_str(func)); script->reportsrc(st); } + return true; } /// Executes a buildin command. @@ -4194,7 +4161,11 @@ int run_func(struct script_state *st) } if( script->config.warn_func_mismatch_argtypes ) { - script->check_buildin_argtype(st, func); + if (script->check_buildin_argtype(st, func) == false) + { + st->state = END; + return 1; + } } if(script->str_data[func].func) { @@ -4393,7 +4364,7 @@ void run_script_main(struct script_state *st) { st->state = RUN; while( st->state == RUN ) { - enum c_op c = script->get_com(st->script->script_buf,&st->pos); + enum c_op c = script->get_com(&st->script->script_buf, &st->pos); switch(c) { case C_EOL: if( stack->defsp > stack->sp ) @@ -4402,27 +4373,29 @@ void run_script_main(struct script_state *st) { script->pop_stack(st, stack->defsp, stack->sp);// pop unused stack data. (unused return value) break; case C_INT: - script->push_val(stack,C_INT,script->get_num(st->script->script_buf,&st->pos),NULL); + script->push_val(stack,C_INT,script->get_num(&st->script->script_buf, &st->pos), NULL); break; case C_POS: case C_NAME: - script->push_val(stack,c,GETVALUE(st->script->script_buf,st->pos),NULL); + script->push_val(stack,c,GETVALUE(&st->script->script_buf, st->pos), NULL); st->pos+=3; break; case C_ARG: script->push_val(stack,c,0,NULL); break; case C_STR: - script->push_conststr(stack, (const char *)(st->script->script_buf+st->pos)); - while(st->script->script_buf[st->pos++]); + script->push_conststr(stack, (const char *)&VECTOR_INDEX(st->script->script_buf, st->pos)); + while (VECTOR_INDEX(st->script->script_buf, st->pos++) != 0) + (void)0; // Skip string break; case C_LSTR: { - int string_id = *((int *)(&st->script->script_buf[st->pos])); - uint8 translations = *((uint8 *)(&st->script->script_buf[st->pos+sizeof(int)])); struct map_session_data *lsd = NULL; - - st->pos += sizeof(int) + sizeof(uint8); + uint8 translations = 0; + int string_id = *((int *)(&VECTOR_INDEX(st->script->script_buf, st->pos))); + st->pos += sizeof(string_id); + translations = *((uint8 *)(&VECTOR_INDEX(st->script->script_buf, st->pos))); + st->pos += sizeof(translations); if( (!st->rid || !(lsd = map->id2sd(st->rid)) || !lsd->lang_id) && !map->default_lang_id ) script->push_conststr(stack, script->string_list+string_id); @@ -4431,7 +4404,7 @@ void run_script_main(struct script_state *st) { int offset = st->pos; for(k = 0; k < translations; k++) { - uint8 lang_id = *(uint8 *)(&st->script->script_buf[offset]); + uint8 lang_id = *(uint8 *)(&VECTOR_INDEX(st->script->script_buf, offset)); offset += sizeof(uint8); if( lang_id == wlang_id ) break; @@ -4440,7 +4413,7 @@ void run_script_main(struct script_state *st) { if (k == translations) script->push_conststr(stack, script->string_list+string_id); else - script->push_conststr(stack, *(const char**)(&st->script->script_buf[offset]) ); + script->push_conststr(stack, *(const char**)(&VECTOR_INDEX(st->script->script_buf, offset))); } st->pos += ( ( sizeof(char*) + sizeof(uint8) ) * translations ); } @@ -4854,9 +4827,6 @@ void do_final_script(void) script->clear_translations(false); script->parser_clean_leftovers(); - - if( script->lang_export_file ) - aFree(script->lang_export_file); } /** @@ -4878,7 +4848,7 @@ void script_load_translations(void) { const char *config_filename = "db/translations.conf"; // FIXME hardcoded name struct config_setting_t *translations = NULL; int i, size; - uint32 total = 0; + int total = 0; uint8 lang_id = 0, k; if (map->minimal) // No translations in minimal mode @@ -4915,24 +4885,22 @@ void script_load_translations(void) { for(i = 0; i < size; i++) { const char *translation_file = libconfig->setting_get_string_elem(translations, i); - script->load_translation(translation_file, ++lang_id, &total); + total += script->load_translation(translation_file, ++lang_id); } libconfig->destroy(&translations_conf); - if( total ) { - struct DBIterator *main_iter, *sub_iter; + if (total != 0) { + struct DBIterator *main_iter; struct DBMap *string_db; struct string_translation *st = NULL; - uint32 j = 0; - CREATE(script->translation_buf, char *, total); - script->translation_buf_size = total; + VECTOR_ENSURE(script->translation_buf, total, 1); 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) ) { - script->translation_buf[j++] = st->buf; + 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)) { + VECTOR_PUSH(script->translation_buf, st->buf); } dbi_destroy(sub_iter); } @@ -4954,52 +4922,75 @@ void script_load_translations(void) { } /** + * Generates a language name from a translation filename. * - **/ -const char * script_get_translation_file_name(const char *file) { - static char file_name[200]; - int i, len = (int)strlen(file), last_bar = -1, last_dot = -1; + * @param file The filename. + * @return The corresponding translation name. + */ +const char *script_get_translation_file_name(const char *file) +{ + const char *basename = NULL, *last_dot = NULL; - for(i = 0; i < len; i++) { - if( file[i] == '/' || file[i] == '\\' ) - last_bar = i; - else if ( file[i] == '.' ) - last_dot = i; + nullpo_retr("Unknown", file); + + basename = strrchr(file, '/');; +#ifdef WIN32 + { + const char *basename_windows = strrchr(file, '\\'); + if (basename_windows > basename) + basename = basename_windows; } +#endif // WIN32 + if (basename == NULL) + basename = file; + else + basename++; // Skip slash + Assert_retr("Unknown", *basename != '\0'); - if( last_bar != -1 || last_dot != -1 ) { - 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) )); + last_dot = strrchr(basename, '.'); + if (last_dot != NULL) { + static char file_name[200]; + if (last_dot == basename) + return basename + 1; + + safestrncpy(file_name, basename, last_dot - basename + 1); return file_name; } - return file; + return basename; } /** - * Parses a individual translation file - **/ -void script_load_translation(const char *file, uint8 lang_id, uint32 *total) { - uint32 translations = 0; + * Parses an individual translation file. + * + * @param file The filename to parse. + * @param lang_id The language identifier. + * @return The amount of strings loaded. + */ +int script_load_translation(const char *file, uint8 lang_id) +{ + int translations = 0; char line[1024]; char msgctxt[NAME_LENGTH*2+1] = { 0 }; struct DBMap *string_db; size_t i; FILE *fp; - struct script_string_buf msgid = { 0 }, msgstr = { 0 }; + struct script_string_buf msgid, msgstr; if( !(fp = fopen(file,"rb")) ) { ShowError("load_translation: failed to open '%s' for reading\n",file); - return; + return 0; } + VECTOR_INIT(msgid); + VECTOR_INIT(msgstr); + script->add_language(script->get_translation_file_name(file)); if( lang_id >= atcommand->max_message_table ) 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; @@ -5008,6 +4999,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] == '"' ) { @@ -5015,44 +5007,50 @@ 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'; } else if ( strncasecmp(line, "msgid \"", 7) == 0 ) { - msgid.pos = 0; + VECTOR_TRUNCATE(msgid); for(i = 7; i < len - 2; i++) { + VECTOR_ENSURE(msgid, 1, 512); if( line[i] == '\\' && line[i+1] == '"' ) { - script_string_buf_addb(&msgid, '"'); + VECTOR_PUSH(msgid, '"'); i++; - } else - script_string_buf_addb(&msgid, line[i]); + } else { + VECTOR_PUSH(msgid, line[i]); + } } - script_string_buf_addb(&msgid,0); + VECTOR_ENSURE(msgid, 1, 512); + VECTOR_PUSH(msgid, '\0'); } else if ( len > 9 && line[9] != '"' && strncasecmp(line, "msgstr \"",8) == 0 ) { - msgstr.pos = 0; + VECTOR_TRUNCATE(msgstr); for(i = 8; i < len - 2; i++) { + VECTOR_ENSURE(msgstr, 1, 512); if( line[i] == '\\' && line[i+1] == '"' ) { - script_string_buf_addb(&msgstr, '"'); + VECTOR_PUSH(msgstr, '"'); i++; - } else - script_string_buf_addb(&msgstr, line[i]); + } else { + VECTOR_PUSH(msgstr, line[i]); + } } - script_string_buf_addb(&msgstr,0); + VECTOR_ENSURE(msgstr, 1, 512); + VECTOR_PUSH(msgstr, '\0'); } - if( msgctxt[0] && msgid.pos > 1 && msgstr.pos > 1 ) { - size_t msgstr_len = msgstr.pos; + if( msgctxt[0] && VECTOR_LENGTH(msgid) > 1 && VECTOR_LENGTH(msgstr) > 1 ) { + int msgstr_len = VECTOR_LENGTH(msgstr); unsigned int inner_len = 1 + (uint32)msgstr_len + 1; //uint8 lang_id + msgstr_len + '\0' if( strcasecmp(msgctxt, "messages.conf") == 0 ) { int k; for(k = 0; k < MAX_MSG; k++) { - if( atcommand->msg_table[0][k] && strcmpi(atcommand->msg_table[0][k],msgid.ptr) == 0 ) { + if( atcommand->msg_table[0][k] && strcmpi(atcommand->msg_table[0][k], VECTOR_DATA(msgid)) == 0 ) { if( atcommand->msg_table[lang_id][k] ) aFree(atcommand->msg_table[lang_id][k]); - atcommand->msg_table[lang_id][k] = aStrdup(msgstr.ptr); + atcommand->msg_table[lang_id][k] = aStrdup(VECTOR_DATA(msgstr)); break; } } @@ -5064,33 +5062,33 @@ void script_load_translation(const char *file, uint8 lang_id, uint32 *total) { strdb_put(script->translation_db, msgctxt, string_db); } - if( !(st = strdb_get(string_db, msgid.ptr) ) ) { + if ((st = strdb_get(string_db, VECTOR_DATA(msgid))) == NULL) { CREATE(st, struct string_translation, 1); - st->string_id = script->string_dup(msgid.ptr); - strdb_put(string_db, msgid.ptr, st); + st->string_id = script->string_dup(VECTOR_DATA(msgid)); + strdb_put(string_db, VECTOR_DATA(msgid), st); } - RECREATE(st->buf, char, st->len + inner_len); + RECREATE(st->buf, uint8, st->len + inner_len); WBUFB(st->buf, st->len) = lang_id; - safestrncpy(WBUFP(st->buf, st->len + 1), msgstr.ptr, msgstr_len + 1); + safestrncpy(WBUFP(st->buf, st->len + 1), VECTOR_DATA(msgstr), msgstr_len + 1); st->translations++; st->len += inner_len; } msgctxt[0] = '\0'; - msgid.pos = msgstr.pos = 0; + VECTOR_TRUNCATE(msgid); + VECTOR_TRUNCATE(msgstr); translations++; } } - *total += translations; - fclose(fp); - script_string_buf_destroy(&msgid); - script_string_buf_destroy(&msgstr); + VECTOR_CLEAR(msgid); + VECTOR_CLEAR(msgstr); - ShowStatus("Done reading '"CL_WHITE"%u"CL_RESET"' translations in '"CL_WHITE"%s"CL_RESET"'.\n", translations, file); + ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' translations in '"CL_WHITE"%s"CL_RESET"'.\n", translations, file); + return translations; } /** @@ -5106,15 +5104,10 @@ void script_clear_translations(bool reload) { script->string_list_pos = 0; script->string_list_size = 0; - if( script->translation_buf ) { - for(i = 0; i < script->translation_buf_size; i++) { - aFree(script->translation_buf[i]); - } - aFree(script->translation_buf); + while (VECTOR_LENGTH(script->translation_buf) > 0) { + aFree(VECTOR_POP(script->translation_buf)); } - - script->translation_buf = NULL; - script->translation_buf_size = 0; + VECTOR_CLEAR(script->translation_buf); if( script->languages ) { for(i = 0; i < script->max_lang_id; i++) @@ -5156,26 +5149,16 @@ int script_translation_db_destroyer(union DBKey key, struct DBData *data, va_lis /** * **/ -void script_parser_clean_leftovers(void) { - if( script->buf ) - aFree(script->buf); - - script->buf = NULL; - script->size = 0; +void script_parser_clean_leftovers(void) +{ + VECTOR_CLEAR(script->buf); if( script->translation_db ) { script->translation_db->destroy(script->translation_db,script->translation_db_destroyer); script->translation_db = NULL; } - if( script->syntax.strings ) { /* used only when generating translation file */ - db_destroy(script->syntax.strings); - script->syntax.strings = NULL; - } - - script_string_buf_destroy(&script->parse_simpleexpr_str); - script_string_buf_destroy(&script->lang_export_line_buf); - script_string_buf_destroy(&script->lang_export_unescaped_buf); + VECTOR_CLEAR(script->parse_simpleexpr_strbuf); } /** @@ -5194,6 +5177,7 @@ int script_parse_cleanup_timer(int tid, int64 tick, int id, intptr_t data) { *------------------------------------------*/ void do_init_script(bool minimal) { script->parse_cleanup_timer_id = INVALID_TIMER; + VECTOR_INIT(script->parse_simpleexpr_strbuf); script->st_db = idb_alloc(DB_OPT_BASE); script->userfunc_db = strdb_alloc(DB_OPT_DUP_KEY,0); @@ -5280,6 +5264,232 @@ const char *script_getfuncname(struct script_state *st) { return NULL; } +/** + * Writes a string to a StringBuf by combining a format string and a set of + * arguments taken from the current script state (caller script function + * arguments). + * + * @param[in] st Script state (must have at least a string at index + * 'start'). + * @param[in] start Index of the format string argument. + * @param[out] out Output string buffer (managed by the caller, must be + * already initialized) + * @retval false if an error occurs. + */ +bool script_sprintf(struct script_state *st, int start, struct StringBuf *out) +{ + const char *format = NULL; + const char *p = NULL, *np = NULL; + char *buf = NULL; + int buf_len = 0; + int lastarg = start; + int argc = script_lastdata(st) + 1; + + Assert_retr(-1, start >= 2 && start <= argc); + Assert_retr(-1, script_hasdata(st, start)); + + p = format = script_getstr(st, start); + + /* + * format-string = "" / *(text / placeholder) + * placeholder = "%%" / "%n" / std-placeholder + * std-placeholder = "%" [pos-parameter] [flags] [width] [precision] [length] type + * pos-parameter = number "$" + * flags = *("-" / "+" / "0" / SP) + * width = number / ("*" [pos-parameter]) + * precision = "." (number / ("*" [pos-parameter])) + * length = "hh" / "h" / "l" / "ll" / "L" / "z" / "j" / "t" + * type = "d" / "i" / "u" / "f" / "F" / "e" / "E" / "g" / "G" / "x" / "X" / "o" / "s" / "c" / "p" / "a" / "A" + * number = digit-nonzero *DIGIT + * digit-nonzero = "1" / "2" / "3" / "4" / "5" / "6" / "7" / "8" / "9" + */ + + while ((np = strchr(p, '%')) != NULL) { + bool flag_plus = false, flag_minus = false, flag_zero = false, flag_space = false; + bool positional_arg = false; + int width = 0, nextarg = lastarg + 1, thisarg = nextarg; + + if (p != np) { + int len = (int)(np - p + 1); + if (buf_len < len) { + RECREATE(buf, char, len); + buf_len = len; + } + safestrncpy(buf, p, len); + StrBuf->AppendStr(out, buf); + } + + p = np; + np++; + + // placeholder = "%%" ; (special case) + if (*np == '%') { + StrBuf->AppendStr(out, "%"); + p = np + 1; + continue; + } + // placeholder = "%n" ; (ignored) + if (*np == 'n') { + ShowWarning("script_sprintf: Format %%n not supported! Skipping...\n"); + script->reportsrc(st); + lastarg = nextarg; + p = np + 1; + continue; + } + + // std-placeholder = "%" [pos-parameter] [flags] [width] [precision] [length] type + + // pos-parameter = number "$" + if (ISDIGIT(*np) && *np != '0') { + const char *pp = np; + while (ISDIGIT(*pp)) + pp++; + if (*pp == '$') { + thisarg = atoi(np) + start; + positional_arg = true; + np = pp + 1; + } + } + + if (thisarg >= argc) { + ShowError("buildin_sprintf: Not enough arguments passed!\n"); + if (buf != NULL) + aFree(buf); + return false; + } + + // flags = *("-" / "+" / "0" / SP) + while (true) { + if (*np == '-') { + flag_minus = true; + } else if (*np == '+') { + flag_plus = true; + } else if (*np == ' ') { + flag_space = true; + } else if (*np == '0') { + flag_zero = true; + } else { + break; + } + np++; + } + + // width = number / ("*" [pos-parameter]) + if (ISDIGIT(*np)) { + width = atoi(np); + while (ISDIGIT(*np)) + np++; + } else if (*np == '*') { + bool positional_widtharg = false; + int width_arg; + np++; + // pos-parameter = number "$" + if (ISDIGIT(*np) && *np != '0') { + const char *pp = np; + while (ISDIGIT(*pp)) + pp++; + if (*pp == '$') { + width_arg = atoi(np) + start; + positional_widtharg = true; + np = pp + 1; + } + } + if (!positional_widtharg) { + width_arg = nextarg; + nextarg++; + if (!positional_arg) + thisarg++; + } + + if (width_arg >= argc || thisarg >= argc) { + ShowError("buildin_sprintf: Not enough arguments passed!\n"); + if (buf != NULL) + aFree(buf); + return false; + } + width = script_getnum(st, width_arg); + } + + // precision = "." (number / ("*" [pos-parameter])) ; (not needed/implemented) + + // length = "hh" / "h" / "l" / "ll" / "L" / "z" / "j" / "t" ; (not needed/implemented) + + // type = "d" / "i" / "u" / "f" / "F" / "e" / "E" / "g" / "G" / "x" / "X" / "o" / "s" / "c" / "p" / "a" / "A" + if (buf_len < 16) { + RECREATE(buf, char, 16); + buf_len = 16; + } + { + int i = 0; + memset(buf, '\0', buf_len); + buf[i++] = '%'; + if (flag_minus) + buf[i++] = '-'; + if (flag_plus) + buf[i++] = '+'; + else if (flag_space) // ignored if '+' is specified + buf[i++] = ' '; + if (flag_zero) + buf[i++] = '0'; + if (width > 0) + safesnprintf(buf + i, buf_len - i - 1, "%d", width); + } + buf[(int)strlen(buf)] = *np; + switch (*np) { + case 'd': + case 'i': + case 'u': + case 'x': + case 'X': + case 'o': + // Piggyback printf + StrBuf->Printf(out, buf, script_getnum(st, thisarg)); + break; + case 's': + // Piggyback printf + StrBuf->Printf(out, buf, script_getstr(st, thisarg)); + break; + case 'c': + { + const char *str = script_getstr(st, thisarg); + // Piggyback printf + StrBuf->Printf(out, buf, str[0]); + } + break; + case 'f': + case 'F': + case 'e': + case 'E': + case 'g': + case 'G': + case 'p': + case 'a': + case 'A': + ShowWarning("buildin_sprintf: Format %%%c not supported! Skipping...\n", *np); + script->reportsrc(st); + lastarg = nextarg; + p = np + 1; + continue; + default: + ShowError("buildin_sprintf: Invalid format string.\n"); + if (buf != NULL) + aFree(buf); + return false; + } + lastarg = nextarg; + p = np + 1; + } + + // Append the remaining part + if (p != NULL) + StrBuf->AppendStr(out, p); + + if (buf != NULL) + aFree(buf); + + return true; +} + //----------------------------------------------------------------------------- // buildin functions // @@ -5295,20 +5505,42 @@ const char *script_getfuncname(struct script_state *st) { BUILDIN(mes) { struct map_session_data *sd = script->rid2sd(st); - if( sd == NULL ) + if (sd == NULL) return true; - if( !script_hasdata(st, 3) ) {// only a single line detected in the script - clif->scriptmes(sd, st->oid, script_getstr(st, 2)); - } else {// parse multiple lines as they exist - int i; + clif->scriptmes(sd, st->oid, script_getstr(st, 2)); - for( i = 2; script_hasdata(st, i); i++ ) { - // send the message to the client - clif->scriptmes(sd, st->oid, script_getstr(st, i)); - } + return true; +} + +/** + * Appends a message to the npc dialog, applying format string conversions (see + * sprintf). + * + * If a dialog doesn't exist yet, one is created. + * + * @code + * mes "<message>"; + * @endcode + */ +BUILDIN(mesf) +{ + struct map_session_data *sd = script->rid2sd(st); + struct StringBuf buf; + + if (sd == NULL) + return true; + + StrBuf->Init(&buf); + + if (!script_sprintf(st, 2, &buf)) { + StrBuf->Destroy(&buf); + return false; } + clif->scriptmes(sd, st->oid, StrBuf->Value(&buf)); + StrBuf->Destroy(&buf); + return true; } @@ -8384,7 +8616,7 @@ BUILDIN(getbrokenid) num=script_getnum(st,2); for(i=0; i<MAX_INVENTORY; i++) { - if(sd->status.inventory[i].attribute) { + if ((sd->status.inventory[i].attribute & ATTR_BROKEN) != 0) { brokencounter++; if(num==brokencounter) { id=sd->status.inventory[i].nameid; @@ -8409,7 +8641,7 @@ BUILDIN(getbrokencount) return true; for (i = 0; i < MAX_INVENTORY; i++) { - if (sd->status.inventory[i].attribute) + if ((sd->status.inventory[i].attribute & ATTR_BROKEN) != 0) counter++; } @@ -8431,10 +8663,11 @@ BUILDIN(repair) num=script_getnum(st,2); for(i=0; i<MAX_INVENTORY; i++) { - if(sd->status.inventory[i].attribute) { + if ((sd->status.inventory[i].attribute & ATTR_BROKEN) != 0) { repaircounter++; if(num==repaircounter) { - sd->status.inventory[i].attribute=0; + sd->status.inventory[i].attribute |= ATTR_BROKEN; + sd->status.inventory[i].attribute ^= ATTR_BROKEN; clif->equiplist(sd); clif->produce_effect(sd, 0, sd->status.inventory[i].nameid); clif->misceffect(&sd->bl, 3); @@ -8458,9 +8691,10 @@ BUILDIN(repairall) for(i = 0; i < MAX_INVENTORY; i++) { - if(sd->status.inventory[i].nameid && sd->status.inventory[i].attribute) + if (sd->status.inventory[i].nameid && (sd->status.inventory[i].attribute & ATTR_BROKEN) != 0) { - sd->status.inventory[i].attribute = 0; + sd->status.inventory[i].attribute |= ATTR_BROKEN; + sd->status.inventory[i].attribute ^= ATTR_BROKEN; clif->produce_effect(sd,0,sd->status.inventory[i].nameid); repaircounter++; } @@ -10085,6 +10319,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; @@ -10507,7 +10742,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; @@ -10515,6 +10751,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 @@ -10539,14 +10777,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; } @@ -10554,10 +10792,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); @@ -10604,7 +10842,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); @@ -10614,17 +10853,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); @@ -10638,12 +10880,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; } @@ -13782,7 +14026,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; @@ -15229,130 +15473,19 @@ BUILDIN(implode) // Implements C sprintf, except format %n. The resulting string is // returned, instead of being saved in variable by reference. //------------------------------------------------------- -BUILDIN(sprintf) { - unsigned int argc = 0, arg = 0; - const char* format; - char* p; - char* q; - char* buf = NULL; - char* buf2 = NULL; - struct script_data* data; - size_t len, buf2_len = 0; - StringBuf final_buf; - - // Fetch init data - format = script_getstr(st, 2); - argc = script_lastdata(st)-2; - len = strlen(format); - - // Skip parsing, where no parsing is required. - if(len==0) { - script_pushconststr(st,""); - return true; - } - - // Pessimistic alloc - CREATE(buf, char, len+1); - - // Need not be parsed, just solve stuff like %%. - if(argc==0) { - memcpy(buf,format,len+1); - script_pushstrcopy(st, buf); - aFree(buf); - return true; - } - - safestrncpy(buf, format, len+1); - - // Issue sprintf for each parameter - StrBuf->Init(&final_buf); - q = buf; - while((p = strchr(q, '%'))!=NULL) { - if(p!=q) { - len = p-q+1; - if(buf2_len<len) { - RECREATE(buf2, char, len); - buf2_len = len; - } - safestrncpy(buf2, q, len); - StrBuf->AppendStr(&final_buf, buf2); - q = p; - } - p = q+1; - if(*p=='%') { // %% - StrBuf->AppendStr(&final_buf, "%"); - q+=2; - continue; - } - if(*p=='n') { // %n - ShowWarning("buildin_sprintf: Format %%n not supported! Skipping...\n"); - script->reportsrc(st); - q+=2; - continue; - } - if(arg>=argc) { - ShowError("buildin_sprintf: Not enough arguments passed!\n"); - aFree(buf); - if(buf2) aFree(buf2); - StrBuf->Destroy(&final_buf); - script_pushconststr(st,""); - return false; - } - if((p = strchr(q+1, '%'))==NULL) { - p = strchr(q, 0); // EOS - } - len = p-q+1; - if(buf2_len<len) { - RECREATE(buf2, char, len); - buf2_len = len; - } - safestrncpy(buf2, q, len); - q = p; - - // Note: This assumes the passed value being the correct - // type to the current format specifier. If not, the server - // probably crashes or returns anything else, than expected, - // but it would behave in normal code the same way so it's - // the scripter's responsibility. - data = script_getdata(st, arg+3); - if(data_isstring(data)) { // String - StrBuf->Printf(&final_buf, buf2, script_getstr(st, arg+3)); - } else if(data_isint(data)) { // Number - StrBuf->Printf(&final_buf, buf2, script_getnum(st, arg+3)); - } else if(data_isreference(data)) { // Variable - char* name = reference_getname(data); - if(name[strlen(name)-1]=='$') { // var Str - StrBuf->Printf(&final_buf, buf2, script_getstr(st, arg+3)); - } else { // var Int - StrBuf->Printf(&final_buf, buf2, script_getnum(st, arg+3)); - } - } else { // Unsupported type - ShowError("buildin_sprintf: Unknown argument type!\n"); - aFree(buf); - if(buf2) aFree(buf2); - StrBuf->Destroy(&final_buf); - script_pushconststr(st,""); - return false; - } - arg++; - } - - // Append anything left - if(*q) { - StrBuf->AppendStr(&final_buf, q); - } +BUILDIN(sprintf) +{ + struct StringBuf buf; + StrBuf->Init(&buf); - // Passed more, than needed - if(arg<argc) { - ShowWarning("buildin_sprintf: Unused arguments passed.\n"); - script->reportsrc(st); + if (!script_sprintf(st, 2, &buf)) { + StrBuf->Destroy(&buf); + script_pushconststr(st, ""); + return false; } - script_pushstrcopy(st, StrBuf->Value(&final_buf)); - - aFree(buf); - if(buf2) aFree(buf2); - StrBuf->Destroy(&final_buf); + script_pushstrcopy(st, StrBuf->Value(&buf)); + StrBuf->Destroy(&buf); return true; } @@ -16479,7 +16612,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); @@ -18017,7 +18150,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); @@ -18026,8 +18160,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 ) @@ -18041,7 +18176,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; } @@ -18631,22 +18766,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); } @@ -18869,68 +18993,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; @@ -20272,8 +20334,10 @@ bool script_add_builtin(const struct script_function *buildin, bool override) { else if( strcmp(buildin->name, "callfunc") == 0 ) script->buildin_callfunc_ref = n; else if( strcmp(buildin->name, "getelementofarray") == 0 ) script->buildin_getelementofarray_ref = n; else if( strcmp(buildin->name, "mes") == 0 ) script->buildin_mes_offset = script->buildin_count; + else if( strcmp(buildin->name, "mesf") == 0 ) script->buildin_mesf_offset = script->buildin_count; else if( strcmp(buildin->name, "select") == 0 ) script->buildin_select_offset = script->buildin_count; else if( strcmp(buildin->name, "_") == 0 ) script->buildin_lang_macro_offset = script->buildin_count; + else if( strcmp(buildin->name, "_$") == 0 ) script->buildin_lang_macro_fmtstring_offset = script->buildin_count; offset = script->buildin_count; @@ -20367,7 +20431,8 @@ void script_parse_builtin(void) { BUILDIN_DEF(__setr,"rv?"), // NPC interaction - BUILDIN_DEF(mes,"s*"), + BUILDIN_DEF(mes,"s"), + BUILDIN_DEF(mesf,"s*"), BUILDIN_DEF(next,""), BUILDIN_DEF(close,""), BUILDIN_DEF(close2,""), @@ -20879,6 +20944,7 @@ void script_parse_builtin(void) { BUILDIN_DEF(showscript, "s?"), BUILDIN_DEF(mergeitem,""), BUILDIN_DEF(_,"s"), + BUILDIN_DEF2(_, "_$", "s"), }; int i, len = ARRAYLENGTH(BUILDIN); RECREATE(script->buildin, char *, script->buildin_count + len); // Pre-alloc to speed up @@ -21112,8 +21178,8 @@ void script_defaults(void) { script->label_count = 0; script->labels_size = 0; - script->buf = NULL; - script->pos = 0, script->size = 0; + VECTOR_INIT(script->buf); + VECTOR_INIT(script->translation_buf); script->parse_options = 0; script->buildin_set_ref = 0; @@ -21239,6 +21305,11 @@ void script_defaults(void) { script->parse_nextline = parse_nextline; script->parse_variable = parse_variable; script->parse_simpleexpr = parse_simpleexpr; + script->parse_simpleexpr_paren = parse_simpleexpr_paren; + script->parse_simpleexpr_number = parse_simpleexpr_number; + script->parse_simpleexpr_string = parse_simpleexpr_string; + script->parse_simpleexpr_name = parse_simpleexpr_name; + script->add_translatable_string = script_add_translatable_string; script->parse_expr = parse_expr; script->parse_line = parse_line; script->read_constdb = read_constdb; diff --git a/src/map/script.h b/src/map/script.h index a1fbe31f0..4df8941b7 100644 --- a/src/map/script.h +++ b/src/map/script.h @@ -394,11 +394,20 @@ struct script_data { struct reg_db *ref; ///< Reference to the scope's variables }; +/** + * A script string buffer, used to hold strings used by the script engine. + */ +VECTOR_STRUCT_DECL(script_string_buf, char); + +/** + * Script buffer, used to hold parsed script data. + */ +VECTOR_STRUCT_DECL(script_buf, unsigned char); + // Moved defsp from script_state to script_stack since // it must be saved when script state is RERUNLINE. [Eoe / jA 1094] struct script_code { - int script_size; - unsigned char *script_buf; + struct script_buf script_buf; struct reg_db local; ///< Local (npc) vars unsigned short instances; }; @@ -493,8 +502,8 @@ struct script_syntax_data { int index; // Number of the syntax used in the script 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; - struct DBMap *strings; // string map parsed (used when exporting strings only) + bool lang_macro_active; // Used to generate translation strings + bool lang_macro_fmtstring_active; // Used to generate translation strings struct DBMap *translation_db; //non-null if this npc has any translated strings to be linked }; @@ -517,16 +526,16 @@ struct script_array { unsigned int *members;/* member list */ }; -struct script_string_buf { - char *ptr; - size_t pos,size; +struct string_translation_entry { + uint8 lang_id; + char string[]; }; struct string_translation { int string_id; uint8 translations; - unsigned int len; - char *buf; + int len; + uint8 *buf; // Array of struct string_translation_entry }; /** @@ -576,8 +585,7 @@ struct script_interface { /* */ /// temporary buffer for passing around compiled bytecode /// @see add_scriptb, set_label, parse_script - unsigned char* buf; - int pos, size; + struct script_buf buf; /* */ struct script_syntax_data syntax; /* */ @@ -611,26 +619,22 @@ struct script_interface { /* */ unsigned int *generic_ui_array; unsigned int generic_ui_array_size; - /* Set during startup when attempting to export the lang, unset after server initialization is over */ - FILE *lang_export_fp; - char *lang_export_file;/* for lang_export_fp */ /* set and unset on npc_parse_script */ const char *parser_current_npc_name; /* */ int buildin_mes_offset; + int buildin_mesf_offset; int buildin_select_offset; int buildin_lang_macro_offset; + int buildin_lang_macro_fmtstring_offset; /* */ struct DBMap *translation_db;/* npc_name => DBMap (strings) */ - char **translation_buf;/* */ - uint32 translation_buf_size; + VECTOR_DECL(uint8 *) translation_buf; /* */ char **languages; uint8 max_lang_id; /* */ - struct script_string_buf parse_simpleexpr_str; - struct script_string_buf lang_export_line_buf; - struct script_string_buf lang_export_unescaped_buf; + struct script_string_buf parse_simpleexpr_strbuf; /* */ int parse_cleanup_timer_id; /* */ @@ -706,8 +710,8 @@ struct script_interface { const char * (*parse_syntax_close) (const char *p); const char * (*parse_syntax_close_sub) (const char *p, int *flag); const char * (*parse_syntax) (const char *p); - c_op (*get_com) (unsigned char *scriptbuf, int *pos); - int (*get_num) (unsigned char *scriptbuf, int *pos); + c_op (*get_com) (const struct script_buf *scriptbuf, int *pos); + int (*get_num) (const struct script_buf *scriptbuf, int *pos); const char* (*op2name) (int op); void (*reportsrc) (struct script_state *st); void (*reportdata) (struct script_data *data); @@ -724,10 +728,15 @@ struct script_interface { int (*add_word) (const char *p); const char* (*parse_callfunc) (const char *p, int require_paren, int is_custom); void (*parse_nextline) (bool first, const char *p); - const char* (*parse_variable) (const char *p); - const char* (*parse_simpleexpr) (const char *p); - const char* (*parse_expr) (const char *p); - const char* (*parse_line) (const char *p); + const char *(*parse_variable) (const char *p); + const char *(*parse_simpleexpr) (const char *p); + const char *(*parse_simpleexpr_paren) (const char *p); + const char *(*parse_simpleexpr_number) (const char *p); + const char *(*parse_simpleexpr_string) (const char *p); + const char *(*parse_simpleexpr_name) (const char *p); + void (*add_translatable_string) (const struct script_string_buf *string, const char *start_point); + const char *(*parse_expr) (const char *p); + const char *(*parse_line) (const char *p); void (*read_constdb) (void); void (*constdb_comment) (const char *comment); void (*load_parameters) (void); @@ -749,7 +758,7 @@ struct script_interface { void (*op_2num) (struct script_state *st, int op, int i1, int i2); void (*op_2) (struct script_state *st, int op); void (*op_1) (struct script_state *st, int op); - void (*check_buildin_argtype) (struct script_state *st, int func); + bool (*check_buildin_argtype) (struct script_state *st, int func); void (*detach_state) (struct script_state *st, bool dequeue_event); int (*db_free_code_sub) (union DBKey key, struct DBData *data, va_list ap); void (*add_autobonus) (const char *autobonus); @@ -807,7 +816,7 @@ struct script_interface { unsigned short (*mapindexname2id) (struct script_state *st, const char* name); int (*string_dup) (char *str); void (*load_translations) (void); - void (*load_translation) (const char *file, uint8 lang_id, uint32 *total); + int (*load_translation) (const char *file, uint8 lang_id); 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); diff --git a/src/map/skill.c b/src/map/skill.c index fb0d54e23..dceebb5b2 100644 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -84,7 +84,8 @@ struct s_skill_dbs skilldbs; struct skill_interface *skill; //Since only mob-casted splash skills can hit ice-walls -static inline int splash_target(struct block_list* bl) { +int skill_splash_target(struct block_list* bl) +{ #ifndef RENEWAL return ( bl->type == BL_MOB ) ? BL_SKILL|BL_CHAR : BL_CHAR; #else // Some skills can now hit ground skills(traps, ice wall & etc.) @@ -2006,7 +2007,7 @@ int skill_break_equip (struct block_list *bl, unsigned short where, int rate, in if (sd) { for (i = 0; i < EQI_MAX; i++) { int j = sd->equip_index[i]; - if (j < 0 || sd->status.inventory[j].attribute == 1 || !sd->inventory_data[j]) + if (j < 0 || (sd->status.inventory[j].attribute & ATTR_BROKEN) != 0 || !sd->inventory_data[j]) continue; switch(i) { @@ -2032,7 +2033,7 @@ int skill_break_equip (struct block_list *bl, unsigned short where, int rate, in continue; } if (flag) { - sd->status.inventory[j].attribute = 1; + sd->status.inventory[j].attribute |= ATTR_BROKEN; pc->unequipitem(sd, j, PCUNEQUIPITEM_RECALC|PCUNEQUIPITEM_FORCE); } } @@ -2069,12 +2070,12 @@ int skill_strip_equip(struct block_list *bl, unsigned short where, int rate, int return where?1:0; } /*========================================================================= - Used to knock back players, monsters, traps, etc - - 'count' is the number of squares to knock back - - 'direction' indicates the way OPPOSITE to the knockback direction (or -1 for default behavior) - - if 'flag&0x1', position update packets must not be sent. - - if 'flag&0x2', skill blown ignores players' special_state.no_knockback - -------------------------------------------------------------------------*/ + * Used to knock back players, monsters, traps, etc + * 'count' is the number of squares to knock back + * 'direction' indicates the way OPPOSITE to the knockback direction (or -1 for default behavior) + * if 'flag&0x1', position update packets must not be sent. + * if 'flag&0x2', skill blown ignores players' special_state.no_knockback + */ int skill_blown(struct block_list* src, struct block_list* target, int count, int8 dir, int flag) { int dx = 0, dy = 0; @@ -2891,11 +2892,11 @@ void skill_attack_display_unknown(int *attack_type, struct block_list* src, stru } int skill_attack_copy_unknown(int *attack_type, struct block_list* src, struct block_list *dsrc, struct block_list *bl, uint16 *skill_id, uint16 *skill_lv, int64 *tick, int *flag) { - return *skill_id; + return *skill_id; } int skill_attack_dir_unknown(int *attack_type, struct block_list* src, struct block_list *dsrc, struct block_list *bl, uint16 *skill_id, uint16 *skill_lv, int64 *tick, int *flag) { - return -1; + return -1; } void skill_attack_blow_unknown(int *attack_type, struct block_list* src, struct block_list *dsrc, struct block_list *bl, uint16 *skill_id, uint16 *skill_lv, int64 *tick, int *flag, int *type, struct Damage *dmg, int64 *damage, int8 *dir) { @@ -3745,7 +3746,7 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1 if (!(flag&1) && sc && sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_MONK) { //Becomes a splash attack when Soul Linked. map->foreachinrange(skill->area_sub, bl, - skill->get_splash(skill_id, skill_lv),splash_target(src), + skill->get_splash(skill_id, skill_lv),skill->splash_target(src), src,skill_id,skill_lv,tick, flag|BCT_ENEMY|1, skill->castend_damage_id); } else @@ -3756,7 +3757,7 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1 clif->skill_nodamage(src,bl,skill_id,skill_lv,1); skill->area_temp[1] = 0; map->foreachinrange(skill->attack_area, src, - skill->get_splash(skill_id, skill_lv), splash_target(src), + skill->get_splash(skill_id, skill_lv), skill->splash_target(src), BF_WEAPON, src, src, skill_id, skill_lv, tick, flag, BCT_ENEMY); break; @@ -3792,7 +3793,7 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1 //line of sight between caster and target. skill->area_temp[1] = bl->id; map->foreachinpath(skill->attack_area,src->m,src->x,src->y,bl->x,bl->y, - skill->get_splash(skill_id, skill_lv),skill->get_maxcount(skill_id,skill_lv), splash_target(src), + skill->get_splash(skill_id, skill_lv),skill->get_maxcount(skill_id,skill_lv), skill->splash_target(src), skill->get_type(skill_id),src,src,skill_id,skill_lv,tick,flag,BCT_ENEMY); break; @@ -3803,7 +3804,7 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1 case NPC_THUNDERBREATH: skill->area_temp[1] = bl->id; map->foreachinpath(skill->attack_area,src->m,src->x,src->y,bl->x,bl->y, - skill->get_splash(skill_id, skill_lv),skill->get_maxcount(skill_id,skill_lv), splash_target(src), + skill->get_splash(skill_id, skill_lv),skill->get_maxcount(skill_id,skill_lv), skill->splash_target(src), skill->get_type(skill_id),src,src,skill_id,skill_lv,tick,flag,BCT_ENEMY); break; @@ -4006,7 +4007,7 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1 skill->area_temp[0] = map->foreachinrange(skill->area_sub, bl, (skill_id == AS_SPLASHER)?1:skill->get_splash(skill_id, skill_lv), BL_CHAR, src, skill_id, skill_lv, tick, BCT_ENEMY, skill->area_sub_count); // recursive invocation of skill->castend_damage_id() with flag|1 - map->foreachinrange(skill->area_sub, bl, skill->get_splash(skill_id, skill_lv), splash_target(src), src, skill_id, skill_lv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill->castend_damage_id); + map->foreachinrange(skill->area_sub, bl, skill->get_splash(skill_id, skill_lv), skill->splash_target(src), src, skill_id, skill_lv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill->castend_damage_id); } break; @@ -4087,9 +4088,9 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1 // Splash around target cell, but only cells inside area; we first have to check the area is not negative if((max(min_x,tx-1) <= min(max_x,tx+1)) && (max(min_y,ty-1) <= min(max_y,ty+1)) && - (map->foreachinarea(skill->area_sub, bl->m, max(min_x,tx-1), max(min_y,ty-1), min(max_x,tx+1), min(max_y,ty+1), splash_target(src), src, skill_id, skill_lv, tick, flag|BCT_ENEMY, skill->area_sub_count))) { + (map->foreachinarea(skill->area_sub, bl->m, max(min_x,tx-1), max(min_y,ty-1), min(max_x,tx+1), min(max_y,ty+1), skill->splash_target(src), src, skill_id, skill_lv, tick, flag|BCT_ENEMY, skill->area_sub_count))) { // Recursive call - map->foreachinarea(skill->area_sub, bl->m, max(min_x,tx-1), max(min_y,ty-1), min(max_x,tx+1), min(max_y,ty+1), splash_target(src), src, skill_id, skill_lv, tick, (flag|BCT_ENEMY)+1, skill->castend_damage_id); + map->foreachinarea(skill->area_sub, bl->m, max(min_x,tx-1), max(min_y,ty-1), min(max_x,tx+1), min(max_y,ty+1), skill->splash_target(src), src, skill_id, skill_lv, tick, (flag|BCT_ENEMY)+1, skill->castend_damage_id); // Self-collision if(bl->x >= min_x && bl->x <= max_x && bl->y >= min_y && bl->y <= max_y) skill->attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,(flag&0xFFF)>0?SD_ANIMATION:0); @@ -4590,7 +4591,7 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1 status_change_end(bl, SC_CLOAKING, INVALID_TIMER); status_change_end(bl, SC_CLOAKINGEXCEED, INVALID_TIMER); // Need confirm it. } else { - map->foreachinrange(skill->area_sub, bl, skill->get_splash(skill_id, skill_lv), splash_target(src), src, skill_id, skill_lv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill->castend_damage_id); + map->foreachinrange(skill->area_sub, bl, skill->get_splash(skill_id, skill_lv), skill->splash_target(src), src, skill_id, skill_lv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill->castend_damage_id); clif->skill_damage(src,src,tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, BDT_SKILL); if( sd ) pc->overheat(sd,1); } @@ -4608,7 +4609,7 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1 // Destination area skill->area_temp[4] = x; skill->area_temp[5] = y; - map->foreachinrange(skill->area_sub, bl, skill->get_splash(skill_id, skill_lv), splash_target(src), src, skill_id, skill_lv, tick, flag|BCT_ENEMY|1, skill->castend_damage_id); + map->foreachinrange(skill->area_sub, bl, skill->get_splash(skill_id, skill_lv), skill->splash_target(src), src, skill_id, skill_lv, tick, flag|BCT_ENEMY|1, skill->castend_damage_id); skill->addtimerskill(src,tick + 800,src->id,x,y,skill_id,skill_lv,0,flag); // To teleport Self clif->skill_damage(src,src,tick,status_get_amotion(src),0,-30000,1,skill_id,skill_lv,BDT_SKILL); } @@ -4667,7 +4668,7 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1 status_change_end(bl, SC_HIDING, INVALID_TIMER); status_change_end(bl, SC_CLOAKINGEXCEED, INVALID_TIMER); } else{ - map->foreachinrange(skill->area_sub, bl, skill->get_splash(skill_id, skill_lv), splash_target(src), src, skill_id, skill_lv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill->castend_damage_id); + map->foreachinrange(skill->area_sub, bl, skill->get_splash(skill_id, skill_lv), skill->splash_target(src), src, skill_id, skill_lv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill->castend_damage_id); clif->skill_damage(src, src, tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, BDT_SKILL); } break; @@ -4804,7 +4805,7 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1 if(flag & 1) skill->attack(skill->get_type(skill_id), src, src, bl, skill_id, skill_lv, tick, flag); else { - map->foreachinrange(skill->area_sub, bl, skill->get_splash(skill_id, skill_lv), splash_target(src), src, skill_id, skill_lv, tick, flag | BCT_ENEMY | SD_SPLASH | 1, skill->castend_damage_id); + map->foreachinrange(skill->area_sub, bl, skill->get_splash(skill_id, skill_lv), skill->splash_target(src), src, skill_id, skill_lv, tick, flag | BCT_ENEMY | SD_SPLASH | 1, skill->castend_damage_id); } break; @@ -5220,7 +5221,7 @@ int skill_castend_id(int tid, int64 tick, int id, intptr_t data) { bool skill_castend_id_unknown(struct unit_data *ud, struct block_list *src, struct block_list *target) { - return false; + return false; } /*========================================== @@ -5456,7 +5457,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin heal_get_jobexp = heal_get_jobexp * battle_config.heal_exp / 100; if (heal_get_jobexp <= 0) heal_get_jobexp = 1; - pc->gainexp (sd, bl, 0, heal_get_jobexp, false); + pc->gainexp(sd, bl, 0, heal_get_jobexp, false); } } break; @@ -5532,7 +5533,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin if (jexp < 1) jexp = 1; } if(exp > 0 || jexp > 0) - pc->gainexp (sd, bl, exp, jexp, false); + pc->gainexp(sd, bl, exp, jexp, false); } } } @@ -6260,7 +6261,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin skill->area_temp[1] = 0; clif->skill_nodamage(src,bl,skill_id,skill_lv,1); map->foreachinrange(skill->area_sub, bl, - skill->get_splash(skill_id, skill_lv), splash_target(src), + skill->get_splash(skill_id, skill_lv), skill->splash_target(src), src,skill_id,skill_lv,tick, flag|BCT_ENEMY|1, skill->castend_damage_id); status_change_end(src, SC_HIDING, INVALID_TIMER); @@ -6279,7 +6280,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin int count = 0; skill->area_temp[1] = 0; clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - count = map->foreachinrange(skill->area_sub, bl, skill->get_splash(skill_id, skill_lv), splash_target(src), + count = map->foreachinrange(skill->area_sub, bl, skill->get_splash(skill_id, skill_lv), skill->splash_target(src), src, skill_id, skill_lv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill->castend_damage_id); if( !count && ( skill_id == NC_AXETORNADO || skill_id == SR_SKYNETBLOW || skill_id == KO_HAPPOKUNAI ) ) clif->skill_damage(src,src,tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, BDT_SKILL); @@ -6325,7 +6326,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin clif->skill_nodamage(src,bl,skill_id,skill_lv,1); skill->area_temp[1] = 0; map->foreachinrange(skill->attack_area, src, - skill->get_splash(skill_id, skill_lv), splash_target(src), + skill->get_splash(skill_id, skill_lv), skill->splash_target(src), BF_MAGIC, src, src, skill_id, skill_lv, tick, flag, BCT_ENEMY); break; @@ -6339,7 +6340,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin clif->skill_nodamage(src, src, skill_id, -1, 1); map->delblock(src); //Required to prevent chain-self-destructions hitting back. map->foreachinrange(skill->area_sub, bl, - skill->get_splash(skill_id, skill_lv), splash_target(src), + skill->get_splash(skill_id, skill_lv), skill->splash_target(src), src, skill_id, skill_lv, tick, flag|targetmask, skill->castend_damage_id); map->addblock(src); @@ -8736,7 +8737,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin int failure; if( (failure = sc_start2(src,bl,type,100,skill_lv,src->id,skill->get_time(skill_id,skill_lv))) ) { - map->foreachinrange(skill->area_sub,src,skill->get_splash(skill_id,skill_lv),splash_target(src),src,skill_id,skill_lv,tick,flag|BCT_ENEMY|SD_SPLASH|1,skill->castend_damage_id);; + map->foreachinrange(skill->area_sub,src,skill->get_splash(skill_id,skill_lv),skill->splash_target(src),src,skill_id,skill_lv,tick,flag|BCT_ENEMY|SD_SPLASH|1,skill->castend_damage_id);; clif->skill_damage(src,src,tick,status_get_amotion(src),0,-30000,1,skill_id,skill_lv,BDT_SKILL); if (sd) pc->overheat(sd,1); } @@ -9077,7 +9078,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin clif->skill_nodamage(src, bl, skill_id, skill_lv, sp ? 1:0); } else { clif->skill_damage(src,bl,tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, BDT_SKILL); - map->foreachinrange(skill->area_sub, bl, skill->get_splash(skill_id, skill_lv), splash_target(src), src, skill_id, skill_lv, tick, flag|BCT_ENEMY|BCT_SELF|SD_SPLASH|1, skill->castend_nodamage_id); + map->foreachinrange(skill->area_sub, bl, skill->get_splash(skill_id, skill_lv), skill->splash_target(src), src, skill_id, skill_lv, tick, flag|BCT_ENEMY|BCT_SELF|SD_SPLASH|1, skill->castend_nodamage_id); } break; @@ -9281,7 +9282,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; @@ -9769,7 +9770,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin } } else { skill->area_temp[2] = 0; - map->foreachinrange(skill->area_sub, bl, skill->get_splash(skill_id, skill_lv), splash_target(src), src, skill_id, skill_lv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill->castend_nodamage_id); + map->foreachinrange(skill->area_sub, bl, skill->get_splash(skill_id, skill_lv), skill->splash_target(src), src, skill_id, skill_lv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill->castend_nodamage_id); } break; @@ -9900,17 +9901,17 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin bool skill_castend_nodamage_id_dead_unknown(struct block_list *src, struct block_list *bl, uint16 *skill_id, uint16 *skill_lv, int64 *tick, int *flag) { - return true; + return true; } bool skill_castend_nodamage_id_undead_unknown(struct block_list *src, struct block_list *bl, uint16 *skill_id, uint16 *skill_lv, int64 *tick, int *flag) { - return true; + return true; } bool skill_castend_nodamage_id_mado_unknown(struct block_list *src, struct block_list *bl, uint16 *skill_id, uint16 *skill_lv, int64 *tick, int *flag) { - return false; + return false; } bool skill_castend_nodamage_id_unknown(struct block_list *src, struct block_list *bl, uint16 *skill_id, uint16 *skill_lv, int64 *tick, int *flag) @@ -10084,7 +10085,7 @@ int skill_castend_pos(int tid, int64 tick, int id, intptr_t data) } -static int check_npc_chaospanic(struct block_list *bl, va_list args) +int skill_check_npc_chaospanic(struct block_list *bl, va_list args) { const struct npc_data *nd = NULL; @@ -10098,7 +10099,8 @@ static int check_npc_chaospanic(struct block_list *bl, va_list args) return 1; } /* skill count without self */ -static int skill_count_wos(struct block_list *bl,va_list ap) { +int skill_count_wos(struct block_list *bl, va_list ap) +{ struct block_list* src = va_arg(ap, struct block_list*); if( src->id != bl->id ) { return 1; @@ -10340,7 +10342,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui case SC_CHAOSPANIC: case SC_MAELSTROM: - if (sd && map->foreachinarea(&check_npc_chaospanic,src->m, x-3, y-3, x+3, y+3, BL_NPC) > 0 ) { + if (sd && map->foreachinarea(skill->check_npc_chaospanic, src->m, x-3, y-3, x+3, y+3, BL_NPC) > 0 ) { clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); break; } @@ -10482,7 +10484,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui if( sc && sc->data[SC_BASILICA] ) status_change_end(src, SC_BASILICA, INVALID_TIMER); // Cancel Basilica else { // Create Basilica. Start SC on caster. Unit timer start SC on others. - if( map->foreachinrange(skill_count_wos, src, 2, BL_MOB|BL_PC, src) ) { + if( map->foreachinrange(skill->count_wos, src, 2, BL_MOB|BL_PC, src) ) { if( sd ) clif->skill_fail(sd,skill_id,USESKILL_FAIL,0); return 1; @@ -10747,7 +10749,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui case RK_DRAGONBREATH: case RK_DRAGONBREATH_WATER: r = skill->get_splash(skill_id,skill_lv); - map->foreachinarea(skill->area_sub,src->m,x-r,y-r,x+r,y+r,splash_target(src), + map->foreachinarea(skill->area_sub,src->m,x-r,y-r,x+r,y+r,skill->splash_target(src), src,skill_id,skill_lv,tick,flag|BCT_ENEMY|1,skill->castend_damage_id); break; case WM_GREAT_ECHO: @@ -10769,7 +10771,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui break; case SO_ARRULLO: r = skill->get_splash(skill_id,skill_lv); - map->foreachinarea(skill->area_sub,src->m,x-r,y-r,x+r,y+r,splash_target(src), + map->foreachinarea(skill->area_sub,src->m,x-r,y-r,x+r,y+r,skill->splash_target(src), src, skill_id, skill_lv, tick, flag|BCT_ENEMY|1, skill->castend_nodamage_id); break; /** @@ -10884,7 +10886,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui case LG_RAYOFGENESIS: if( status->charge(src,status_get_max_hp(src)*3*skill_lv / 100,0) ) { r = skill->get_splash(skill_id,skill_lv); - map->foreachinarea(skill->area_sub,src->m,x-r,y-r,x+r,y+r,splash_target(src), + map->foreachinarea(skill->area_sub,src->m,x-r,y-r,x+r,y+r,skill->splash_target(src), src,skill_id,skill_lv,tick,flag|BCT_ENEMY|1,skill->castend_damage_id); } else if( sd ) clif->skill_fail(sd,skill_id,USESKILL_FAIL,0); @@ -11717,7 +11719,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; @@ -13123,7 +13125,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] @@ -14063,22 +14066,22 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id int skill_check_condition_castbegin_off_unknown(struct status_change *sc, uint16 *skill_id) { - return -1; + return -1; } int skill_check_condition_castbegin_mount_unknown(struct status_change *sc, uint16 *skill_id) { - return 0; + return 0; } int skill_check_condition_castbegin_madogear_unknown(struct status_change *sc, uint16 *skill_id) { - return 0; + return 0; } int skill_check_condition_castbegin_unknown(struct status_change *sc, uint16 *skill_id) { - return -1; + return -1; } int skill_check_condition_castend(struct map_session_data* sd, uint16 skill_id, uint16 skill_lv) { @@ -14089,7 +14092,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 ) { @@ -14701,12 +14704,12 @@ struct skill_condition skill_get_requirement(struct map_session_data* sd, uint16 bool skill_get_requirement_off_unknown(struct status_change *sc, uint16 *skill_id) { - return false; + return false; } bool skill_get_requirement_item_unknown(struct status_change *sc, struct map_session_data* sd, uint16 *skill_id, uint16 *skill_lv, uint16 *idx, int *i) { - return false; + return false; } void skill_get_requirement_unknown(struct status_change *sc, struct map_session_data* sd, uint16 *skill_id, uint16 *skill_lv, struct skill_condition *req) @@ -15222,7 +15225,7 @@ void skill_repairweapon (struct map_session_data *sd, int idx) { return; //Invalid index?? item = &target_sd->status.inventory[idx]; - if( item->nameid <= 0 || item->attribute == 0 ) + if( item->nameid <= 0 || (item->attribute & ATTR_BROKEN) == 0 ) return; //Again invalid item.... if( sd != target_sd && !battle->check_range(&sd->bl,&target_sd->bl, skill->get_range2(&sd->bl, sd->menuskill_id,sd->menuskill_val2) ) ){ @@ -15241,7 +15244,8 @@ void skill_repairweapon (struct map_session_data *sd, int idx) { clif->skill_nodamage(&sd->bl,&target_sd->bl,sd->menuskill_id,1,1); - item->attribute = 0;/* clear broken state */ + item->attribute |= ATTR_BROKEN; + item->attribute ^= ATTR_BROKEN; /* clear broken state */ clif->equiplist(target_sd); @@ -15995,14 +15999,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 ) @@ -16060,11 +16064,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 ) @@ -16671,7 +16675,7 @@ int skill_unit_timer_sub(union DBKey key, struct DBData *data, va_list ap) case UNT_FEINTBOMB: { struct block_list *src = map->id2bl(group->src_id); if( src ) { - map->foreachinrange(skill->area_sub, &su->bl, su->range, splash_target(src), src, SC_FEINTBOMB, group->skill_lv, tick, BCT_ENEMY|SD_ANIMATION|1, skill->castend_damage_id); + map->foreachinrange(skill->area_sub, &su->bl, su->range, skill->splash_target(src), src, SC_FEINTBOMB, group->skill_lv, tick, BCT_ENEMY|SD_ANIMATION|1, skill->castend_damage_id); status_change_end(src, SC__FEINTBOMB_MASTER, INVALID_TIMER); } skill->delunit(su); @@ -20634,4 +20638,7 @@ void skill_defaults(void) { skill->get_requirement_off_unknown = skill_get_requirement_off_unknown; skill->get_requirement_item_unknown = skill_get_requirement_item_unknown; skill->get_requirement_unknown = skill_get_requirement_unknown; + skill->splash_target = skill_splash_target; + skill->check_npc_chaospanic = skill_check_npc_chaospanic; + skill->count_wos = skill_count_wos; } diff --git a/src/map/skill.h b/src/map/skill.h index 9bb3eae13..45f025e74 100644 --- a/src/map/skill.h +++ b/src/map/skill.h @@ -2113,6 +2113,9 @@ struct skill_interface { bool (*get_requirement_off_unknown) (struct status_change *sc, uint16 *skill_id); bool (*get_requirement_item_unknown) (struct status_change *sc, struct map_session_data* sd, uint16 *skill_id, uint16 *skill_lv, uint16 *idx, int *i); void (*get_requirement_unknown) (struct status_change *sc, struct map_session_data* sd, uint16 *skill_id, uint16 *skill_lv, struct skill_condition *req); + int (*splash_target) (struct block_list* bl); + int (*check_npc_chaospanic) (struct block_list *bl, va_list args); + int (*count_wos) (struct block_list *bl, va_list ap); }; #ifdef HERCULES_CORE diff --git a/src/map/status.c b/src/map/status.c index a8771c0a5..83d8943c9 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -125,7 +125,8 @@ int status_type2relevant_bl_types(int type) return status->dbs->RelevantBLTypes[type]; } -static void set_sc(uint16 skill_id, sc_type sc, int icon, unsigned int flag) { +void status_set_sc(uint16 skill_id, sc_type sc, int icon, unsigned int flag) +{ uint16 idx; if( (idx = skill->get_index(skill_id)) == 0 ) { ShowError("set_sc: Unsupported skill id %d\n", skill_id); @@ -147,9 +148,9 @@ static void set_sc(uint16 skill_id, sc_type sc, int icon, unsigned int flag) { } void initChangeTables(void) { -#define add_sc(skill,sc) set_sc((skill),(sc),SI_BLANK,SCB_NONE) +#define add_sc(skill,sc) status->set_sc((skill),(sc),SI_BLANK,SCB_NONE) // indicates that the status displays a visual effect for the affected unit, and should be sent to the client for all supported units -#define set_sc_with_vfx(skill, sc, icon, flag) do { set_sc((skill), (sc), (icon), (flag)); if((icon) < SI_MAX) status->dbs->RelevantBLTypes[(icon)] |= BL_SCEFFECT; } while(0) +#define set_sc_with_vfx(skill, sc, icon, flag) do { status->set_sc((skill), (sc), (icon), (flag)); if((icon) < SI_MAX) status->dbs->RelevantBLTypes[(icon)] |= BL_SCEFFECT; } while(0) int i; @@ -167,83 +168,83 @@ void initChangeTables(void) { memset(status->dbs->DisplayType, 0, sizeof(status->dbs->DisplayType)); //First we define the skill for common ailments. These are used in skill_additional_effect through sc cards. [Skotlex] - set_sc( NPC_PETRIFYATTACK , SC_STONE , SI_BLANK , SCB_DEF_ELE|SCB_DEF|SCB_MDEF ); - set_sc( NPC_WIDEFREEZE , SC_FREEZE , SI_BLANK , SCB_DEF_ELE|SCB_DEF|SCB_MDEF ); - set_sc( NPC_STUNATTACK , SC_STUN , SI_BLANK , SCB_NONE ); - set_sc( NPC_SLEEPATTACK , SC_SLEEP , SI_BLANK , SCB_NONE ); - set_sc( NPC_POISON , SC_POISON , SI_BLANK , SCB_DEF2|SCB_REGEN ); - set_sc( NPC_CURSEATTACK , SC_CURSE , SI_BLANK , SCB_LUK|SCB_BATK|SCB_WATK|SCB_SPEED ); - set_sc( NPC_SILENCEATTACK , SC_SILENCE , SI_BLANK , SCB_NONE ); - set_sc( NPC_WIDECONFUSE , SC_CONFUSION , SI_BLANK , SCB_NONE ); - set_sc( NPC_BLINDATTACK , SC_BLIND , SI_BLANK , SCB_HIT|SCB_FLEE ); - set_sc( NPC_BLEEDING , SC_BLOODING , SI_BLOODING , SCB_REGEN ); - set_sc( NPC_POISON , SC_DPOISON , SI_BLANK , SCB_DEF2|SCB_REGEN ); + status->set_sc( NPC_PETRIFYATTACK , SC_STONE , SI_BLANK , SCB_DEF_ELE|SCB_DEF|SCB_MDEF ); + status->set_sc( NPC_WIDEFREEZE , SC_FREEZE , SI_BLANK , SCB_DEF_ELE|SCB_DEF|SCB_MDEF ); + status->set_sc( NPC_STUNATTACK , SC_STUN , SI_BLANK , SCB_NONE ); + status->set_sc( NPC_SLEEPATTACK , SC_SLEEP , SI_BLANK , SCB_NONE ); + status->set_sc( NPC_POISON , SC_POISON , SI_BLANK , SCB_DEF2|SCB_REGEN ); + status->set_sc( NPC_CURSEATTACK , SC_CURSE , SI_BLANK , SCB_LUK|SCB_BATK|SCB_WATK|SCB_SPEED ); + status->set_sc( NPC_SILENCEATTACK , SC_SILENCE , SI_BLANK , SCB_NONE ); + status->set_sc( NPC_WIDECONFUSE , SC_CONFUSION , SI_BLANK , SCB_NONE ); + status->set_sc( NPC_BLINDATTACK , SC_BLIND , SI_BLANK , SCB_HIT|SCB_FLEE ); + status->set_sc( NPC_BLEEDING , SC_BLOODING , SI_BLOODING , SCB_REGEN ); + status->set_sc( NPC_POISON , SC_DPOISON , SI_BLANK , SCB_DEF2|SCB_REGEN ); //The main status definitions add_sc( SM_BASH , SC_STUN ); - set_sc( SM_PROVOKE , SC_PROVOKE , SI_PROVOKE , SCB_DEF|SCB_DEF2|SCB_BATK|SCB_WATK ); + status->set_sc( SM_PROVOKE , SC_PROVOKE , SI_PROVOKE , SCB_DEF|SCB_DEF2|SCB_BATK|SCB_WATK ); add_sc( SM_MAGNUM , SC_SUB_WEAPONPROPERTY ); - set_sc( SM_ENDURE , SC_ENDURE , SI_ENDURE , SCB_MDEF|SCB_DSPD ); + status->set_sc( SM_ENDURE , SC_ENDURE , SI_ENDURE , SCB_MDEF|SCB_DSPD ); add_sc( MG_SIGHT , SC_SIGHT ); add_sc( MG_SAFETYWALL , SC_SAFETYWALL ); add_sc( MG_FROSTDIVER , SC_FREEZE ); add_sc( MG_STONECURSE , SC_STONE ); add_sc( AL_RUWACH , SC_RUWACH ); add_sc( AL_PNEUMA , SC_PNEUMA ); - set_sc( AL_INCAGI , SC_INC_AGI , SI_INC_AGI , SCB_AGI|SCB_SPEED ); - set_sc( AL_DECAGI , SC_DEC_AGI , SI_DEC_AGI , SCB_AGI|SCB_SPEED ); - set_sc( AL_CRUCIS , SC_CRUCIS , SI_CRUCIS , SCB_DEF ); - set_sc( AL_ANGELUS , SC_ANGELUS , SI_ANGELUS , SCB_DEF2 ); - set_sc( AL_BLESSING , SC_BLESSING , SI_BLESSING , SCB_STR|SCB_INT|SCB_DEX ); - set_sc( AC_CONCENTRATION , SC_CONCENTRATION , SI_CONCENTRATION , SCB_AGI|SCB_DEX ); - set_sc( TF_HIDING , SC_HIDING , SI_HIDING , SCB_SPEED ); + status->set_sc( AL_INCAGI , SC_INC_AGI , SI_INC_AGI , SCB_AGI|SCB_SPEED ); + status->set_sc( AL_DECAGI , SC_DEC_AGI , SI_DEC_AGI , SCB_AGI|SCB_SPEED ); + status->set_sc( AL_CRUCIS , SC_CRUCIS , SI_CRUCIS , SCB_DEF ); + status->set_sc( AL_ANGELUS , SC_ANGELUS , SI_ANGELUS , SCB_DEF2 ); + status->set_sc( AL_BLESSING , SC_BLESSING , SI_BLESSING , SCB_STR|SCB_INT|SCB_DEX ); + status->set_sc( AC_CONCENTRATION , SC_CONCENTRATION , SI_CONCENTRATION , SCB_AGI|SCB_DEX ); + status->set_sc( TF_HIDING , SC_HIDING , SI_HIDING , SCB_SPEED ); add_sc( TF_POISON , SC_POISON ); - set_sc( KN_TWOHANDQUICKEN , SC_TWOHANDQUICKEN , SI_TWOHANDQUICKEN , SCB_ASPD ); + status->set_sc( KN_TWOHANDQUICKEN , SC_TWOHANDQUICKEN , SI_TWOHANDQUICKEN , SCB_ASPD ); add_sc( KN_AUTOCOUNTER , SC_AUTOCOUNTER ); - set_sc( PR_IMPOSITIO , SC_IMPOSITIO , SI_IMPOSITIO , + status->set_sc( PR_IMPOSITIO , SC_IMPOSITIO , SI_IMPOSITIO , #ifdef RENEWAL SCB_NONE ); #else SCB_WATK ); #endif - set_sc( PR_SUFFRAGIUM , SC_SUFFRAGIUM , SI_SUFFRAGIUM , SCB_NONE ); - set_sc( PR_ASPERSIO , SC_ASPERSIO , SI_ASPERSIO , SCB_ATK_ELE ); - set_sc( PR_BENEDICTIO , SC_BENEDICTIO , SI_BENEDICTIO , SCB_DEF_ELE ); - set_sc( PR_SLOWPOISON , SC_SLOWPOISON , SI_SLOWPOISON , SCB_REGEN ); - set_sc( PR_KYRIE , SC_KYRIE , SI_KYRIE , SCB_NONE ); - set_sc( PR_MAGNIFICAT , SC_MAGNIFICAT , SI_MAGNIFICAT , SCB_REGEN ); - set_sc( PR_GLORIA , SC_GLORIA , SI_GLORIA , SCB_LUK ); + status->set_sc( PR_SUFFRAGIUM , SC_SUFFRAGIUM , SI_SUFFRAGIUM , SCB_NONE ); + status->set_sc( PR_ASPERSIO , SC_ASPERSIO , SI_ASPERSIO , SCB_ATK_ELE ); + status->set_sc( PR_BENEDICTIO , SC_BENEDICTIO , SI_BENEDICTIO , SCB_DEF_ELE ); + status->set_sc( PR_SLOWPOISON , SC_SLOWPOISON , SI_SLOWPOISON , SCB_REGEN ); + status->set_sc( PR_KYRIE , SC_KYRIE , SI_KYRIE , SCB_NONE ); + status->set_sc( PR_MAGNIFICAT , SC_MAGNIFICAT , SI_MAGNIFICAT , SCB_REGEN ); + status->set_sc( PR_GLORIA , SC_GLORIA , SI_GLORIA , SCB_LUK ); add_sc( PR_LEXDIVINA , SC_SILENCE ); - set_sc( PR_LEXAETERNA , SC_LEXAETERNA , SI_LEXAETERNA , SCB_NONE ); + status->set_sc( PR_LEXAETERNA , SC_LEXAETERNA , SI_LEXAETERNA , SCB_NONE ); add_sc( WZ_METEOR , SC_STUN ); add_sc( WZ_VERMILION , SC_BLIND ); add_sc( WZ_FROSTNOVA , SC_FREEZE ); add_sc( WZ_STORMGUST , SC_FREEZE ); - set_sc( WZ_QUAGMIRE , SC_QUAGMIRE , SI_QUAGMIRE , SCB_AGI|SCB_DEX|SCB_ASPD|SCB_SPEED ); - set_sc( BS_ADRENALINE , SC_ADRENALINE , SI_ADRENALINE , SCB_ASPD ); - set_sc( BS_WEAPONPERFECT , SC_WEAPONPERFECT , SI_WEAPONPERFECT, SCB_NONE ); - set_sc( BS_OVERTHRUST , SC_OVERTHRUST , SI_OVERTHRUST , SCB_NONE ); - set_sc( BS_MAXIMIZE , SC_MAXIMIZEPOWER , SI_MAXIMIZE , SCB_REGEN ); + status->set_sc( WZ_QUAGMIRE , SC_QUAGMIRE , SI_QUAGMIRE , SCB_AGI|SCB_DEX|SCB_ASPD|SCB_SPEED ); + status->set_sc( BS_ADRENALINE , SC_ADRENALINE , SI_ADRENALINE , SCB_ASPD ); + status->set_sc( BS_WEAPONPERFECT , SC_WEAPONPERFECT , SI_WEAPONPERFECT, SCB_NONE ); + status->set_sc( BS_OVERTHRUST , SC_OVERTHRUST , SI_OVERTHRUST , SCB_NONE ); + status->set_sc( BS_MAXIMIZE , SC_MAXIMIZEPOWER , SI_MAXIMIZE , SCB_REGEN ); add_sc( HT_LANDMINE , SC_STUN ); - set_sc( HT_ANKLESNARE , SC_ANKLESNARE , SI_ANKLESNARE , SCB_NONE ); + status->set_sc( HT_ANKLESNARE , SC_ANKLESNARE , SI_ANKLESNARE , SCB_NONE ); add_sc( HT_SANDMAN , SC_SLEEP ); add_sc( HT_FLASHER , SC_BLIND ); add_sc( HT_FREEZINGTRAP , SC_FREEZE ); - set_sc( AS_CLOAKING , SC_CLOAKING , SI_CLOAKING , SCB_CRI|SCB_SPEED ); + status->set_sc( AS_CLOAKING , SC_CLOAKING , SI_CLOAKING , SCB_CRI|SCB_SPEED ); add_sc( AS_SONICBLOW , SC_STUN ); - set_sc( AS_ENCHANTPOISON , SC_ENCHANTPOISON , SI_ENCHANTPOISON, SCB_ATK_ELE ); - set_sc( AS_POISONREACT , SC_POISONREACT , SI_POISONREACT , SCB_NONE ); + status->set_sc( AS_ENCHANTPOISON , SC_ENCHANTPOISON , SI_ENCHANTPOISON, SCB_ATK_ELE ); + status->set_sc( AS_POISONREACT , SC_POISONREACT , SI_POISONREACT , SCB_NONE ); add_sc( AS_VENOMDUST , SC_POISON ); add_sc( AS_SPLASHER , SC_SPLASHER ); - set_sc( NV_TRICKDEAD , SC_TRICKDEAD , SI_TRICKDEAD , SCB_REGEN ); - set_sc( SM_AUTOBERSERK , SC_AUTOBERSERK , SI_AUTOBERSERK , SCB_NONE ); + status->set_sc( NV_TRICKDEAD , SC_TRICKDEAD , SI_TRICKDEAD , SCB_REGEN ); + status->set_sc( SM_AUTOBERSERK , SC_AUTOBERSERK , SI_AUTOBERSERK , SCB_NONE ); add_sc( TF_SPRINKLESAND , SC_BLIND ); add_sc( TF_THROWSTONE , SC_STUN ); - set_sc( MC_LOUD , SC_SHOUT , SI_SHOUT , SCB_STR ); - set_sc( MG_ENERGYCOAT , SC_ENERGYCOAT , SI_ENERGYCOAT , SCB_NONE ); - set_sc( NPC_EMOTION , SC_MODECHANGE , SI_BLANK , SCB_MODE ); + status->set_sc( MC_LOUD , SC_SHOUT , SI_SHOUT , SCB_STR ); + status->set_sc( MG_ENERGYCOAT , SC_ENERGYCOAT , SI_ENERGYCOAT , SCB_NONE ); + status->set_sc( NPC_EMOTION , SC_MODECHANGE , SI_BLANK , SCB_MODE ); add_sc( NPC_EMOTION_ON , SC_MODECHANGE ); - set_sc( NPC_ATTRICHANGE , SC_ARMOR_PROPERTY , SI_ARMOR_PROPERTY , SCB_DEF_ELE ); + status->set_sc( NPC_ATTRICHANGE , SC_ARMOR_PROPERTY , SI_ARMOR_PROPERTY , SCB_DEF_ELE ); add_sc( NPC_CHANGEWATER , SC_ARMOR_PROPERTY ); add_sc( NPC_CHANGEGROUND , SC_ARMOR_PROPERTY ); add_sc( NPC_CHANGEFIRE , SC_ARMOR_PROPERTY ); @@ -260,184 +261,184 @@ void initChangeTables(void) { add_sc( NPC_CURSEATTACK , SC_CURSE ); add_sc( NPC_SLEEPATTACK , SC_SLEEP ); add_sc( NPC_MAGICALATTACK , SC_MAGICALATTACK ); - set_sc( NPC_KEEPING , SC_KEEPING , SI_BLANK , SCB_DEF ); + status->set_sc( NPC_KEEPING , SC_KEEPING , SI_BLANK , SCB_DEF ); add_sc( NPC_DARKBLESSING , SC_COMA ); - set_sc( NPC_BARRIER , SC_BARRIER , SI_BLANK , SCB_MDEF|SCB_DEF ); + status->set_sc( NPC_BARRIER , SC_BARRIER , SI_BLANK , SCB_MDEF|SCB_DEF ); add_sc( NPC_DEFENDER , SC_ARMOR ); add_sc( NPC_LICK , SC_STUN ); - set_sc( NPC_HALLUCINATION , SC_ILLUSION , SI_ILLUSION , SCB_NONE ); + status->set_sc( NPC_HALLUCINATION , SC_ILLUSION , SI_ILLUSION , SCB_NONE ); add_sc( NPC_REBIRTH , SC_REBIRTH ); add_sc( RG_RAID , SC_STUN ); #ifdef RENEWAL add_sc( RG_RAID , SC_RAID ); add_sc( RG_BACKSTAP , SC_STUN ); #endif - set_sc( RG_STRIPWEAPON , SC_NOEQUIPWEAPON , SI_NOEQUIPWEAPON , SCB_WATK ); - set_sc( RG_STRIPSHIELD , SC_NOEQUIPSHIELD , SI_NOEQUIPSHIELD , SCB_DEF ); - set_sc( RG_STRIPARMOR , SC_NOEQUIPARMOR , SI_NOEQUIPARMOR , SCB_VIT ); - set_sc( RG_STRIPHELM , SC_NOEQUIPHELM , SI_NOEQUIPHELM , SCB_INT ); + status->set_sc( RG_STRIPWEAPON , SC_NOEQUIPWEAPON , SI_NOEQUIPWEAPON , SCB_WATK ); + status->set_sc( RG_STRIPSHIELD , SC_NOEQUIPSHIELD , SI_NOEQUIPSHIELD , SCB_DEF ); + status->set_sc( RG_STRIPARMOR , SC_NOEQUIPARMOR , SI_NOEQUIPARMOR , SCB_VIT ); + status->set_sc( RG_STRIPHELM , SC_NOEQUIPHELM , SI_NOEQUIPHELM , SCB_INT ); add_sc( AM_ACIDTERROR , SC_BLOODING ); - set_sc( AM_CP_WEAPON , SC_PROTECTWEAPON , SI_PROTECTWEAPON , SCB_NONE ); - set_sc( AM_CP_SHIELD , SC_PROTECTSHIELD , SI_PROTECTSHIELD , SCB_NONE ); - set_sc( AM_CP_ARMOR , SC_PROTECTARMOR , SI_PROTECTARMOR , SCB_NONE ); - set_sc( AM_CP_HELM , SC_PROTECTHELM , SI_PROTECTHELM , SCB_NONE ); - set_sc( CR_AUTOGUARD , SC_AUTOGUARD , SI_AUTOGUARD , SCB_NONE ); + status->set_sc( AM_CP_WEAPON , SC_PROTECTWEAPON , SI_PROTECTWEAPON , SCB_NONE ); + status->set_sc( AM_CP_SHIELD , SC_PROTECTSHIELD , SI_PROTECTSHIELD , SCB_NONE ); + status->set_sc( AM_CP_ARMOR , SC_PROTECTARMOR , SI_PROTECTARMOR , SCB_NONE ); + status->set_sc( AM_CP_HELM , SC_PROTECTHELM , SI_PROTECTHELM , SCB_NONE ); + status->set_sc( CR_AUTOGUARD , SC_AUTOGUARD , SI_AUTOGUARD , SCB_NONE ); add_sc( CR_SHIELDCHARGE , SC_STUN ); - set_sc( CR_REFLECTSHIELD , SC_REFLECTSHIELD , SI_REFLECTSHIELD , SCB_NONE ); + status->set_sc( CR_REFLECTSHIELD , SC_REFLECTSHIELD , SI_REFLECTSHIELD , SCB_NONE ); add_sc( CR_HOLYCROSS , SC_BLIND ); add_sc( CR_GRANDCROSS , SC_BLIND ); add_sc( CR_DEVOTION , SC_DEVOTION ); - set_sc( CR_PROVIDENCE , SC_PROVIDENCE , SI_PROVIDENCE , SCB_ALL ); - set_sc( CR_DEFENDER , SC_DEFENDER , SI_DEFENDER , SCB_SPEED|SCB_ASPD ); - set_sc( CR_SPEARQUICKEN , SC_SPEARQUICKEN , SI_SPEARQUICKEN , SCB_ASPD|SCB_CRI|SCB_FLEE ); - set_sc( MO_STEELBODY , SC_STEELBODY , SI_STEELBODY , SCB_DEF|SCB_MDEF|SCB_ASPD|SCB_SPEED ); + status->set_sc( CR_PROVIDENCE , SC_PROVIDENCE , SI_PROVIDENCE , SCB_ALL ); + status->set_sc( CR_DEFENDER , SC_DEFENDER , SI_DEFENDER , SCB_SPEED|SCB_ASPD ); + status->set_sc( CR_SPEARQUICKEN , SC_SPEARQUICKEN , SI_SPEARQUICKEN , SCB_ASPD|SCB_CRI|SCB_FLEE ); + status->set_sc( MO_STEELBODY , SC_STEELBODY , SI_STEELBODY , SCB_DEF|SCB_MDEF|SCB_ASPD|SCB_SPEED ); add_sc( MO_BLADESTOP , SC_BLADESTOP_WAIT ); add_sc( MO_BLADESTOP , SC_BLADESTOP ); - set_sc( MO_EXPLOSIONSPIRITS , SC_EXPLOSIONSPIRITS, SI_EXPLOSIONSPIRITS, SCB_CRI|SCB_REGEN ); - set_sc( MO_EXTREMITYFIST , SC_EXTREMITYFIST , SI_BLANK , SCB_REGEN ); + status->set_sc( MO_EXPLOSIONSPIRITS , SC_EXPLOSIONSPIRITS, SI_EXPLOSIONSPIRITS, SCB_CRI|SCB_REGEN ); + status->set_sc( MO_EXTREMITYFIST , SC_EXTREMITYFIST , SI_BLANK , SCB_REGEN ); #ifdef RENEWAL - set_sc( MO_EXTREMITYFIST , SC_EXTREMITYFIST2 , SI_EXTREMITYFIST , SCB_NONE ); + status->set_sc( MO_EXTREMITYFIST , SC_EXTREMITYFIST2 , SI_EXTREMITYFIST , SCB_NONE ); #endif add_sc( SA_MAGICROD , SC_MAGICROD ); - set_sc( SA_AUTOSPELL , SC_AUTOSPELL , SI_AUTOSPELL , SCB_NONE ); - set_sc( SA_FLAMELAUNCHER , SC_PROPERTYFIRE , SI_PROPERTYFIRE , SCB_ATK_ELE ); - set_sc( SA_FROSTWEAPON , SC_PROPERTYWATER , SI_PROPERTYWATER , SCB_ATK_ELE ); - set_sc( SA_LIGHTNINGLOADER , SC_PROPERTYWIND , SI_PROPERTYWIND , SCB_ATK_ELE ); - set_sc( SA_SEISMICWEAPON , SC_PROPERTYGROUND , SI_PROPERTYGROUND , SCB_ATK_ELE ); - set_sc( SA_VOLCANO , SC_VOLCANO , SI_GROUNDMAGIC , SCB_WATK ); - set_sc( SA_DELUGE , SC_DELUGE , SI_GROUNDMAGIC , SCB_MAXHP ); - set_sc( SA_VIOLENTGALE , SC_VIOLENTGALE , SI_GROUNDMAGIC , SCB_FLEE ); + status->set_sc( SA_AUTOSPELL , SC_AUTOSPELL , SI_AUTOSPELL , SCB_NONE ); + status->set_sc( SA_FLAMELAUNCHER , SC_PROPERTYFIRE , SI_PROPERTYFIRE , SCB_ATK_ELE ); + status->set_sc( SA_FROSTWEAPON , SC_PROPERTYWATER , SI_PROPERTYWATER , SCB_ATK_ELE ); + status->set_sc( SA_LIGHTNINGLOADER , SC_PROPERTYWIND , SI_PROPERTYWIND , SCB_ATK_ELE ); + status->set_sc( SA_SEISMICWEAPON , SC_PROPERTYGROUND , SI_PROPERTYGROUND , SCB_ATK_ELE ); + status->set_sc( SA_VOLCANO , SC_VOLCANO , SI_GROUNDMAGIC , SCB_WATK ); + status->set_sc( SA_DELUGE , SC_DELUGE , SI_GROUNDMAGIC , SCB_MAXHP ); + status->set_sc( SA_VIOLENTGALE , SC_VIOLENTGALE , SI_GROUNDMAGIC , SCB_FLEE ); add_sc( SA_REVERSEORCISH , SC_ORCISH ); add_sc( SA_COMA , SC_COMA ); - set_sc( BD_ENCORE , SC_DANCING , SI_BLANK , SCB_SPEED|SCB_REGEN ); + status->set_sc( BD_ENCORE , SC_DANCING , SI_BLANK , SCB_SPEED|SCB_REGEN ); add_sc( BD_RICHMANKIM , SC_RICHMANKIM ); - set_sc( BD_ETERNALCHAOS , SC_ETERNALCHAOS , SI_BLANK , SCB_DEF2 ); - set_sc( BD_DRUMBATTLEFIELD , SC_DRUMBATTLE , SI_BLANK , SCB_WATK|SCB_DEF ); - set_sc( BD_RINGNIBELUNGEN , SC_NIBELUNGEN , SI_BLANK , SCB_WATK ); + status->set_sc( BD_ETERNALCHAOS , SC_ETERNALCHAOS , SI_BLANK , SCB_DEF2 ); + status->set_sc( BD_DRUMBATTLEFIELD , SC_DRUMBATTLE , SI_BLANK , SCB_WATK|SCB_DEF ); + status->set_sc( BD_RINGNIBELUNGEN , SC_NIBELUNGEN , SI_BLANK , SCB_WATK ); add_sc( BD_ROKISWEIL , SC_ROKISWEIL ); add_sc( BD_INTOABYSS , SC_INTOABYSS ); - set_sc( BD_SIEGFRIED , SC_SIEGFRIED , SI_BLANK , SCB_ALL ); + status->set_sc( BD_SIEGFRIED , SC_SIEGFRIED , SI_BLANK , SCB_ALL ); add_sc( BA_FROSTJOKER , SC_FREEZE ); - set_sc( BA_WHISTLE , SC_WHISTLE , SI_BLANK , SCB_FLEE|SCB_FLEE2 ); - set_sc( BA_ASSASSINCROSS , SC_ASSNCROS , SI_BLANK , SCB_ASPD ); + status->set_sc( BA_WHISTLE , SC_WHISTLE , SI_BLANK , SCB_FLEE|SCB_FLEE2 ); + status->set_sc( BA_ASSASSINCROSS , SC_ASSNCROS , SI_BLANK , SCB_ASPD ); add_sc( BA_POEMBRAGI , SC_POEMBRAGI ); - set_sc( BA_APPLEIDUN , SC_APPLEIDUN , SI_BLANK , SCB_MAXHP ); + status->set_sc( BA_APPLEIDUN , SC_APPLEIDUN , SI_BLANK , SCB_MAXHP ); add_sc( DC_SCREAM , SC_STUN ); - set_sc( DC_HUMMING , SC_HUMMING , SI_BLANK , SCB_HIT ); - set_sc( DC_DONTFORGETME , SC_DONTFORGETME , SI_BLANK , SCB_SPEED|SCB_ASPD ); - set_sc( DC_FORTUNEKISS , SC_FORTUNE , SI_BLANK , SCB_CRI ); - set_sc( DC_SERVICEFORYOU , SC_SERVICEFORYOU , SI_BLANK , SCB_ALL ); + status->set_sc( DC_HUMMING , SC_HUMMING , SI_BLANK , SCB_HIT ); + status->set_sc( DC_DONTFORGETME , SC_DONTFORGETME , SI_BLANK , SCB_SPEED|SCB_ASPD ); + status->set_sc( DC_FORTUNEKISS , SC_FORTUNE , SI_BLANK , SCB_CRI ); + status->set_sc( DC_SERVICEFORYOU , SC_SERVICEFORYOU , SI_BLANK , SCB_ALL ); add_sc( NPC_DARKCROSS , SC_BLIND ); add_sc( NPC_GRANDDARKNESS , SC_BLIND ); - set_sc( NPC_STOP , SC_STOP , SI_STOP , SCB_NONE ); - set_sc( NPC_WEAPONBRAKER , SC_BROKENWEAPON , SI_BROKENWEAPON , SCB_NONE ); - set_sc( NPC_ARMORBRAKE , SC_BROKENARMOR , SI_BROKENARMOR , SCB_NONE ); - set_sc( NPC_CHANGEUNDEAD , SC_PROPERTYUNDEAD , SI_PROPERTYUNDEAD , SCB_DEF_ELE ); - set_sc( NPC_POWERUP , SC_INCHITRATE , SI_BLANK , SCB_HIT ); - set_sc( NPC_AGIUP , SC_INCFLEERATE , SI_BLANK , SCB_FLEE ); + status->set_sc( NPC_STOP , SC_STOP , SI_STOP , SCB_NONE ); + status->set_sc( NPC_WEAPONBRAKER , SC_BROKENWEAPON , SI_BROKENWEAPON , SCB_NONE ); + status->set_sc( NPC_ARMORBRAKE , SC_BROKENARMOR , SI_BROKENARMOR , SCB_NONE ); + status->set_sc( NPC_CHANGEUNDEAD , SC_PROPERTYUNDEAD , SI_PROPERTYUNDEAD , SCB_DEF_ELE ); + status->set_sc( NPC_POWERUP , SC_INCHITRATE , SI_BLANK , SCB_HIT ); + status->set_sc( NPC_AGIUP , SC_INCFLEERATE , SI_BLANK , SCB_FLEE ); add_sc( NPC_INVISIBLE , SC_CLOAKING ); - set_sc( LK_AURABLADE , SC_AURABLADE , SI_AURABLADE , SCB_NONE ); - set_sc( LK_PARRYING , SC_PARRYING , SI_PARRYING , SCB_NONE ); + status->set_sc( LK_AURABLADE , SC_AURABLADE , SI_AURABLADE , SCB_NONE ); + status->set_sc( LK_PARRYING , SC_PARRYING , SI_PARRYING , SCB_NONE ); #ifndef RENEWAL - set_sc( LK_CONCENTRATION , SC_LKCONCENTRATION , SI_LKCONCENTRATION , SCB_BATK|SCB_WATK|SCB_HIT|SCB_DEF|SCB_DEF2); + status->set_sc( LK_CONCENTRATION , SC_LKCONCENTRATION , SI_LKCONCENTRATION , SCB_BATK|SCB_WATK|SCB_HIT|SCB_DEF|SCB_DEF2); #else - set_sc( LK_CONCENTRATION , SC_LKCONCENTRATION , SI_LKCONCENTRATION , SCB_HIT|SCB_DEF); + status->set_sc( LK_CONCENTRATION , SC_LKCONCENTRATION , SI_LKCONCENTRATION , SCB_HIT|SCB_DEF); #endif - set_sc( LK_TENSIONRELAX , SC_TENSIONRELAX , SI_TENSIONRELAX , SCB_REGEN ); - set_sc( LK_BERSERK , SC_BERSERK , SI_BERSERK , SCB_DEF|SCB_DEF2|SCB_MDEF|SCB_MDEF2|SCB_FLEE|SCB_SPEED|SCB_ASPD|SCB_MAXHP|SCB_REGEN ); - set_sc( HP_ASSUMPTIO , SC_ASSUMPTIO , SI_ASSUMPTIO , SCB_NONE ); + status->set_sc( LK_TENSIONRELAX , SC_TENSIONRELAX , SI_TENSIONRELAX , SCB_REGEN ); + status->set_sc( LK_BERSERK , SC_BERSERK , SI_BERSERK , SCB_DEF|SCB_DEF2|SCB_MDEF|SCB_MDEF2|SCB_FLEE|SCB_SPEED|SCB_ASPD|SCB_MAXHP|SCB_REGEN ); + status->set_sc( HP_ASSUMPTIO , SC_ASSUMPTIO , SI_ASSUMPTIO , SCB_NONE ); add_sc( HP_BASILICA , SC_BASILICA ); - set_sc( HW_MAGICPOWER , SC_MAGICPOWER , SI_MAGICPOWER , SCB_MATK ); + status->set_sc( HW_MAGICPOWER , SC_MAGICPOWER , SI_MAGICPOWER , SCB_MATK ); add_sc( PA_SACRIFICE , SC_SACRIFICE ); - set_sc( PA_GOSPEL , SC_GOSPEL , SI_BLANK , SCB_SPEED|SCB_ASPD ); + status->set_sc( PA_GOSPEL , SC_GOSPEL , SI_BLANK , SCB_SPEED|SCB_ASPD ); add_sc( PA_GOSPEL , SC_SCRESIST ); add_sc( CH_TIGERFIST , SC_STOP ); - set_sc( ASC_EDP , SC_EDP , SI_EDP , SCB_NONE ); - set_sc( SN_SIGHT , SC_TRUESIGHT , SI_TRUESIGHT , SCB_STR|SCB_AGI|SCB_VIT|SCB_INT|SCB_DEX|SCB_LUK|SCB_CRI|SCB_HIT ); - set_sc( SN_WINDWALK , SC_WINDWALK , SI_WINDWALK , SCB_FLEE|SCB_SPEED ); - set_sc( WS_MELTDOWN , SC_MELTDOWN , SI_MELTDOWN , SCB_NONE ); - set_sc( WS_CARTBOOST , SC_CARTBOOST , SI_CARTBOOST , SCB_SPEED ); - set_sc( ST_CHASEWALK , SC_CHASEWALK , SI_BLANK , SCB_SPEED ); - set_sc( ST_REJECTSWORD , SC_SWORDREJECT , SI_SWORDREJECT , SCB_NONE ); + status->set_sc( ASC_EDP , SC_EDP , SI_EDP , SCB_NONE ); + status->set_sc( SN_SIGHT , SC_TRUESIGHT , SI_TRUESIGHT , SCB_STR|SCB_AGI|SCB_VIT|SCB_INT|SCB_DEX|SCB_LUK|SCB_CRI|SCB_HIT ); + status->set_sc( SN_WINDWALK , SC_WINDWALK , SI_WINDWALK , SCB_FLEE|SCB_SPEED ); + status->set_sc( WS_MELTDOWN , SC_MELTDOWN , SI_MELTDOWN , SCB_NONE ); + status->set_sc( WS_CARTBOOST , SC_CARTBOOST , SI_CARTBOOST , SCB_SPEED ); + status->set_sc( ST_CHASEWALK , SC_CHASEWALK , SI_BLANK , SCB_SPEED ); + status->set_sc( ST_REJECTSWORD , SC_SWORDREJECT , SI_SWORDREJECT , SCB_NONE ); add_sc( ST_REJECTSWORD , SC_AUTOCOUNTER ); - set_sc( CG_MARIONETTE , SC_MARIONETTE_MASTER , SI_MARIONETTE_MASTER , SCB_STR|SCB_AGI|SCB_VIT|SCB_INT|SCB_DEX|SCB_LUK ); - set_sc( CG_MARIONETTE , SC_MARIONETTE , SI_MARIONETTE , SCB_STR|SCB_AGI|SCB_VIT|SCB_INT|SCB_DEX|SCB_LUK ); + status->set_sc( CG_MARIONETTE , SC_MARIONETTE_MASTER , SI_MARIONETTE_MASTER , SCB_STR|SCB_AGI|SCB_VIT|SCB_INT|SCB_DEX|SCB_LUK ); + status->set_sc( CG_MARIONETTE , SC_MARIONETTE , SI_MARIONETTE , SCB_STR|SCB_AGI|SCB_VIT|SCB_INT|SCB_DEX|SCB_LUK ); add_sc( LK_SPIRALPIERCE , SC_STOP ); add_sc( LK_HEADCRUSH , SC_BLOODING ); - set_sc( LK_JOINTBEAT , SC_JOINTBEAT , SI_JOINTBEAT , SCB_BATK|SCB_DEF2|SCB_SPEED|SCB_ASPD ); + status->set_sc( LK_JOINTBEAT , SC_JOINTBEAT , SI_JOINTBEAT , SCB_BATK|SCB_DEF2|SCB_SPEED|SCB_ASPD ); add_sc( HW_NAPALMVULCAN , SC_CURSE ); - set_sc( PF_MINDBREAKER , SC_MINDBREAKER , SI_BLANK , SCB_MATK|SCB_MDEF2 ); + status->set_sc( PF_MINDBREAKER , SC_MINDBREAKER , SI_BLANK , SCB_MATK|SCB_MDEF2 ); add_sc( PF_MEMORIZE , SC_MEMORIZE ); add_sc( PF_FOGWALL , SC_FOGWALL ); - set_sc( PF_SPIDERWEB , SC_SPIDERWEB , SI_BLANK , SCB_FLEE ); - set_sc( WE_BABY , SC_BABY , SI_PROTECTEXP , SCB_NONE ); - set_sc( TK_RUN , SC_RUN , SI_RUN , SCB_SPEED|SCB_DSPD ); - set_sc( TK_RUN , SC_STRUP , SI_STRUP , SCB_STR ); - set_sc( TK_READYSTORM , SC_STORMKICK_READY , SI_STORMKICK_ON , SCB_NONE ); - set_sc( TK_READYDOWN , SC_DOWNKICK_READY , SI_DOWNKICK_ON , SCB_NONE ); + status->set_sc( PF_SPIDERWEB , SC_SPIDERWEB , SI_BLANK , SCB_FLEE ); + status->set_sc( WE_BABY , SC_BABY , SI_PROTECTEXP , SCB_NONE ); + status->set_sc( TK_RUN , SC_RUN , SI_RUN , SCB_SPEED|SCB_DSPD ); + status->set_sc( TK_RUN , SC_STRUP , SI_STRUP , SCB_STR ); + status->set_sc( TK_READYSTORM , SC_STORMKICK_READY , SI_STORMKICK_ON , SCB_NONE ); + status->set_sc( TK_READYDOWN , SC_DOWNKICK_READY , SI_DOWNKICK_ON , SCB_NONE ); add_sc( TK_DOWNKICK , SC_STUN ); - set_sc( TK_READYTURN , SC_TURNKICK_READY , SI_TURNKICK_ON , SCB_NONE ); - set_sc( TK_READYCOUNTER , SC_COUNTERKICK_READY , SI_COUNTER_ON , SCB_NONE ); - set_sc( TK_DODGE , SC_DODGE_READY , SI_DODGE_ON , SCB_NONE ); - set_sc( TK_SPTIME , SC_EARTHSCROLL , SI_EARTHSCROLL , SCB_NONE ); + status->set_sc( TK_READYTURN , SC_TURNKICK_READY , SI_TURNKICK_ON , SCB_NONE ); + status->set_sc( TK_READYCOUNTER , SC_COUNTERKICK_READY , SI_COUNTER_ON , SCB_NONE ); + status->set_sc( TK_DODGE , SC_DODGE_READY , SI_DODGE_ON , SCB_NONE ); + status->set_sc( TK_SPTIME , SC_EARTHSCROLL , SI_EARTHSCROLL , SCB_NONE ); add_sc( TK_SEVENWIND , SC_TK_SEVENWIND ); - set_sc( TK_SEVENWIND , SC_PROPERTYTELEKINESIS , SI_PROPERTYTELEKINESIS , SCB_ATK_ELE ); - set_sc( TK_SEVENWIND , SC_PROPERTYDARK , SI_PROPERTYDARK , SCB_ATK_ELE ); - set_sc( SG_SUN_WARM , SC_WARM , SI_SG_SUN_WARM , SCB_NONE ); + status->set_sc( TK_SEVENWIND , SC_PROPERTYTELEKINESIS , SI_PROPERTYTELEKINESIS , SCB_ATK_ELE ); + status->set_sc( TK_SEVENWIND , SC_PROPERTYDARK , SI_PROPERTYDARK , SCB_ATK_ELE ); + status->set_sc( SG_SUN_WARM , SC_WARM , SI_SG_SUN_WARM , SCB_NONE ); add_sc( SG_MOON_WARM , SC_WARM ); add_sc( SG_STAR_WARM , SC_WARM ); - set_sc( SG_SUN_COMFORT , SC_SUN_COMFORT , SI_SUN_COMFORT , SCB_DEF2 ); - set_sc( SG_MOON_COMFORT , SC_MOON_COMFORT , SI_MOON_COMFORT , SCB_FLEE ); - set_sc( SG_STAR_COMFORT , SC_STAR_COMFORT , SI_STAR_COMFORT , SCB_ASPD ); + status->set_sc( SG_SUN_COMFORT , SC_SUN_COMFORT , SI_SUN_COMFORT , SCB_DEF2 ); + status->set_sc( SG_MOON_COMFORT , SC_MOON_COMFORT , SI_MOON_COMFORT , SCB_FLEE ); + status->set_sc( SG_STAR_COMFORT , SC_STAR_COMFORT , SI_STAR_COMFORT , SCB_ASPD ); add_sc( SG_FRIEND , SC_SKILLRATE_UP ); - set_sc( SG_KNOWLEDGE , SC_KNOWLEDGE , SI_BLANK , SCB_ALL ); - set_sc( SG_FUSION , SC_FUSION , SI_BLANK , SCB_SPEED ); - set_sc( BS_ADRENALINE2 , SC_ADRENALINE2 , SI_ADRENALINE2 , SCB_ASPD ); - set_sc( SL_KAIZEL , SC_KAIZEL , SI_KAIZEL , SCB_NONE ); - set_sc( SL_KAAHI , SC_KAAHI , SI_KAAHI , SCB_NONE ); - set_sc( SL_KAUPE , SC_KAUPE , SI_KAUPE , SCB_NONE ); - set_sc( SL_KAITE , SC_KAITE , SI_KAITE , SCB_NONE ); + status->set_sc( SG_KNOWLEDGE , SC_KNOWLEDGE , SI_BLANK , SCB_ALL ); + status->set_sc( SG_FUSION , SC_FUSION , SI_BLANK , SCB_SPEED ); + status->set_sc( BS_ADRENALINE2 , SC_ADRENALINE2 , SI_ADRENALINE2 , SCB_ASPD ); + status->set_sc( SL_KAIZEL , SC_KAIZEL , SI_KAIZEL , SCB_NONE ); + status->set_sc( SL_KAAHI , SC_KAAHI , SI_KAAHI , SCB_NONE ); + status->set_sc( SL_KAUPE , SC_KAUPE , SI_KAUPE , SCB_NONE ); + status->set_sc( SL_KAITE , SC_KAITE , SI_KAITE , SCB_NONE ); add_sc( SL_STUN , SC_STUN ); - set_sc( SL_SWOO , SC_SWOO , SI_BLANK , SCB_SPEED ); - set_sc( SL_SKE , SC_SKE , SI_BLANK , SCB_BATK|SCB_WATK|SCB_DEF|SCB_DEF2 ); - set_sc( SL_SKA , SC_SKA , SI_BLANK , SCB_DEF|SCB_MDEF|SCB_ASPD ); - set_sc( SL_SMA , SC_SMA_READY , SI_SMA_READY , SCB_NONE ); - set_sc( SM_SELFPROVOKE , SC_PROVOKE , SI_PROVOKE , SCB_DEF|SCB_DEF2|SCB_BATK|SCB_WATK ); - set_sc( ST_PRESERVE , SC_PRESERVE , SI_PRESERVE , SCB_NONE ); - set_sc( PF_DOUBLECASTING , SC_DOUBLECASTING , SI_DOUBLECASTING , SCB_NONE ); - set_sc( HW_GRAVITATION , SC_GRAVITATION , SI_BLANK , SCB_ASPD ); + status->set_sc( SL_SWOO , SC_SWOO , SI_BLANK , SCB_SPEED ); + status->set_sc( SL_SKE , SC_SKE , SI_BLANK , SCB_BATK|SCB_WATK|SCB_DEF|SCB_DEF2 ); + status->set_sc( SL_SKA , SC_SKA , SI_BLANK , SCB_DEF|SCB_MDEF|SCB_ASPD ); + status->set_sc( SL_SMA , SC_SMA_READY , SI_SMA_READY , SCB_NONE ); + status->set_sc( SM_SELFPROVOKE , SC_PROVOKE , SI_PROVOKE , SCB_DEF|SCB_DEF2|SCB_BATK|SCB_WATK ); + status->set_sc( ST_PRESERVE , SC_PRESERVE , SI_PRESERVE , SCB_NONE ); + status->set_sc( PF_DOUBLECASTING , SC_DOUBLECASTING , SI_DOUBLECASTING , SCB_NONE ); + status->set_sc( HW_GRAVITATION , SC_GRAVITATION , SI_BLANK , SCB_ASPD ); add_sc( WS_CARTTERMINATION , SC_STUN ); - set_sc( WS_OVERTHRUSTMAX , SC_OVERTHRUSTMAX , SI_OVERTHRUSTMAX , SCB_NONE ); - set_sc( CG_LONGINGFREEDOM , SC_LONGING , SI_BLANK , SCB_SPEED|SCB_ASPD ); + status->set_sc( WS_OVERTHRUSTMAX , SC_OVERTHRUSTMAX , SI_OVERTHRUSTMAX , SCB_NONE ); + status->set_sc( CG_LONGINGFREEDOM , SC_LONGING , SI_BLANK , SCB_SPEED|SCB_ASPD ); add_sc( CG_HERMODE , SC_HERMODE ); - set_sc( CG_TAROTCARD , SC_TAROTCARD , SI_TAROTCARD , SCB_NONE ); - set_sc( ITEM_ENCHANTARMS , SC_ENCHANTARMS , SI_BLANK , SCB_ATK_ELE ); - set_sc( SL_HIGH , SC_SOULLINK , SI_SOULLINK , SCB_ALL ); - set_sc( KN_ONEHAND , SC_ONEHANDQUICKEN , SI_ONEHANDQUICKEN , SCB_ASPD ); - set_sc( GS_FLING , SC_FLING , SI_BLANK , SCB_DEF|SCB_DEF2 ); + status->set_sc( CG_TAROTCARD , SC_TAROTCARD , SI_TAROTCARD , SCB_NONE ); + status->set_sc( ITEM_ENCHANTARMS , SC_ENCHANTARMS , SI_BLANK , SCB_ATK_ELE ); + status->set_sc( SL_HIGH , SC_SOULLINK , SI_SOULLINK , SCB_ALL ); + status->set_sc( KN_ONEHAND , SC_ONEHANDQUICKEN , SI_ONEHANDQUICKEN , SCB_ASPD ); + status->set_sc( GS_FLING , SC_FLING , SI_BLANK , SCB_DEF|SCB_DEF2 ); add_sc( GS_CRACKER , SC_STUN ); add_sc( GS_DISARM , SC_NOEQUIPWEAPON ); add_sc( GS_PIERCINGSHOT , SC_BLOODING ); - set_sc( GS_MADNESSCANCEL , SC_GS_MADNESSCANCEL , SI_GS_MADNESSCANCEL , SCB_ASPD + status->set_sc( GS_MADNESSCANCEL , SC_GS_MADNESSCANCEL , SI_GS_MADNESSCANCEL , SCB_ASPD #ifndef RENEWAL |SCB_BATK ); #else ); #endif - set_sc( GS_ADJUSTMENT , SC_GS_ADJUSTMENT , SI_GS_ADJUSTMENT , SCB_HIT|SCB_FLEE ); - set_sc( GS_INCREASING , SC_GS_ACCURACY , SI_GS_ACCURACY , SCB_AGI|SCB_DEX|SCB_HIT ); - set_sc( GS_GATLINGFEVER , SC_GS_GATLINGFEVER , SI_GS_GATLINGFEVER , SCB_FLEE|SCB_SPEED|SCB_ASPD + status->set_sc( GS_ADJUSTMENT , SC_GS_ADJUSTMENT , SI_GS_ADJUSTMENT , SCB_HIT|SCB_FLEE ); + status->set_sc( GS_INCREASING , SC_GS_ACCURACY , SI_GS_ACCURACY , SCB_AGI|SCB_DEX|SCB_HIT ); + status->set_sc( GS_GATLINGFEVER , SC_GS_GATLINGFEVER , SI_GS_GATLINGFEVER , SCB_FLEE|SCB_SPEED|SCB_ASPD #ifndef RENEWAL |SCB_BATK ); #else ); #endif - set_sc( NJ_TATAMIGAESHI , SC_NJ_TATAMIGAESHI , SI_BLANK , SCB_NONE ); - set_sc( NJ_SUITON , SC_NJ_SUITON , SI_NJ_SUITON , SCB_AGI|SCB_SPEED ); + status->set_sc( NJ_TATAMIGAESHI , SC_NJ_TATAMIGAESHI , SI_BLANK , SCB_NONE ); + status->set_sc( NJ_SUITON , SC_NJ_SUITON , SI_NJ_SUITON , SCB_AGI|SCB_SPEED ); add_sc( NJ_HYOUSYOURAKU , SC_FREEZE ); - set_sc( NJ_NEN , SC_NJ_NEN , SI_NJ_NEN , SCB_STR|SCB_INT ); - set_sc( NJ_UTSUSEMI , SC_NJ_UTSUSEMI , SI_NJ_UTSUSEMI , SCB_NONE ); - set_sc( NJ_BUNSINJYUTSU , SC_NJ_BUNSINJYUTSU , SI_NJ_BUNSINJYUTSU , SCB_DYE ); + status->set_sc( NJ_NEN , SC_NJ_NEN , SI_NJ_NEN , SCB_STR|SCB_INT ); + status->set_sc( NJ_UTSUSEMI , SC_NJ_UTSUSEMI , SI_NJ_UTSUSEMI , SCB_NONE ); + status->set_sc( NJ_BUNSINJYUTSU , SC_NJ_BUNSINJYUTSU , SI_NJ_BUNSINJYUTSU , SCB_DYE ); add_sc( NPC_ICEBREATH , SC_FREEZE ); add_sc( NPC_ACIDBREATH , SC_POISON ); @@ -451,201 +452,201 @@ void initChangeTables(void) { add_sc( NPC_WIDESIGHT , SC_SIGHT ); add_sc( NPC_EVILLAND , SC_BLIND ); add_sc( NPC_MAGICMIRROR , SC_MAGICMIRROR ); - set_sc( NPC_SLOWCAST , SC_SLOWCAST , SI_SLOWCAST , SCB_NONE ); - set_sc( NPC_CRITICALWOUND , SC_CRITICALWOUND , SI_CRITICALWOUND , SCB_NONE ); - set_sc( NPC_STONESKIN , SC_STONESKIN , SI_BLANK , SCB_DEF|SCB_MDEF ); + status->set_sc( NPC_SLOWCAST , SC_SLOWCAST , SI_SLOWCAST , SCB_NONE ); + status->set_sc( NPC_CRITICALWOUND , SC_CRITICALWOUND , SI_CRITICALWOUND , SCB_NONE ); + status->set_sc( NPC_STONESKIN , SC_STONESKIN , SI_BLANK , SCB_DEF|SCB_MDEF ); add_sc( NPC_ANTIMAGIC , SC_STONESKIN ); add_sc( NPC_WIDECURSE , SC_CURSE ); add_sc( NPC_WIDESTUN , SC_STUN ); - set_sc( NPC_HELLPOWER , SC_HELLPOWER , SI_HELLPOWER , SCB_NONE ); - set_sc( NPC_WIDEHELLDIGNITY , SC_HELLPOWER , SI_HELLPOWER , SCB_NONE ); - set_sc( NPC_INVINCIBLE , SC_INVINCIBLE , SI_INVINCIBLE , SCB_SPEED ); - set_sc( NPC_INVINCIBLEOFF , SC_INVINCIBLEOFF , SI_BLANK , SCB_SPEED ); + status->set_sc( NPC_HELLPOWER , SC_HELLPOWER , SI_HELLPOWER , SCB_NONE ); + status->set_sc( NPC_WIDEHELLDIGNITY , SC_HELLPOWER , SI_HELLPOWER , SCB_NONE ); + status->set_sc( NPC_INVINCIBLE , SC_INVINCIBLE , SI_INVINCIBLE , SCB_SPEED ); + status->set_sc( NPC_INVINCIBLEOFF , SC_INVINCIBLEOFF , SI_BLANK , SCB_SPEED ); - set_sc( CASH_BLESSING , SC_BLESSING , SI_BLESSING , SCB_STR|SCB_INT|SCB_DEX ); - set_sc( CASH_INCAGI , SC_INC_AGI , SI_INC_AGI , SCB_AGI|SCB_SPEED ); - set_sc( CASH_ASSUMPTIO , SC_ASSUMPTIO , SI_ASSUMPTIO , SCB_NONE ); + status->set_sc( CASH_BLESSING , SC_BLESSING , SI_BLESSING , SCB_STR|SCB_INT|SCB_DEX ); + status->set_sc( CASH_INCAGI , SC_INC_AGI , SI_INC_AGI , SCB_AGI|SCB_SPEED ); + status->set_sc( CASH_ASSUMPTIO , SC_ASSUMPTIO , SI_ASSUMPTIO , SCB_NONE ); - set_sc( ALL_PARTYFLEE , SC_PARTYFLEE , SI_PARTYFLEE , SCB_NONE ); - set_sc( ALL_ODINS_POWER , SC_ODINS_POWER , SI_ODINS_POWER , SCB_WATK | SCB_MATK | SCB_MDEF | SCB_DEF); + status->set_sc( ALL_PARTYFLEE , SC_PARTYFLEE , SI_PARTYFLEE , SCB_NONE ); + status->set_sc( ALL_ODINS_POWER , SC_ODINS_POWER , SI_ODINS_POWER , SCB_WATK | SCB_MATK | SCB_MDEF | SCB_DEF); - set_sc( CR_SHRINK , SC_CR_SHRINK , SI_CR_SHRINK , SCB_NONE ); - set_sc( RG_CLOSECONFINE , SC_RG_CCONFINE_S , SI_RG_CCONFINE_S , SCB_NONE ); - set_sc( RG_CLOSECONFINE , SC_RG_CCONFINE_M , SI_RG_CCONFINE_M , SCB_FLEE ); - set_sc( WZ_SIGHTBLASTER , SC_WZ_SIGHTBLASTER , SI_WZ_SIGHTBLASTER , SCB_NONE ); - set_sc( DC_WINKCHARM , SC_DC_WINKCHARM , SI_DC_WINKCHARM , SCB_NONE ); + status->set_sc( CR_SHRINK , SC_CR_SHRINK , SI_CR_SHRINK , SCB_NONE ); + status->set_sc( RG_CLOSECONFINE , SC_RG_CCONFINE_S , SI_RG_CCONFINE_S , SCB_NONE ); + status->set_sc( RG_CLOSECONFINE , SC_RG_CCONFINE_M , SI_RG_CCONFINE_M , SCB_FLEE ); + status->set_sc( WZ_SIGHTBLASTER , SC_WZ_SIGHTBLASTER , SI_WZ_SIGHTBLASTER , SCB_NONE ); + status->set_sc( DC_WINKCHARM , SC_DC_WINKCHARM , SI_DC_WINKCHARM , SCB_NONE ); add_sc( MO_BALKYOUNG , SC_STUN ); add_sc( SA_ELEMENTWATER , SC_ARMOR_PROPERTY ); add_sc( SA_ELEMENTFIRE , SC_ARMOR_PROPERTY ); add_sc( SA_ELEMENTGROUND , SC_ARMOR_PROPERTY ); add_sc( SA_ELEMENTWIND , SC_ARMOR_PROPERTY ); - set_sc( HLIF_AVOID , SC_HLIF_AVOID , SI_BLANK , SCB_SPEED ); - set_sc( HLIF_CHANGE , SC_HLIF_CHANGE , SI_BLANK , SCB_VIT|SCB_INT ); - set_sc( HFLI_FLEET , SC_HLIF_FLEET , SI_BLANK , SCB_ASPD|SCB_BATK|SCB_WATK ); - set_sc( HFLI_SPEED , SC_HLIF_SPEED , SI_BLANK , SCB_FLEE ); - set_sc( HAMI_DEFENCE , SC_HAMI_DEFENCE , SI_BLANK , SCB_DEF ); - set_sc( HAMI_BLOODLUST , SC_HAMI_BLOODLUST , SI_BLANK , SCB_BATK|SCB_WATK ); + status->set_sc( HLIF_AVOID , SC_HLIF_AVOID , SI_BLANK , SCB_SPEED ); + status->set_sc( HLIF_CHANGE , SC_HLIF_CHANGE , SI_BLANK , SCB_VIT|SCB_INT ); + status->set_sc( HFLI_FLEET , SC_HLIF_FLEET , SI_BLANK , SCB_ASPD|SCB_BATK|SCB_WATK ); + status->set_sc( HFLI_SPEED , SC_HLIF_SPEED , SI_BLANK , SCB_FLEE ); + status->set_sc( HAMI_DEFENCE , SC_HAMI_DEFENCE , SI_BLANK , SCB_DEF ); + status->set_sc( HAMI_BLOODLUST , SC_HAMI_BLOODLUST , SI_BLANK , SCB_BATK|SCB_WATK ); // Homunculus S - set_sc( MH_LIGHT_OF_REGENE , SC_LIGHT_OF_REGENE , SI_LIGHT_OF_REGENE , SCB_NONE ); - set_sc( MH_OVERED_BOOST , SC_OVERED_BOOST , SI_OVERED_BOOST , SCB_FLEE|SCB_ASPD|SCB_DEF ); + status->set_sc( MH_LIGHT_OF_REGENE , SC_LIGHT_OF_REGENE , SI_LIGHT_OF_REGENE , SCB_NONE ); + status->set_sc( MH_OVERED_BOOST , SC_OVERED_BOOST , SI_OVERED_BOOST , SCB_FLEE|SCB_ASPD|SCB_DEF ); add_sc(MH_STAHL_HORN, SC_STUN); - set_sc(MH_ANGRIFFS_MODUS, SC_ANGRIFFS_MODUS, SI_ANGRIFFS_MODUS, SCB_BATK | SCB_DEF | SCB_FLEE | SCB_MAXHP); - set_sc(MH_GOLDENE_FERSE, SC_GOLDENE_FERSE, SI_GOLDENE_FERSE, SCB_ASPD|SCB_MAXHP); + status->set_sc(MH_ANGRIFFS_MODUS, SC_ANGRIFFS_MODUS, SI_ANGRIFFS_MODUS, SCB_BATK | SCB_DEF | SCB_FLEE | SCB_MAXHP); + status->set_sc(MH_GOLDENE_FERSE, SC_GOLDENE_FERSE, SI_GOLDENE_FERSE, SCB_ASPD|SCB_MAXHP); add_sc( MH_STEINWAND, SC_SAFETYWALL ); - set_sc(MH_VOLCANIC_ASH, SC_VOLCANIC_ASH, SI_VOLCANIC_ASH, SCB_DEF|SCB_DEF2|SCB_HIT|SCB_BATK|SCB_FLEE); - set_sc(MH_GRANITIC_ARMOR, SC_GRANITIC_ARMOR, SI_GRANITIC_ARMOR, SCB_NONE); - set_sc(MH_MAGMA_FLOW, SC_MAGMA_FLOW, SI_MAGMA_FLOW, SCB_NONE); - set_sc(MH_PYROCLASTIC, SC_PYROCLASTIC, SI_PYROCLASTIC, SCB_BATK|SCB_ATK_ELE); + status->set_sc(MH_VOLCANIC_ASH, SC_VOLCANIC_ASH, SI_VOLCANIC_ASH, SCB_DEF|SCB_DEF2|SCB_HIT|SCB_BATK|SCB_FLEE); + status->set_sc(MH_GRANITIC_ARMOR, SC_GRANITIC_ARMOR, SI_GRANITIC_ARMOR, SCB_NONE); + status->set_sc(MH_MAGMA_FLOW, SC_MAGMA_FLOW, SI_MAGMA_FLOW, SCB_NONE); + status->set_sc(MH_PYROCLASTIC, SC_PYROCLASTIC, SI_PYROCLASTIC, SCB_BATK|SCB_ATK_ELE); add_sc(MH_LAVA_SLIDE, SC_BURNING); - set_sc(MH_NEEDLE_OF_PARALYZE, SC_NEEDLE_OF_PARALYZE, SI_NEEDLE_OF_PARALYZE, SCB_DEF2); + status->set_sc(MH_NEEDLE_OF_PARALYZE, SC_NEEDLE_OF_PARALYZE, SI_NEEDLE_OF_PARALYZE, SCB_DEF2); add_sc(MH_POISON_MIST, SC_BLIND); - set_sc(MH_PAIN_KILLER, SC_PAIN_KILLER, SI_PAIN_KILLER, SCB_ASPD); + status->set_sc(MH_PAIN_KILLER, SC_PAIN_KILLER, SI_PAIN_KILLER, SCB_ASPD); - set_sc( MH_SILENT_BREEZE , SC_SILENCE , SI_SILENT_BREEZE , SCB_NONE ); + status->set_sc( MH_SILENT_BREEZE , SC_SILENCE , SI_SILENT_BREEZE , SCB_NONE ); add_sc( MH_STYLE_CHANGE , SC_STYLE_CHANGE); - set_sc( MH_TINDER_BREAKER , SC_RG_CCONFINE_S , SI_RG_CCONFINE_S , SCB_NONE ); - set_sc( MH_TINDER_BREAKER , SC_RG_CCONFINE_M , SI_RG_CCONFINE_M , SCB_FLEE ); + status->set_sc( MH_TINDER_BREAKER , SC_RG_CCONFINE_S , SI_RG_CCONFINE_S , SCB_NONE ); + status->set_sc( MH_TINDER_BREAKER , SC_RG_CCONFINE_M , SI_RG_CCONFINE_M , SCB_FLEE ); add_sc( MER_CRASH , SC_STUN ); - set_sc( MER_PROVOKE , SC_PROVOKE , SI_PROVOKE , SCB_DEF|SCB_DEF2|SCB_BATK|SCB_WATK ); + status->set_sc( MER_PROVOKE , SC_PROVOKE , SI_PROVOKE , SCB_DEF|SCB_DEF2|SCB_BATK|SCB_WATK ); add_sc( MS_MAGNUM , SC_SUB_WEAPONPROPERTY ); add_sc( MER_SIGHT , SC_SIGHT ); - set_sc( MER_DECAGI , SC_DEC_AGI , SI_DEC_AGI , SCB_AGI|SCB_SPEED ); - set_sc( MER_MAGNIFICAT , SC_MAGNIFICAT , SI_MAGNIFICAT , SCB_REGEN ); + status->set_sc( MER_DECAGI , SC_DEC_AGI , SI_DEC_AGI , SCB_AGI|SCB_SPEED ); + status->set_sc( MER_MAGNIFICAT , SC_MAGNIFICAT , SI_MAGNIFICAT , SCB_REGEN ); add_sc( MER_LEXDIVINA , SC_SILENCE ); add_sc( MA_LANDMINE , SC_STUN ); add_sc( MA_SANDMAN , SC_SLEEP ); add_sc( MA_FREEZINGTRAP , SC_FREEZE ); - set_sc( MER_AUTOBERSERK , SC_AUTOBERSERK , SI_AUTOBERSERK , SCB_NONE ); - set_sc( ML_AUTOGUARD , SC_AUTOGUARD , SI_AUTOGUARD , SCB_NONE ); - set_sc( MS_REFLECTSHIELD , SC_REFLECTSHIELD , SI_REFLECTSHIELD , SCB_NONE ); - set_sc( ML_DEFENDER , SC_DEFENDER , SI_DEFENDER , SCB_SPEED|SCB_ASPD ); - set_sc( MS_PARRYING , SC_PARRYING , SI_PARRYING , SCB_NONE ); - set_sc( MS_BERSERK , SC_BERSERK , SI_BERSERK , SCB_DEF|SCB_DEF2|SCB_MDEF|SCB_MDEF2|SCB_FLEE|SCB_SPEED|SCB_ASPD|SCB_MAXHP|SCB_REGEN ); + status->set_sc( MER_AUTOBERSERK , SC_AUTOBERSERK , SI_AUTOBERSERK , SCB_NONE ); + status->set_sc( ML_AUTOGUARD , SC_AUTOGUARD , SI_AUTOGUARD , SCB_NONE ); + status->set_sc( MS_REFLECTSHIELD , SC_REFLECTSHIELD , SI_REFLECTSHIELD , SCB_NONE ); + status->set_sc( ML_DEFENDER , SC_DEFENDER , SI_DEFENDER , SCB_SPEED|SCB_ASPD ); + status->set_sc( MS_PARRYING , SC_PARRYING , SI_PARRYING , SCB_NONE ); + status->set_sc( MS_BERSERK , SC_BERSERK , SI_BERSERK , SCB_DEF|SCB_DEF2|SCB_MDEF|SCB_MDEF2|SCB_FLEE|SCB_SPEED|SCB_ASPD|SCB_MAXHP|SCB_REGEN ); add_sc( ML_SPIRALPIERCE , SC_STOP ); - set_sc( MER_QUICKEN , SC_MER_QUICKEN , SI_BLANK , SCB_ASPD ); + status->set_sc( MER_QUICKEN , SC_MER_QUICKEN , SI_BLANK , SCB_ASPD ); add_sc( ML_DEVOTION , SC_DEVOTION ); - set_sc( MER_KYRIE , SC_KYRIE , SI_KYRIE , SCB_NONE ); - set_sc( MER_BLESSING , SC_BLESSING , SI_BLESSING , SCB_STR|SCB_INT|SCB_DEX ); - set_sc( MER_INCAGI , SC_INC_AGI , SI_INC_AGI , SCB_AGI|SCB_SPEED ); + status->set_sc( MER_KYRIE , SC_KYRIE , SI_KYRIE , SCB_NONE ); + status->set_sc( MER_BLESSING , SC_BLESSING , SI_BLESSING , SCB_STR|SCB_INT|SCB_DEX ); + status->set_sc( MER_INCAGI , SC_INC_AGI , SI_INC_AGI , SCB_AGI|SCB_SPEED ); - set_sc( GD_LEADERSHIP , SC_LEADERSHIP , SI_BLANK , SCB_STR ); - set_sc( GD_GLORYWOUNDS , SC_GLORYWOUNDS , SI_BLANK , SCB_VIT ); - set_sc( GD_SOULCOLD , SC_SOULCOLD , SI_BLANK , SCB_AGI ); - set_sc( GD_HAWKEYES , SC_HAWKEYES , SI_BLANK , SCB_DEX ); + status->set_sc( GD_LEADERSHIP , SC_LEADERSHIP , SI_BLANK , SCB_STR ); + status->set_sc( GD_GLORYWOUNDS , SC_GLORYWOUNDS , SI_BLANK , SCB_VIT ); + status->set_sc( GD_SOULCOLD , SC_SOULCOLD , SI_BLANK , SCB_AGI ); + status->set_sc( GD_HAWKEYES , SC_HAWKEYES , SI_BLANK , SCB_DEX ); - set_sc( GD_BATTLEORDER , SC_GDSKILL_BATTLEORDER , SI_BLANK , SCB_STR|SCB_INT|SCB_DEX ); - set_sc( GD_REGENERATION , SC_GDSKILL_REGENERATION , SI_BLANK , SCB_REGEN ); + status->set_sc( GD_BATTLEORDER , SC_GDSKILL_BATTLEORDER , SI_BLANK , SCB_STR|SCB_INT|SCB_DEX ); + status->set_sc( GD_REGENERATION , SC_GDSKILL_REGENERATION , SI_BLANK , SCB_REGEN ); /** * Rune Knight **/ - set_sc( RK_ENCHANTBLADE , SC_ENCHANTBLADE , SI_ENCHANTBLADE , SCB_NONE ); - set_sc( RK_DRAGONHOWLING , SC_FEAR , SI_BLANK , SCB_FLEE|SCB_HIT ); - set_sc( RK_DEATHBOUND , SC_DEATHBOUND , SI_DEATHBOUND , SCB_NONE ); - set_sc( RK_WINDCUTTER , SC_FEAR , SI_BLANK , SCB_FLEE|SCB_HIT ); + status->set_sc( RK_ENCHANTBLADE , SC_ENCHANTBLADE , SI_ENCHANTBLADE , SCB_NONE ); + status->set_sc( RK_DRAGONHOWLING , SC_FEAR , SI_BLANK , SCB_FLEE|SCB_HIT ); + status->set_sc( RK_DEATHBOUND , SC_DEATHBOUND , SI_DEATHBOUND , SCB_NONE ); + status->set_sc( RK_WINDCUTTER , SC_FEAR , SI_BLANK , SCB_FLEE|SCB_HIT ); add_sc( RK_DRAGONBREATH , SC_BURNING ); - set_sc( RK_MILLENNIUMSHIELD , SC_MILLENNIUMSHIELD , SI_BLANK , SCB_NONE ); - set_sc( RK_REFRESH , SC_REFRESH , SI_REFRESH , SCB_NONE ); - set_sc( RK_GIANTGROWTH , SC_GIANTGROWTH , SI_GIANTGROWTH , SCB_STR ); - set_sc( RK_STONEHARDSKIN , SC_STONEHARDSKIN , SI_STONEHARDSKIN , SCB_NONE ); - set_sc( RK_VITALITYACTIVATION, SC_VITALITYACTIVATION, SI_VITALITYACTIVATION, SCB_REGEN ); - set_sc( RK_FIGHTINGSPIRIT , SC_FIGHTINGSPIRIT , SI_FIGHTINGSPIRIT , SCB_WATK|SCB_ASPD ); - set_sc( RK_ABUNDANCE , SC_ABUNDANCE , SI_ABUNDANCE , SCB_NONE ); - set_sc( RK_CRUSHSTRIKE , SC_CRUSHSTRIKE , SI_CRUSHSTRIKE , SCB_NONE ); + status->set_sc( RK_MILLENNIUMSHIELD , SC_MILLENNIUMSHIELD , SI_BLANK , SCB_NONE ); + status->set_sc( RK_REFRESH , SC_REFRESH , SI_REFRESH , SCB_NONE ); + status->set_sc( RK_GIANTGROWTH , SC_GIANTGROWTH , SI_GIANTGROWTH , SCB_STR ); + status->set_sc( RK_STONEHARDSKIN , SC_STONEHARDSKIN , SI_STONEHARDSKIN , SCB_NONE ); + status->set_sc( RK_VITALITYACTIVATION, SC_VITALITYACTIVATION, SI_VITALITYACTIVATION, SCB_REGEN ); + status->set_sc( RK_FIGHTINGSPIRIT , SC_FIGHTINGSPIRIT , SI_FIGHTINGSPIRIT , SCB_WATK|SCB_ASPD ); + status->set_sc( RK_ABUNDANCE , SC_ABUNDANCE , SI_ABUNDANCE , SCB_NONE ); + status->set_sc( RK_CRUSHSTRIKE , SC_CRUSHSTRIKE , SI_CRUSHSTRIKE , SCB_NONE ); add_sc( RK_DRAGONBREATH_WATER, SC_FROSTMISTY ); /** * GC Guillotine Cross **/ set_sc_with_vfx( GC_VENOMIMPRESS , SC_VENOMIMPRESS , SI_VENOMIMPRESS , SCB_NONE ); - set_sc( GC_POISONINGWEAPON , SC_POISONINGWEAPON , SI_POISONINGWEAPON , SCB_NONE ); - set_sc( GC_WEAPONBLOCKING , SC_WEAPONBLOCKING , SI_WEAPONBLOCKING , SCB_NONE ); - set_sc( GC_CLOAKINGEXCEED , SC_CLOAKINGEXCEED , SI_CLOAKINGEXCEED , SCB_SPEED ); - set_sc( GC_HALLUCINATIONWALK , SC_HALLUCINATIONWALK, SI_HALLUCINATIONWALK, SCB_FLEE ); - set_sc( GC_ROLLINGCUTTER , SC_ROLLINGCUTTER , SI_ROLLINGCUTTER , SCB_NONE ); + status->set_sc( GC_POISONINGWEAPON , SC_POISONINGWEAPON , SI_POISONINGWEAPON , SCB_NONE ); + status->set_sc( GC_WEAPONBLOCKING , SC_WEAPONBLOCKING , SI_WEAPONBLOCKING , SCB_NONE ); + status->set_sc( GC_CLOAKINGEXCEED , SC_CLOAKINGEXCEED , SI_CLOAKINGEXCEED , SCB_SPEED ); + status->set_sc( GC_HALLUCINATIONWALK , SC_HALLUCINATIONWALK, SI_HALLUCINATIONWALK, SCB_FLEE ); + status->set_sc( GC_ROLLINGCUTTER , SC_ROLLINGCUTTER , SI_ROLLINGCUTTER , SCB_NONE ); set_sc_with_vfx( GC_DARKCROW , SC_DARKCROW , SI_DARKCROW , SCB_NONE ); /** * Arch Bishop **/ - set_sc( AB_ADORAMUS , SC_ADORAMUS , SI_ADORAMUS , SCB_AGI|SCB_SPEED ); + status->set_sc( AB_ADORAMUS , SC_ADORAMUS , SI_ADORAMUS , SCB_AGI|SCB_SPEED ); add_sc( AB_CLEMENTIA , SC_BLESSING ); add_sc( AB_CANTO , SC_INC_AGI ); - set_sc( AB_EPICLESIS , SC_EPICLESIS , SI_EPICLESIS , SCB_MAXHP ); + status->set_sc( AB_EPICLESIS , SC_EPICLESIS , SI_EPICLESIS , SCB_MAXHP ); add_sc( AB_PRAEFATIO , SC_KYRIE ); set_sc_with_vfx( AB_ORATIO , SC_ORATIO , SI_ORATIO , SCB_NONE ); - set_sc( AB_LAUDAAGNUS , SC_LAUDAAGNUS , SI_LAUDAAGNUS , SCB_VIT ); - set_sc( AB_LAUDARAMUS , SC_LAUDARAMUS , SI_LAUDARAMUS , SCB_LUK ); - set_sc( AB_RENOVATIO , SC_RENOVATIO , SI_RENOVATIO , SCB_REGEN ); - set_sc( AB_EXPIATIO , SC_EXPIATIO , SI_EXPIATIO , SCB_ATK_ELE ); - set_sc( AB_DUPLELIGHT , SC_DUPLELIGHT , SI_DUPLELIGHT , SCB_NONE ); - set_sc( AB_SECRAMENT , SC_SECRAMENT , SI_SECRAMENT , SCB_NONE ); - set_sc( AB_OFFERTORIUM , SC_OFFERTORIUM , SI_OFFERTORIUM , SCB_NONE ); + status->set_sc( AB_LAUDAAGNUS , SC_LAUDAAGNUS , SI_LAUDAAGNUS , SCB_VIT ); + status->set_sc( AB_LAUDARAMUS , SC_LAUDARAMUS , SI_LAUDARAMUS , SCB_LUK ); + status->set_sc( AB_RENOVATIO , SC_RENOVATIO , SI_RENOVATIO , SCB_REGEN ); + status->set_sc( AB_EXPIATIO , SC_EXPIATIO , SI_EXPIATIO , SCB_ATK_ELE ); + status->set_sc( AB_DUPLELIGHT , SC_DUPLELIGHT , SI_DUPLELIGHT , SCB_NONE ); + status->set_sc( AB_SECRAMENT , SC_SECRAMENT , SI_SECRAMENT , SCB_NONE ); + status->set_sc( AB_OFFERTORIUM , SC_OFFERTORIUM , SI_OFFERTORIUM , SCB_NONE ); /** * Warlock **/ add_sc( WL_WHITEIMPRISON , SC_WHITEIMPRISON ); set_sc_with_vfx( WL_FROSTMISTY , SC_FROSTMISTY , SI_FROSTMISTY , SCB_ASPD|SCB_SPEED|SCB_DEF ); - set_sc( WL_MARSHOFABYSS , SC_MARSHOFABYSS , SI_MARSHOFABYSS , SCB_SPEED|SCB_FLEE|SCB_AGI|SCB_DEX ); - set_sc(WL_RECOGNIZEDSPELL , SC_RECOGNIZEDSPELL , SI_RECOGNIZEDSPELL , SCB_MATK); - set_sc( WL_STASIS , SC_STASIS , SI_STASIS , SCB_NONE ); - set_sc( WL_TELEKINESIS_INTENSE, SC_TELEKINESIS_INTENSE , SI_TELEKINESIS_INTENSE , SCB_MATK ); + status->set_sc( WL_MARSHOFABYSS , SC_MARSHOFABYSS , SI_MARSHOFABYSS , SCB_SPEED|SCB_FLEE|SCB_AGI|SCB_DEX ); + status->set_sc(WL_RECOGNIZEDSPELL , SC_RECOGNIZEDSPELL , SI_RECOGNIZEDSPELL , SCB_MATK); + status->set_sc( WL_STASIS , SC_STASIS , SI_STASIS , SCB_NONE ); + status->set_sc( WL_TELEKINESIS_INTENSE, SC_TELEKINESIS_INTENSE , SI_TELEKINESIS_INTENSE , SCB_MATK ); /** * Ranger **/ - set_sc( RA_FEARBREEZE , SC_FEARBREEZE , SI_FEARBREEZE , SCB_NONE ); - set_sc( RA_ELECTRICSHOCKER , SC_ELECTRICSHOCKER , SI_ELECTRICSHOCKER , SCB_NONE ); - set_sc( RA_WUGDASH , SC_WUGDASH , SI_WUGDASH , SCB_SPEED ); - set_sc( RA_CAMOUFLAGE , SC_CAMOUFLAGE , SI_CAMOUFLAGE , SCB_SPEED ); + status->set_sc( RA_FEARBREEZE , SC_FEARBREEZE , SI_FEARBREEZE , SCB_NONE ); + status->set_sc( RA_ELECTRICSHOCKER , SC_ELECTRICSHOCKER , SI_ELECTRICSHOCKER , SCB_NONE ); + status->set_sc( RA_WUGDASH , SC_WUGDASH , SI_WUGDASH , SCB_SPEED ); + status->set_sc( RA_CAMOUFLAGE , SC_CAMOUFLAGE , SI_CAMOUFLAGE , SCB_SPEED ); add_sc( RA_MAGENTATRAP , SC_ARMOR_PROPERTY ); add_sc( RA_COBALTTRAP , SC_ARMOR_PROPERTY ); add_sc( RA_MAIZETRAP , SC_ARMOR_PROPERTY ); add_sc( RA_VERDURETRAP , SC_ARMOR_PROPERTY ); add_sc( RA_FIRINGTRAP , SC_BURNING ); add_sc( RA_ICEBOUNDTRAP , SC_FROSTMISTY ); - set_sc( RA_UNLIMIT , SC_UNLIMIT , SI_UNLIMIT , SCB_DEF|SCB_DEF2|SCB_MDEF|SCB_MDEF2 ); + status->set_sc( RA_UNLIMIT , SC_UNLIMIT , SI_UNLIMIT , SCB_DEF|SCB_DEF2|SCB_MDEF|SCB_MDEF2 ); /** * Mechanic **/ - set_sc( NC_ACCELERATION , SC_ACCELERATION , SI_ACCELERATION , SCB_SPEED ); - set_sc( NC_HOVERING , SC_HOVERING , SI_HOVERING , SCB_SPEED ); - set_sc( NC_SHAPESHIFT , SC_SHAPESHIFT , SI_SHAPESHIFT , SCB_DEF_ELE ); - set_sc( NC_INFRAREDSCAN , SC_INFRAREDSCAN , SI_INFRAREDSCAN , SCB_FLEE ); - set_sc( NC_ANALYZE , SC_ANALYZE , SI_ANALYZE , SCB_DEF|SCB_DEF2|SCB_MDEF|SCB_MDEF2 ); - set_sc( NC_MAGNETICFIELD , SC_MAGNETICFIELD , SI_MAGNETICFIELD , SCB_NONE ); - set_sc( NC_NEUTRALBARRIER , SC_NEUTRALBARRIER , SI_NEUTRALBARRIER , SCB_DEF|SCB_MDEF ); - set_sc( NC_STEALTHFIELD , SC_STEALTHFIELD , SI_STEALTHFIELD , SCB_NONE ); + status->set_sc( NC_ACCELERATION , SC_ACCELERATION , SI_ACCELERATION , SCB_SPEED ); + status->set_sc( NC_HOVERING , SC_HOVERING , SI_HOVERING , SCB_SPEED ); + status->set_sc( NC_SHAPESHIFT , SC_SHAPESHIFT , SI_SHAPESHIFT , SCB_DEF_ELE ); + status->set_sc( NC_INFRAREDSCAN , SC_INFRAREDSCAN , SI_INFRAREDSCAN , SCB_FLEE ); + status->set_sc( NC_ANALYZE , SC_ANALYZE , SI_ANALYZE , SCB_DEF|SCB_DEF2|SCB_MDEF|SCB_MDEF2 ); + status->set_sc( NC_MAGNETICFIELD , SC_MAGNETICFIELD , SI_MAGNETICFIELD , SCB_NONE ); + status->set_sc( NC_NEUTRALBARRIER , SC_NEUTRALBARRIER , SI_NEUTRALBARRIER , SCB_DEF|SCB_MDEF ); + status->set_sc( NC_STEALTHFIELD , SC_STEALTHFIELD , SI_STEALTHFIELD , SCB_NONE ); /** * Royal Guard **/ - set_sc( LG_REFLECTDAMAGE , SC_LG_REFLECTDAMAGE , SI_LG_REFLECTDAMAGE, SCB_NONE ); - set_sc( LG_FORCEOFVANGUARD , SC_FORCEOFVANGUARD , SI_FORCEOFVANGUARD , SCB_MAXHP ); - set_sc( LG_EXEEDBREAK , SC_EXEEDBREAK , SI_EXEEDBREAK , SCB_NONE ); - set_sc( LG_PRESTIGE , SC_PRESTIGE , SI_PRESTIGE , SCB_DEF ); - set_sc( LG_BANDING , SC_BANDING , SI_BANDING , SCB_DEF2|SCB_WATK );// Renewal: atk2 & def2 - set_sc( LG_PIETY , SC_BENEDICTIO , SI_BENEDICTIO , SCB_DEF_ELE ); - set_sc( LG_EARTHDRIVE , SC_EARTHDRIVE , SI_EARTHDRIVE , SCB_DEF|SCB_ASPD ); - set_sc( LG_INSPIRATION , SC_INSPIRATION , SI_INSPIRATION , SCB_MAXHP|SCB_WATK|SCB_HIT|SCB_VIT|SCB_AGI|SCB_STR|SCB_DEX|SCB_INT|SCB_LUK); - set_sc( LG_KINGS_GRACE , SC_KINGS_GRACE , SI_KINGS_GRACE , SCB_NONE ); + status->set_sc( LG_REFLECTDAMAGE , SC_LG_REFLECTDAMAGE , SI_LG_REFLECTDAMAGE, SCB_NONE ); + status->set_sc( LG_FORCEOFVANGUARD , SC_FORCEOFVANGUARD , SI_FORCEOFVANGUARD , SCB_MAXHP ); + status->set_sc( LG_EXEEDBREAK , SC_EXEEDBREAK , SI_EXEEDBREAK , SCB_NONE ); + status->set_sc( LG_PRESTIGE , SC_PRESTIGE , SI_PRESTIGE , SCB_DEF ); + status->set_sc( LG_BANDING , SC_BANDING , SI_BANDING , SCB_DEF2|SCB_WATK );// Renewal: atk2 & def2 + status->set_sc( LG_PIETY , SC_BENEDICTIO , SI_BENEDICTIO , SCB_DEF_ELE ); + status->set_sc( LG_EARTHDRIVE , SC_EARTHDRIVE , SI_EARTHDRIVE , SCB_DEF|SCB_ASPD ); + status->set_sc( LG_INSPIRATION , SC_INSPIRATION , SI_INSPIRATION , SCB_MAXHP|SCB_WATK|SCB_HIT|SCB_VIT|SCB_AGI|SCB_STR|SCB_DEX|SCB_INT|SCB_LUK); + status->set_sc( LG_KINGS_GRACE , SC_KINGS_GRACE , SI_KINGS_GRACE , SCB_NONE ); /** * Shadow Chaser **/ - set_sc( SC_REPRODUCE , SC__REPRODUCE , SI_REPRODUCE , SCB_NONE ); - set_sc( SC_AUTOSHADOWSPELL , SC__AUTOSHADOWSPELL, SI_AUTOSHADOWSPELL , SCB_NONE ); - set_sc( SC_SHADOWFORM , SC__SHADOWFORM , SI_SHADOWFORM , SCB_NONE ); - set_sc( SC_BODYPAINT , SC__BODYPAINT , SI_BODYPAINT , SCB_ASPD ); - set_sc( SC_INVISIBILITY , SC__INVISIBILITY , SI_INVISIBILITY , SCB_ASPD|SCB_CRI|SCB_ATK_ELE ); - set_sc( SC_DEADLYINFECT , SC__DEADLYINFECT , SI_DEADLYINFECT , SCB_NONE ); - set_sc( SC_ENERVATION , SC__ENERVATION , SI_ENERVATION , SCB_BATK ); - set_sc( SC_GROOMY , SC__GROOMY , SI_GROOMY , SCB_ASPD|SCB_HIT|SCB_SPEED ); - set_sc( SC_IGNORANCE , SC__IGNORANCE , SI_IGNORANCE , SCB_NONE ); - set_sc( SC_LAZINESS , SC__LAZINESS , SI_LAZINESS , SCB_FLEE ); - set_sc( SC_UNLUCKY , SC__UNLUCKY , SI_UNLUCKY , SCB_CRI|SCB_FLEE2 ); - set_sc( SC_WEAKNESS , SC__WEAKNESS , SI_WEAKNESS , SCB_FLEE2|SCB_MAXHP ); - set_sc( SC_STRIPACCESSARY , SC__STRIPACCESSARY , SI_STRIPACCESSARY , SCB_DEX|SCB_INT|SCB_LUK ); + status->set_sc( SC_REPRODUCE , SC__REPRODUCE , SI_REPRODUCE , SCB_NONE ); + status->set_sc( SC_AUTOSHADOWSPELL , SC__AUTOSHADOWSPELL, SI_AUTOSHADOWSPELL , SCB_NONE ); + status->set_sc( SC_SHADOWFORM , SC__SHADOWFORM , SI_SHADOWFORM , SCB_NONE ); + status->set_sc( SC_BODYPAINT , SC__BODYPAINT , SI_BODYPAINT , SCB_ASPD ); + status->set_sc( SC_INVISIBILITY , SC__INVISIBILITY , SI_INVISIBILITY , SCB_ASPD|SCB_CRI|SCB_ATK_ELE ); + status->set_sc( SC_DEADLYINFECT , SC__DEADLYINFECT , SI_DEADLYINFECT , SCB_NONE ); + status->set_sc( SC_ENERVATION , SC__ENERVATION , SI_ENERVATION , SCB_BATK ); + status->set_sc( SC_GROOMY , SC__GROOMY , SI_GROOMY , SCB_ASPD|SCB_HIT|SCB_SPEED ); + status->set_sc( SC_IGNORANCE , SC__IGNORANCE , SI_IGNORANCE , SCB_NONE ); + status->set_sc( SC_LAZINESS , SC__LAZINESS , SI_LAZINESS , SCB_FLEE ); + status->set_sc( SC_UNLUCKY , SC__UNLUCKY , SI_UNLUCKY , SCB_CRI|SCB_FLEE2 ); + status->set_sc( SC_WEAKNESS , SC__WEAKNESS , SI_WEAKNESS , SCB_FLEE2|SCB_MAXHP ); + status->set_sc( SC_STRIPACCESSARY , SC__STRIPACCESSARY , SI_STRIPACCESSARY , SCB_DEX|SCB_INT|SCB_LUK ); set_sc_with_vfx( SC_MANHOLE , SC__MANHOLE , SI_MANHOLE , SCB_NONE ); add_sc( SC_CHAOSPANIC , SC__CHAOS ); add_sc( SC_MAELSTROM , SC__MAELSTROM ); @@ -656,113 +657,113 @@ void initChangeTables(void) { **/ add_sc( SR_DRAGONCOMBO , SC_STUN ); add_sc( SR_EARTHSHAKER , SC_STUN ); - set_sc( SR_FALLENEMPIRE , SC_FALLENEMPIRE , SI_FALLENEMPIRE , SCB_NONE ); - set_sc( SR_CRESCENTELBOW , SC_CRESCENTELBOW , SI_CRESCENTELBOW , SCB_NONE ); + status->set_sc( SR_FALLENEMPIRE , SC_FALLENEMPIRE , SI_FALLENEMPIRE , SCB_NONE ); + status->set_sc( SR_CRESCENTELBOW , SC_CRESCENTELBOW , SI_CRESCENTELBOW , SCB_NONE ); set_sc_with_vfx( SR_CURSEDCIRCLE , SC_CURSEDCIRCLE_TARGET, SI_CURSEDCIRCLE_TARGET , SCB_NONE ); - set_sc( SR_LIGHTNINGWALK , SC_LIGHTNINGWALK , SI_LIGHTNINGWALK , SCB_NONE ); - set_sc( SR_RAISINGDRAGON , SC_RAISINGDRAGON , SI_RAISINGDRAGON , SCB_REGEN|SCB_MAXHP|SCB_MAXSP ); - set_sc( SR_GENTLETOUCH_ENERGYGAIN, SC_GENTLETOUCH_ENERGYGAIN , SI_GENTLETOUCH_ENERGYGAIN, SCB_NONE ); - set_sc( SR_GENTLETOUCH_CHANGE , SC_GENTLETOUCH_CHANGE , SI_GENTLETOUCH_CHANGE , SCB_ASPD|SCB_MDEF|SCB_MAXHP ); - set_sc( SR_GENTLETOUCH_REVITALIZE, SC_GENTLETOUCH_REVITALIZE , SI_GENTLETOUCH_REVITALIZE, SCB_MAXHP|SCB_DEF2|SCB_REGEN ); - set_sc( SR_FLASHCOMBO , SC_FLASHCOMBO , SI_FLASHCOMBO , SCB_WATK ); + status->set_sc( SR_LIGHTNINGWALK , SC_LIGHTNINGWALK , SI_LIGHTNINGWALK , SCB_NONE ); + status->set_sc( SR_RAISINGDRAGON , SC_RAISINGDRAGON , SI_RAISINGDRAGON , SCB_REGEN|SCB_MAXHP|SCB_MAXSP ); + status->set_sc( SR_GENTLETOUCH_ENERGYGAIN, SC_GENTLETOUCH_ENERGYGAIN , SI_GENTLETOUCH_ENERGYGAIN, SCB_NONE ); + status->set_sc( SR_GENTLETOUCH_CHANGE , SC_GENTLETOUCH_CHANGE , SI_GENTLETOUCH_CHANGE , SCB_ASPD|SCB_MDEF|SCB_MAXHP ); + status->set_sc( SR_GENTLETOUCH_REVITALIZE, SC_GENTLETOUCH_REVITALIZE , SI_GENTLETOUCH_REVITALIZE, SCB_MAXHP|SCB_DEF2|SCB_REGEN ); + status->set_sc( SR_FLASHCOMBO , SC_FLASHCOMBO , SI_FLASHCOMBO , SCB_WATK ); /** * Wanderer / Minstrel **/ - set_sc( WA_SWING_DANCE , SC_SWING , SI_SWINGDANCE , SCB_SPEED|SCB_ASPD ); - set_sc( WA_SYMPHONY_OF_LOVER , SC_SYMPHONY_LOVE , SI_SYMPHONYOFLOVERS , SCB_MDEF ); - set_sc( WA_MOONLIT_SERENADE , SC_MOONLIT_SERENADE , SI_MOONLITSERENADE , SCB_MATK ); - set_sc( MI_RUSH_WINDMILL , SC_RUSH_WINDMILL , SI_RUSHWINDMILL , SCB_WATK ); - set_sc( MI_ECHOSONG , SC_ECHOSONG , SI_ECHOSONG , SCB_DEF2 ); - set_sc( MI_HARMONIZE , SC_HARMONIZE , SI_HARMONIZE , SCB_STR|SCB_AGI|SCB_VIT|SCB_INT|SCB_DEX|SCB_LUK ); + status->set_sc( WA_SWING_DANCE , SC_SWING , SI_SWINGDANCE , SCB_SPEED|SCB_ASPD ); + status->set_sc( WA_SYMPHONY_OF_LOVER , SC_SYMPHONY_LOVE , SI_SYMPHONYOFLOVERS , SCB_MDEF ); + status->set_sc( WA_MOONLIT_SERENADE , SC_MOONLIT_SERENADE , SI_MOONLITSERENADE , SCB_MATK ); + status->set_sc( MI_RUSH_WINDMILL , SC_RUSH_WINDMILL , SI_RUSHWINDMILL , SCB_WATK ); + status->set_sc( MI_ECHOSONG , SC_ECHOSONG , SI_ECHOSONG , SCB_DEF2 ); + status->set_sc( MI_HARMONIZE , SC_HARMONIZE , SI_HARMONIZE , SCB_STR|SCB_AGI|SCB_VIT|SCB_INT|SCB_DEX|SCB_LUK ); set_sc_with_vfx(WM_POEMOFNETHERWORLD, SC_NETHERWORLD , SI_NETHERWORLD , SCB_NONE); set_sc_with_vfx( WM_VOICEOFSIREN , SC_SIREN , SI_SIREN , SCB_NONE ); set_sc_with_vfx( WM_LULLABY_DEEPSLEEP , SC_DEEP_SLEEP , SI_DEEPSLEEP , SCB_NONE ); - set_sc( WM_SIRCLEOFNATURE , SC_SIRCLEOFNATURE , SI_SIRCLEOFNATURE , SCB_NONE ); - set_sc( WM_GLOOMYDAY , SC_GLOOMYDAY , SI_GLOOMYDAY , SCB_FLEE|SCB_ASPD ); - set_sc( WM_SONG_OF_MANA , SC_SONG_OF_MANA , SI_SONG_OF_MANA , SCB_NONE ); - set_sc( WM_DANCE_WITH_WUG , SC_DANCE_WITH_WUG , SI_DANCEWITHWUG , SCB_ASPD ); - set_sc( WM_SATURDAY_NIGHT_FEVER , SC_SATURDAY_NIGHT_FEVER , SI_SATURDAYNIGHTFEVER , SCB_BATK|SCB_DEF|SCB_FLEE|SCB_REGEN ); - set_sc( WM_LERADS_DEW , SC_LERADS_DEW , SI_LERADSDEW , SCB_MAXHP ); - set_sc( WM_MELODYOFSINK , SC_MELODYOFSINK , SI_MELODYOFSINK , SCB_INT ); - set_sc( WM_BEYOND_OF_WARCRY , SC_BEYOND_OF_WARCRY , SI_WARCRYOFBEYOND , SCB_STR|SCB_CRI|SCB_MAXHP ); - set_sc( WM_UNLIMITED_HUMMING_VOICE, SC_UNLIMITED_HUMMING_VOICE, SI_UNLIMITEDHUMMINGVOICE, SCB_NONE ); - set_sc( WM_FRIGG_SONG , SC_FRIGG_SONG , SI_FRIGG_SONG , SCB_MAXHP ); + status->set_sc( WM_SIRCLEOFNATURE , SC_SIRCLEOFNATURE , SI_SIRCLEOFNATURE , SCB_NONE ); + status->set_sc( WM_GLOOMYDAY , SC_GLOOMYDAY , SI_GLOOMYDAY , SCB_FLEE|SCB_ASPD ); + status->set_sc( WM_SONG_OF_MANA , SC_SONG_OF_MANA , SI_SONG_OF_MANA , SCB_NONE ); + status->set_sc( WM_DANCE_WITH_WUG , SC_DANCE_WITH_WUG , SI_DANCEWITHWUG , SCB_ASPD ); + status->set_sc( WM_SATURDAY_NIGHT_FEVER , SC_SATURDAY_NIGHT_FEVER , SI_SATURDAYNIGHTFEVER , SCB_BATK|SCB_DEF|SCB_FLEE|SCB_REGEN ); + status->set_sc( WM_LERADS_DEW , SC_LERADS_DEW , SI_LERADSDEW , SCB_MAXHP ); + status->set_sc( WM_MELODYOFSINK , SC_MELODYOFSINK , SI_MELODYOFSINK , SCB_INT ); + status->set_sc( WM_BEYOND_OF_WARCRY , SC_BEYOND_OF_WARCRY , SI_WARCRYOFBEYOND , SCB_STR|SCB_CRI|SCB_MAXHP ); + status->set_sc( WM_UNLIMITED_HUMMING_VOICE, SC_UNLIMITED_HUMMING_VOICE, SI_UNLIMITEDHUMMINGVOICE, SCB_NONE ); + status->set_sc( WM_FRIGG_SONG , SC_FRIGG_SONG , SI_FRIGG_SONG , SCB_MAXHP ); /** * Sorcerer **/ - set_sc( SO_FIREWALK , SC_PROPERTYWALK , SI_PROPERTYWALK , SCB_NONE ); - set_sc( SO_ELECTRICWALK , SC_PROPERTYWALK , SI_PROPERTYWALK , SCB_NONE ); - set_sc( SO_SPELLFIST , SC_SPELLFIST , SI_SPELLFIST , SCB_NONE ); + status->set_sc( SO_FIREWALK , SC_PROPERTYWALK , SI_PROPERTYWALK , SCB_NONE ); + status->set_sc( SO_ELECTRICWALK , SC_PROPERTYWALK , SI_PROPERTYWALK , SCB_NONE ); + status->set_sc( SO_SPELLFIST , SC_SPELLFIST , SI_SPELLFIST , SCB_NONE ); set_sc_with_vfx( SO_DIAMONDDUST , SC_COLD , SI_COLD , SCB_NONE ); // it does show the snow icon on mobs but doesn't affect it. - set_sc( SO_CLOUD_KILL , SC_POISON , SI_CLOUDKILL , SCB_NONE ); - set_sc( SO_STRIKING , SC_STRIKING , SI_STRIKING , SCB_WATK|SCB_CRI ); + status->set_sc( SO_CLOUD_KILL , SC_POISON , SI_CLOUDKILL , SCB_NONE ); + status->set_sc( SO_STRIKING , SC_STRIKING , SI_STRIKING , SCB_WATK|SCB_CRI ); add_sc( SO_WARMER , SC_WARMER ); // At the moment, no icon on officials - set_sc( SO_VACUUM_EXTREME , SC_VACUUM_EXTREME , SI_VACUUM_EXTREME , SCB_NONE ); - set_sc( SO_ARRULLO , SC_DEEP_SLEEP , SI_DEEPSLEEP , SCB_NONE ); - set_sc( SO_FIRE_INSIGNIA , SC_FIRE_INSIGNIA , SI_FIRE_INSIGNIA , SCB_MATK | SCB_BATK | SCB_WATK | SCB_ATK_ELE | SCB_REGEN ); - set_sc( SO_WATER_INSIGNIA , SC_WATER_INSIGNIA , SI_WATER_INSIGNIA , SCB_WATK | SCB_ATK_ELE | SCB_REGEN ); - set_sc( SO_WIND_INSIGNIA , SC_WIND_INSIGNIA , SI_WIND_INSIGNIA , SCB_WATK | SCB_ATK_ELE | SCB_REGEN ); - set_sc( SO_EARTH_INSIGNIA , SC_EARTH_INSIGNIA , SI_EARTH_INSIGNIA , SCB_MDEF|SCB_DEF|SCB_MAXHP|SCB_MAXSP|SCB_WATK | SCB_ATK_ELE | SCB_REGEN ); + status->set_sc( SO_VACUUM_EXTREME , SC_VACUUM_EXTREME , SI_VACUUM_EXTREME , SCB_NONE ); + status->set_sc( SO_ARRULLO , SC_DEEP_SLEEP , SI_DEEPSLEEP , SCB_NONE ); + status->set_sc( SO_FIRE_INSIGNIA , SC_FIRE_INSIGNIA , SI_FIRE_INSIGNIA , SCB_MATK | SCB_BATK | SCB_WATK | SCB_ATK_ELE | SCB_REGEN ); + status->set_sc( SO_WATER_INSIGNIA , SC_WATER_INSIGNIA , SI_WATER_INSIGNIA , SCB_WATK | SCB_ATK_ELE | SCB_REGEN ); + status->set_sc( SO_WIND_INSIGNIA , SC_WIND_INSIGNIA , SI_WIND_INSIGNIA , SCB_WATK | SCB_ATK_ELE | SCB_REGEN ); + status->set_sc( SO_EARTH_INSIGNIA , SC_EARTH_INSIGNIA , SI_EARTH_INSIGNIA , SCB_MDEF|SCB_DEF|SCB_MAXHP|SCB_MAXSP|SCB_WATK | SCB_ATK_ELE | SCB_REGEN ); add_sc( SO_ELEMENTAL_SHIELD , SC_SAFETYWALL ); /** * Genetic **/ - set_sc( GN_CARTBOOST , SC_GN_CARTBOOST, SI_CARTSBOOST , SCB_SPEED ); - set_sc( GN_THORNS_TRAP , SC_THORNS_TRAP , SI_THORNTRAP , SCB_NONE ); + status->set_sc( GN_CARTBOOST , SC_GN_CARTBOOST, SI_CARTSBOOST , SCB_SPEED ); + status->set_sc( GN_THORNS_TRAP , SC_THORNS_TRAP , SI_THORNTRAP , SCB_NONE ); set_sc_with_vfx( GN_BLOOD_SUCKER , SC_BLOOD_SUCKER , SI_BLOODSUCKER , SCB_NONE ); - set_sc( GN_WALLOFTHORN , SC_STOP , SI_BLANK , SCB_NONE ); - set_sc( GN_FIRE_EXPANSION_SMOKE_POWDER, SC_FIRE_EXPANSION_SMOKE_POWDER , SI_FIRE_EXPANSION_SMOKE_POWDER, SCB_NONE ); - set_sc( GN_FIRE_EXPANSION_TEAR_GAS , SC_FIRE_EXPANSION_TEAR_GAS , SI_FIRE_EXPANSION_TEAR_GAS , SCB_NONE ); - set_sc( GN_MANDRAGORA , SC_MANDRAGORA , SI_MANDRAGORA , SCB_INT ); + status->set_sc( GN_WALLOFTHORN , SC_STOP , SI_BLANK , SCB_NONE ); + status->set_sc( GN_FIRE_EXPANSION_SMOKE_POWDER, SC_FIRE_EXPANSION_SMOKE_POWDER , SI_FIRE_EXPANSION_SMOKE_POWDER, SCB_NONE ); + status->set_sc( GN_FIRE_EXPANSION_TEAR_GAS , SC_FIRE_EXPANSION_TEAR_GAS , SI_FIRE_EXPANSION_TEAR_GAS , SCB_NONE ); + status->set_sc( GN_MANDRAGORA , SC_MANDRAGORA , SI_MANDRAGORA , SCB_INT ); // Elemental Spirit summoner's 'side' status changes. - set_sc( EL_CIRCLE_OF_FIRE , SC_CIRCLE_OF_FIRE_OPTION, SI_CIRCLE_OF_FIRE_OPTION, SCB_NONE ); - set_sc( EL_FIRE_CLOAK , SC_FIRE_CLOAK_OPTION , SI_FIRE_CLOAK_OPTION , SCB_ALL ); - set_sc( EL_WATER_SCREEN , SC_WATER_SCREEN_OPTION , SI_WATER_SCREEN_OPTION , SCB_NONE ); - set_sc( EL_WATER_DROP , SC_WATER_DROP_OPTION , SI_WATER_DROP_OPTION , SCB_ALL ); - set_sc( EL_WATER_BARRIER , SC_WATER_BARRIER , SI_WATER_BARRIER , SCB_WATK|SCB_FLEE ); - set_sc( EL_WIND_STEP , SC_WIND_STEP_OPTION , SI_WIND_STEP_OPTION , SCB_SPEED|SCB_FLEE ); - set_sc( EL_WIND_CURTAIN , SC_WIND_CURTAIN_OPTION , SI_WIND_CURTAIN_OPTION , SCB_ALL ); - set_sc( EL_ZEPHYR , SC_ZEPHYR , SI_ZEPHYR , SCB_FLEE ); - set_sc( EL_SOLID_SKIN , SC_SOLID_SKIN_OPTION , SI_SOLID_SKIN_OPTION , SCB_DEF|SCB_MAXHP ); - set_sc( EL_STONE_SHIELD , SC_STONE_SHIELD_OPTION , SI_STONE_SHIELD_OPTION , SCB_ALL ); - set_sc( EL_POWER_OF_GAIA , SC_POWER_OF_GAIA , SI_POWER_OF_GAIA , SCB_MAXHP|SCB_DEF|SCB_SPEED ); - set_sc( EL_PYROTECHNIC , SC_PYROTECHNIC_OPTION , SI_PYROTECHNIC_OPTION , SCB_WATK ); - set_sc( EL_HEATER , SC_HEATER_OPTION , SI_HEATER_OPTION , SCB_WATK ); - set_sc( EL_TROPIC , SC_TROPIC_OPTION , SI_TROPIC_OPTION , SCB_WATK ); - set_sc( EL_AQUAPLAY , SC_AQUAPLAY_OPTION , SI_AQUAPLAY_OPTION , SCB_MATK ); - set_sc( EL_COOLER , SC_COOLER_OPTION , SI_COOLER_OPTION , SCB_MATK ); - set_sc( EL_CHILLY_AIR , SC_CHILLY_AIR_OPTION , SI_CHILLY_AIR_OPTION , SCB_MATK ); - set_sc( EL_GUST , SC_GUST_OPTION , SI_GUST_OPTION , SCB_ASPD ); - set_sc( EL_BLAST , SC_BLAST_OPTION , SI_BLAST_OPTION , SCB_ASPD ); - set_sc( EL_WILD_STORM , SC_WILD_STORM_OPTION , SI_WILD_STORM_OPTION , SCB_ASPD ); - set_sc( EL_PETROLOGY , SC_PETROLOGY_OPTION , SI_PETROLOGY_OPTION , SCB_MAXHP ); - set_sc( EL_CURSED_SOIL , SC_CURSED_SOIL_OPTION , SI_CURSED_SOIL_OPTION , SCB_MAXHP ); - set_sc( EL_UPHEAVAL , SC_UPHEAVAL_OPTION , SI_UPHEAVAL_OPTION , SCB_MAXHP ); - set_sc( EL_TIDAL_WEAPON , SC_TIDAL_WEAPON_OPTION , SI_TIDAL_WEAPON_OPTION , SCB_ALL ); - set_sc( EL_ROCK_CRUSHER , SC_ROCK_CRUSHER , SI_ROCK_CRUSHER , SCB_DEF ); - set_sc( EL_ROCK_CRUSHER_ATK, SC_ROCK_CRUSHER_ATK , SI_ROCK_CRUSHER_ATK , SCB_SPEED ); + status->set_sc( EL_CIRCLE_OF_FIRE , SC_CIRCLE_OF_FIRE_OPTION, SI_CIRCLE_OF_FIRE_OPTION, SCB_NONE ); + status->set_sc( EL_FIRE_CLOAK , SC_FIRE_CLOAK_OPTION , SI_FIRE_CLOAK_OPTION , SCB_ALL ); + status->set_sc( EL_WATER_SCREEN , SC_WATER_SCREEN_OPTION , SI_WATER_SCREEN_OPTION , SCB_NONE ); + status->set_sc( EL_WATER_DROP , SC_WATER_DROP_OPTION , SI_WATER_DROP_OPTION , SCB_ALL ); + status->set_sc( EL_WATER_BARRIER , SC_WATER_BARRIER , SI_WATER_BARRIER , SCB_WATK|SCB_FLEE ); + status->set_sc( EL_WIND_STEP , SC_WIND_STEP_OPTION , SI_WIND_STEP_OPTION , SCB_SPEED|SCB_FLEE ); + status->set_sc( EL_WIND_CURTAIN , SC_WIND_CURTAIN_OPTION , SI_WIND_CURTAIN_OPTION , SCB_ALL ); + status->set_sc( EL_ZEPHYR , SC_ZEPHYR , SI_ZEPHYR , SCB_FLEE ); + status->set_sc( EL_SOLID_SKIN , SC_SOLID_SKIN_OPTION , SI_SOLID_SKIN_OPTION , SCB_DEF|SCB_MAXHP ); + status->set_sc( EL_STONE_SHIELD , SC_STONE_SHIELD_OPTION , SI_STONE_SHIELD_OPTION , SCB_ALL ); + status->set_sc( EL_POWER_OF_GAIA , SC_POWER_OF_GAIA , SI_POWER_OF_GAIA , SCB_MAXHP|SCB_DEF|SCB_SPEED ); + status->set_sc( EL_PYROTECHNIC , SC_PYROTECHNIC_OPTION , SI_PYROTECHNIC_OPTION , SCB_WATK ); + status->set_sc( EL_HEATER , SC_HEATER_OPTION , SI_HEATER_OPTION , SCB_WATK ); + status->set_sc( EL_TROPIC , SC_TROPIC_OPTION , SI_TROPIC_OPTION , SCB_WATK ); + status->set_sc( EL_AQUAPLAY , SC_AQUAPLAY_OPTION , SI_AQUAPLAY_OPTION , SCB_MATK ); + status->set_sc( EL_COOLER , SC_COOLER_OPTION , SI_COOLER_OPTION , SCB_MATK ); + status->set_sc( EL_CHILLY_AIR , SC_CHILLY_AIR_OPTION , SI_CHILLY_AIR_OPTION , SCB_MATK ); + status->set_sc( EL_GUST , SC_GUST_OPTION , SI_GUST_OPTION , SCB_ASPD ); + status->set_sc( EL_BLAST , SC_BLAST_OPTION , SI_BLAST_OPTION , SCB_ASPD ); + status->set_sc( EL_WILD_STORM , SC_WILD_STORM_OPTION , SI_WILD_STORM_OPTION , SCB_ASPD ); + status->set_sc( EL_PETROLOGY , SC_PETROLOGY_OPTION , SI_PETROLOGY_OPTION , SCB_MAXHP ); + status->set_sc( EL_CURSED_SOIL , SC_CURSED_SOIL_OPTION , SI_CURSED_SOIL_OPTION , SCB_MAXHP ); + status->set_sc( EL_UPHEAVAL , SC_UPHEAVAL_OPTION , SI_UPHEAVAL_OPTION , SCB_MAXHP ); + status->set_sc( EL_TIDAL_WEAPON , SC_TIDAL_WEAPON_OPTION , SI_TIDAL_WEAPON_OPTION , SCB_ALL ); + status->set_sc( EL_ROCK_CRUSHER , SC_ROCK_CRUSHER , SI_ROCK_CRUSHER , SCB_DEF ); + status->set_sc( EL_ROCK_CRUSHER_ATK, SC_ROCK_CRUSHER_ATK , SI_ROCK_CRUSHER_ATK , SCB_SPEED ); add_sc( KO_YAMIKUMO , SC_HIDING ); set_sc_with_vfx( KO_JYUMONJIKIRI , SC_KO_JYUMONJIKIRI , SI_KO_JYUMONJIKIRI , SCB_NONE ); add_sc( KO_MAKIBISHI , SC_STUN ); - set_sc( KO_MEIKYOUSISUI , SC_MEIKYOUSISUI , SI_MEIKYOUSISUI , SCB_NONE ); - set_sc( KO_KYOUGAKU , SC_KYOUGAKU , SI_KYOUGAKU , SCB_STR|SCB_AGI|SCB_VIT|SCB_INT|SCB_DEX|SCB_LUK ); + status->set_sc( KO_MEIKYOUSISUI , SC_MEIKYOUSISUI , SI_MEIKYOUSISUI , SCB_NONE ); + status->set_sc( KO_KYOUGAKU , SC_KYOUGAKU , SI_KYOUGAKU , SCB_STR|SCB_AGI|SCB_VIT|SCB_INT|SCB_DEX|SCB_LUK ); add_sc( KO_JYUSATSU , SC_CURSE ); - set_sc( KO_ZENKAI , SC_ZENKAI , SI_ZENKAI , SCB_NONE ); - set_sc( KO_IZAYOI , SC_IZAYOI , SI_IZAYOI , SCB_MATK ); - set_sc( KG_KYOMU , SC_KYOMU , SI_KYOMU , SCB_NONE ); - set_sc( KG_KAGEMUSYA , SC_KAGEMUSYA , SI_KAGEMUSYA , SCB_NONE ); - set_sc( KG_KAGEHUMI , SC_KG_KAGEHUMI , SI_KG_KAGEHUMI , SCB_NONE ); - set_sc( OB_ZANGETSU , SC_ZANGETSU , SI_ZANGETSU , SCB_MATK|SCB_BATK ); + status->set_sc( KO_ZENKAI , SC_ZENKAI , SI_ZENKAI , SCB_NONE ); + status->set_sc( KO_IZAYOI , SC_IZAYOI , SI_IZAYOI , SCB_MATK ); + status->set_sc( KG_KYOMU , SC_KYOMU , SI_KYOMU , SCB_NONE ); + status->set_sc( KG_KAGEMUSYA , SC_KAGEMUSYA , SI_KAGEMUSYA , SCB_NONE ); + status->set_sc( KG_KAGEHUMI , SC_KG_KAGEHUMI , SI_KG_KAGEHUMI , SCB_NONE ); + status->set_sc( OB_ZANGETSU , SC_ZANGETSU , SI_ZANGETSU , SCB_MATK|SCB_BATK ); set_sc_with_vfx( OB_AKAITSUKI, SC_AKAITSUKI , SI_AKAITSUKI , SCB_NONE ); - set_sc( OB_OBOROGENSOU , SC_GENSOU , SI_GENSOU , SCB_NONE ); + status->set_sc( OB_OBOROGENSOU , SC_GENSOU , SI_GENSOU , SCB_NONE ); - set_sc( ALL_FULL_THROTTLE , SC_FULL_THROTTLE , SI_FULL_THROTTLE , SCB_SPEED|SCB_STR|SCB_AGI|SCB_VIT|SCB_INT|SCB_DEX|SCB_LUK ); + status->set_sc( ALL_FULL_THROTTLE , SC_FULL_THROTTLE , SI_FULL_THROTTLE , SCB_SPEED|SCB_STR|SCB_AGI|SCB_VIT|SCB_INT|SCB_DEX|SCB_LUK ); add_sc( ALL_REVERSEORCISH , SC_ORCISH ); - set_sc( ALL_ANGEL_PROTECT , SC_ANGEL_PROTECT , SI_ANGEL_PROTECT , SCB_REGEN ); + status->set_sc( ALL_ANGEL_PROTECT , SC_ANGEL_PROTECT , SI_ANGEL_PROTECT , SCB_REGEN ); add_sc( NPC_WIDEHEALTHFEAR , SC_FEAR ); add_sc( NPC_WIDEBODYBURNNING , SC_BURNING ); @@ -1237,7 +1238,7 @@ void initDummyData(void) } //For copying a status_data structure from b to a, without overwriting current Hp and Sp -static inline void status_cpy(struct status_data* a, const struct status_data* b) +void status_copy(struct status_data *a, const struct status_data *b) { memcpy((void*)&a->max_hp, (const void*)&b->max_hp, sizeof(struct status_data)-(sizeof(a->hp)+sizeof(a->sp))); } @@ -3160,7 +3161,7 @@ int status_calc_pc_(struct map_session_data* sd, enum e_status_calc_opt opt) { sd->left_weapon.addrace[RC_DEMON] += sc->data[SC_PHI_DEMON]->val1; } } - status_cpy(&sd->battle_status, bstatus); + status->copy(&sd->battle_status, bstatus); // ----- CLIENT-SIDE REFRESH ----- if(!sd->bl.prev) { @@ -3199,7 +3200,7 @@ int status_calc_mercenary_(struct mercenary_data *md, enum e_status_calc_opt opt } status->calc_misc(&md->bl, mstatus, md->db->lv); - status_cpy(&md->battle_status, mstatus); + status->copy(&md->battle_status, mstatus); return 0; } @@ -3237,7 +3238,7 @@ int status_calc_elemental_(struct elemental_data *ed, enum e_status_calc_opt opt memcpy(&ed->battle_status, estatus, sizeof(struct status_data)); } else { status->calc_misc(&ed->bl, estatus, 0); - status_cpy(&ed->battle_status, estatus); + status->copy(&ed->battle_status, estatus); } return 0; @@ -3274,7 +3275,7 @@ int status_calc_npc_(struct npc_data *nd, enum e_status_calc_opt opt) { nstatus->luk = nd->stat_point; status->calc_misc(&nd->bl, nstatus, nd->level); - status_cpy(&nd->status, nstatus); + status->copy(&nd->status, nstatus); return 0; } @@ -3360,7 +3361,7 @@ int status_calc_homunculus_(struct homun_data *hd, enum e_status_calc_opt opt) { status->calc_misc(&hd->bl, hstatus, hom->level); - status_cpy(&hd->battle_status, hstatus); + status->copy(&hd->battle_status, hstatus); return 1; } @@ -3540,7 +3541,7 @@ void status_calc_regen_rate(struct block_list *bl, struct regen_data *regen, str #endif regen->rate.sp += 1; } - + if (sc->data[SC_GDSKILL_REGENERATION]) { const struct status_change_entry *sce = sc->data[SC_GDSKILL_REGENERATION]; if (!sce->val4) { @@ -3610,7 +3611,7 @@ void status_calc_bl_main(struct block_list *bl, /*enum scb_flag*/int flag) { } if((!(bl->type&BL_REGEN)) && (!sc || !sc->count)) { //No difference. - status_cpy(st, bst); + status->copy(st, bst); return; } @@ -4300,10 +4301,15 @@ unsigned short status_base_atk(const struct block_list *bl, const struct status_ return cap_value(str, 0, USHRT_MAX); } -#ifndef RENEWAL -static inline unsigned short status_base_matk_min(const struct status_data *st) { return st->int_ + (st->int_ / 7)*(st->int_ / 7); } -#endif // not RENEWAL -static inline unsigned short status_base_matk_max(const struct status_data *st) { return st->int_ + (st->int_ / 5)*(st->int_ / 5); } +unsigned short status_base_matk_min(const struct status_data *st) +{ + return st->int_ + (st->int_ / 7) * (st->int_ / 7); +} + +unsigned short status_base_matk_max(const struct status_data *st) +{ + return st->int_ + (st->int_ / 5)*(st->int_ / 5); +} unsigned short status_base_matk(struct block_list *bl, const struct status_data *st, int level) { #ifdef RENEWAL @@ -4350,8 +4356,8 @@ void status_calc_misc(struct block_list *bl, struct status_data *st, int level) st->mdef2 += (int)(bl->type == BL_PC ? (st->int_ + ((float)level / 4) + ((float)(st->dex + st->vit) / 5)) : ((float)(st->int_ + level) / 4)); //(every 4 base level = +1 mdef) + (every 1 int = +1 mdef) + (every 5 dex = +1 mdef) + (every 5 vit = +1 mdef) } #else // not RENEWAL - st->matk_min = status_base_matk_min(st); - st->matk_max = status_base_matk_max(st); + st->matk_min = status->base_matk_min(st); + st->matk_max = status->base_matk_max(st); st->hit += level + st->dex; st->flee += level + st->agi; st->def2 += st->vit; @@ -4386,7 +4392,7 @@ void status_calc_misc(struct block_list *bl, struct status_data *st, int level) break; case BL_MER: #ifdef RENEWAL - st->matk_min = st->matk_max = status_base_matk_max(st); + st->matk_min = st->matk_max = status->base_matk_max(st); st->def2 = st->vit + level / 10 + st->vit / 5; st->mdef2 = level / 10 + st->int_ / 5; #endif @@ -5576,9 +5582,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 @@ -5648,8 +5654,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() @@ -7495,8 +7501,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) @@ -7506,8 +7513,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; @@ -11610,7 +11619,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; @@ -12107,8 +12116,8 @@ void status_get_matk_sub(struct block_list *bl, int flag, unsigned short *matk_m } #else // not RENEWAL - *matk_min = status_base_matk_min(st) + (sd ? sd->bonus.ematk : 0); - *matk_max = status_base_matk_max(st) + (sd ? sd->bonus.ematk : 0); + *matk_min = status->base_matk_min(st) + (sd ? sd->bonus.ematk : 0); + *matk_max = status->base_matk_max(st) + (sd ? sd->bonus.ematk : 0); #endif if ( sd && sd->matk_rate != 100 ) { @@ -12961,7 +12970,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)) @@ -12971,10 +12980,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++; } } @@ -13224,4 +13236,10 @@ void status_defaults(void) { status->readdb_scconfig = status_readdb_scconfig; status->read_job_db = status_read_job_db; status->read_job_db_sub = status_read_job_db_sub; + status->set_sc = status_set_sc; + status->copy = status_copy; +#ifndef RENEWAL + status->base_matk_min = status_base_matk_min; +#endif // RENEWAL + status->base_matk_max = status_base_matk_max; } diff --git a/src/map/status.h b/src/map/status.h index 2b932b149..dbb507bd1 100644 --- a/src/map/status.h +++ b/src/map/status.h @@ -64,7 +64,9 @@ enum refine_type { REFINE_TYPE_WEAPON2 = 2, REFINE_TYPE_WEAPON3 = 3, REFINE_TYPE_WEAPON4 = 4, +#ifndef REFINE_TYPE_MAX REFINE_TYPE_MAX = 5 +#endif }; /** @@ -825,8 +827,9 @@ typedef enum sc_type { SC_M_LIFEPOTION, SC_G_LIFEPOTION, // 640 SC_MYSTICPOWDER, - +#ifndef SC_MAX SC_MAX, //Automatically updated max, used in for's to check we are within bounds. +#endif } sc_type; /// Official status change ids, used to display status icons in the client. @@ -1792,8 +1795,9 @@ enum si_type { //SI_EP16_2_BUFF_SS = 963, //SI_EP16_2_BUFF_SC = 964, //SI_EP16_2_BUFF_AC = 965, - +#ifndef SI_MAX SI_MAX, +#endif }; // JOINTBEAT stackable ailments @@ -2313,6 +2317,10 @@ struct status_interface { bool (*readdb_scconfig) (char *fields[], int columns, int current); void (*read_job_db) (void); void (*read_job_db_sub) (int idx, const char *name, struct config_setting_t *jdb); + void (*set_sc) (uint16 skill_id, sc_type sc, int icon, unsigned int flag); + void (*copy) (struct status_data *a, const struct status_data *b); + unsigned short (*base_matk_min) (const struct status_data *st); + unsigned short (*base_matk_max) (const struct status_data *st); }; #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 d9001f6f5..3ae1017f8 100644 --- a/src/map/vending.c +++ b/src/map/vending.c @@ -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); } } @@ -276,7 +276,7 @@ void vending_openvending(struct map_session_data* sd, const char* message, const || pc->cartitem_amount(sd, index, amount) < 0 // invalid item or insufficient quantity //NOTE: official server does not do any of the following checks! || !sd->status.cart[index].identify // unidentified item - || sd->status.cart[index].attribute == 1 // broken item + || (sd->status.cart[index].attribute & ATTR_BROKEN) != 0 // broken item || sd->status.cart[index].expire_time // It should not be in the cart but just in case || (sd->status.cart[index].bound && !pc_can_give_bound_items(sd)) // can't trade bound items w/o permission || !itemdb_cantrade(&sd->status.cart[index], pc_get_group_level(sd), pc_get_group_level(sd)) ) // untradeable item |